使用拦截器注入post参数

现在jfinal里面获取post有点麻烦,特别是要整个写入model的时候,都要用get

这边目标是使用注解定义controller里面的方法的参数,然后根据注解和参数的类型自动传值,同时解决getFile及访问后删除文件的问题

例如

public void aaa(@ModelPara User user, @PostPara String username, @PostPara String phone)


1.初始化操作

    //缓存model字段名称及其数据类型,用于@ModelPara
    public static final Map<Class, Map<String, Class>> fieldClassMap = new HashMap();
    //定义model类所在位置
    public static final String modelPackage = "com.xx.common.model";
    public static final String baseModelPackage = "com.xx.common.model.base";

    static {
        //加载model字段名称及其数据类型
        Set<Class<?>> classSet = ClassUtil.scanPackage(baseModelPackage);
        for (Class<?> aClass : classSet) {
            Method[] methods = aClass.getDeclaredMethods();
            LinkedList<Method> getMethodList = new LinkedList<>();
            for (Method method : methods) {
                if (method.getName().matches("get[A-Z]\\w*")) {
                    getMethodList.add(method);
                }
            }
            Map<String, Class> map = new HashMap<>(getMethodList.size());
            for (Method method : getMethodList) {
                String name = method.getName().substring(3);
                name = ((char) (name.charAt(0) + 32)) + name.substring(1);
                map.put(name, method.getReturnType());
            }
            try {
                fieldClassMap.put(Class.forName(aClass.getTypeName().replace(
                        baseModelPackage + ".Base", modelPackage + "."
                )), map);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
//        System.out.println(fieldClassMap);
    }

2.定义拦截函数

@SneakyThrows //忽略抛出异常
@Override
public void intercept(Invocation invocation) {
    try {
        JSONObject json = null;
        if ("POST".equals(invocation.getController().getRequest().getMethod())) {
            //获取文件
            if (invocation.getController().getRequest().getContentType() != null &&
                    invocation.getController().getRequest().getContentType().contains("multipart/form-data")) {
                invocation.getController().getFiles();
            }
            //获取post body中的json
            if (StrUtil.equals(invocation.getController().getRequest().getContentType(), "application/json")) {
                String jsonString = HttpKit.readData(invocation.getController().getRequest());
                if (StrUtil.isNotBlank(jsonString)) {
                    json = JSONObject.parseObject(jsonString);
                    for (Map.Entry<String, Object> entry : json.entrySet()) {
                        invocation.getController().setAttr(entry.getKey(), entry.getValue());
                    }
                }
                invocation.getController().setAttr("postJson", jsonString);
            }
        }
        if (json == null) {
            json = new JSONObject();
        }
        //获取form-data和get参数
        for (Map.Entry<String, String[]> entry : invocation.getController().getParaMap().entrySet()) {
            if (entry.getValue() != null && entry.getValue().length > 0) {
                json.put(entry.getKey(), entry.getValue()[0]);
            }
        }
        //设置注解
        setAnnotation(invocation, json);
        invocation.invoke();
    } catch (CustomException e1) {
        throw e1;
    } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e2) {
        e2.printStackTrace();
        throw new Exception("POST映射错误:" + e2.getMessage());
    }
    //删除上传的文件
    try {
        if (invocation.getController().getRequest().getContentType().contains("multipart/form-data")) {
            for (UploadFile uploadFile : invocation.getController().getFiles()) {
                uploadFile.getFile().delete();
            }
        }
    } catch (Exception e) {

    }
}


3.定义根据注解传参的函数

    private void setAnnotation(Invocation invocation, JSONObject json) throws CustomException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        for (int index = 0; index < invocation.getMethod().getParameters().length; index++) {
            Parameter parameter = invocation.getMethod().getParameters()[index];
            if (parameter.getAnnotation(ModelPara.class) != null) {
                //ModelPara类型的注解
                Object instance = parameter.getType().getDeclaredConstructor().newInstance();
                Method setParaMethod = parameter.getType().getMethod("set", String.class, Object.class);
                for (Map.Entry<String, Object> entry : json.entrySet()) {
                    Object o = entry.getValue();
                    Class c = fieldClassMap.get(parameter.getType()).get(entry.getKey());
                    if (c != null) {
                        //参数类型转化
                        o = BaseDataConvertUtil.convert(o, c);
                        try {
                            setParaMethod.invoke(instance, entry.getKey(), o);
                        } catch (InvocationTargetException e) {
                            if (e.getCause() == null || e.getCause().getMessage() == null || !e.getCause().getMessage().contains("The attribute name does not exist")) {
                                throw e;
                            }
                        }
                    }
                }
                invocation.setArg(index, instance);
            } else if (parameter.getAnnotation(PostPara.class) != null) {
                //PostPara类型的注解
                Object o = json.get(parameter.getName());
                if (o != null) {
                    if (parameter.getType().isAssignableFrom(o.getClass())) {
                        invocation.setArg(index, o);
                    } else {
                        //参数类型转化
                        if (!BaseDataConvertUtil.inConvertType(o)) {
                            o = o.toString();
                        }
                        o = BaseDataConvertUtil.convert(o, parameter.getType());
                        if (o != null) {
                            if (parameter.getType().isAssignableFrom(o.getClass())) {
                                invocation.setArg(index, o);
                            } else {
                                //字段类型错误:%s,应为%s或其子类
                                throw new CustomException(ErrorCodeConstant.B1002, parameter.getName(),
                                        parameter.getType().getSimpleName());
                            }
                        }
                    }
                }
            } else {
//                invocation.setArg(index, null);
            }
        }
    }


4.基本参数自动转化(复杂的参数就直接是jsonobject或jsonarray了)

public class BaseDataConvertUtil {
    public static Set<Class> classSet = new HashSet<>();

    static {
        classSet.add(String.class);
        classSet.add(Double.class);
        classSet.add(Integer.class);
        classSet.add(BigDecimal.class);
        classSet.add(Long.class);
        classSet.add(Boolean.class);
        classSet.add(Date.class);
    }
    //是否是可转化的类型
    public static boolean inConvertType(Object object) {
        return object == null ||
                classSet.contains(object.getClass());

    }
    //自动转化
    public static Object convert(Object object, Class<?> c) {
        if (object == null)
            return null;
        else if (object.getClass().equals(c)) {
            return object;
        } else if (c == String.class) {
            if (object instanceof Date)
                return DateUtil.formatDateTime((Date) object);
            return object.toString();
        } else if (c == Double.class) {
            if (object instanceof Integer)
                return ((Integer) object).doubleValue();
            if (object instanceof Double)
                return object;
            if (object instanceof Long)
                return ((Long) object).doubleValue();
            if (object instanceof BigDecimal)
                return ((BigDecimal) object).doubleValue();
            if (object instanceof Boolean)
                return (Boolean) object ? 1.0D : 0.0D;
            if (object instanceof Date)
                return (double) ((Date) object).getTime();
            try {
                return Double.valueOf(object.toString());
            } catch (Exception e) {
                return null;
            }
        } else if (c == Integer.class) {
            if (object instanceof Integer)
                return object;
            if (object instanceof Double)
                return ((Double) object).intValue();
            if (object instanceof Long)
                return ((Long) object).intValue();
            if (object instanceof BigDecimal)
                return ((BigDecimal) object).intValue();
            if (object instanceof Boolean)
                return (Boolean) object ? 1 : 0;
            if (object instanceof Date)
                return (int) ((Date) object).getTime();
            try {
                return Integer.valueOf(object.toString());
            } catch (Exception e) {
                return null;
            }
        } else if (c == Long.class) {
            if (object instanceof Integer)
                return ((Integer) object).longValue();
            if (object instanceof Double)
                return ((Double) object).longValue();
            if (object instanceof Long)
                return object;
            if (object instanceof BigDecimal)
                return ((BigDecimal) object).longValue();
            if (object instanceof Boolean)
                return (Boolean) object ? 1L : 0L;
            if (object instanceof Date)
                return ((Date) object).getTime();
            try {
                return Long.valueOf(object.toString());
            } catch (Exception e) {
                return null;
            }
        } else if (c == Boolean.class) {
            if (object instanceof Integer)
                return !object.equals(0);
            if (object instanceof Double)
                return !object.equals(0D);
            if (object instanceof Long)
                return !object.equals(0L);
            if (object instanceof BigDecimal)
                return ((BigDecimal) object).intValue() != 1;
            if (object instanceof Boolean)
                return object;
            if (object instanceof Date)
                return object != null;
            try {
                return "true".equals(object.toString()) || "1".equals(object.toString());
            } catch (Exception e) {
                return null;
            }
        } else if (c == Date.class) {
            if (object instanceof Integer)
                return new Date((Integer) object);
            if (object instanceof Double)
                return new Date(((Double) object).longValue());
            if (object instanceof Long)
                return new Date((Long) object);
            if (object instanceof BigDecimal)
                return new Date(((BigDecimal) object).longValue());
            if (object instanceof Boolean)
                return (Boolean) object ? new Date() : null;
            if (object instanceof Date)
                return object;
            try {
                return DateUtil.parse(object.toString());
            } catch (Exception e) {
                return null;
            }
        }
        return object;
    }

    public static Integer convertToInteger(Object object) {
        return (Integer) convert(object, Integer.class);
    }

    public static Double convertToDouble(Object object) {
        return (Double) convert(object, Double.class);
    }

    public static String convertToString(Object object) {
        return (String) convert(object, String.class);
    }

    public static Long convertToLong(Object object) {
        return (Long) convert(object, Long.class);
    }

    public static void main(String[] args) {
        Object object = convert(1.0, Integer.class);
        System.out.println(object);
        System.out.println(object.getClass());
    }
}


拦截器完整类

package com.xx.interceptor;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xx.annotation.ModelPara;
import com.xx.annotation.PostPara;
import com.xx.constant.ErrorCodeConstant;
import com.xx.exception.CustomException;
import com.xx.util.BaseDataConvertUtil;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.kit.HttpKit;
import com.jfinal.upload.UploadFile;
import lombok.SneakyThrows;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

public class PostParaInterceptor implements Interceptor {
    /**
     * 缓存model字段名称及其数据类型,用于@ModelPara
     */
    public static final Map<Class, Map<String, Class>> fieldClassMap = new HashMap();
    /**
     * 定义model类所在位置
     */
    public static final String modelPackage = "com.xx.common.model";
    public static final String baseModelPackage = "com.xx.common.model.base";

    static {
        //加载model字段名称及其数据类型
        Set<Class<?>> classSet = ClassUtil.scanPackage(baseModelPackage);
        for (Class<?> aClass : classSet) {
            Method[] methods = aClass.getDeclaredMethods();
            LinkedList<Method> getMethodList = new LinkedList<>();
            for (Method method : methods) {
                if (method.getName().matches("get[A-Z]\\w*")) {
                    getMethodList.add(method);
                }
            }
            Map<String, Class> map = new HashMap<>(getMethodList.size());
            for (Method method : getMethodList) {
                String name = method.getName().substring(3);
                name = ((char) (name.charAt(0) + 32)) + name.substring(1);
                map.put(name, method.getReturnType());
            }
            try {
                fieldClassMap.put(Class.forName(aClass.getTypeName().replace(
                        baseModelPackage + ".Base", modelPackage + "."
                )), map);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
//        System.out.println(fieldClassMap);
    }

    @SneakyThrows //忽略抛出异常
    @Override
    public void intercept(Invocation invocation) {
        try {
            JSONObject json = null;
            if ("POST".equals(invocation.getController().getRequest().getMethod())) {
                //获取文件
                if (invocation.getController().getRequest().getContentType() != null &&
                        invocation.getController().getRequest().getContentType().contains("multipart/form-data")) {
                    invocation.getController().getFiles();
                }
                //获取post body中的json
                if (StrUtil.equals(invocation.getController().getRequest().getContentType(), "application/json")) {
                    String jsonString = HttpKit.readData(invocation.getController().getRequest());
                    if (StrUtil.isNotBlank(jsonString)) {
                        json = JSONObject.parseObject(jsonString);
                        for (Map.Entry<String, Object> entry : json.entrySet()) {
                            invocation.getController().setAttr(entry.getKey(), entry.getValue());
                        }
                    }
                    invocation.getController().setAttr("postJson", jsonString);
                }
            }
            if (json == null) {
                json = new JSONObject();
            }
            //获取form-data和get参数
            for (Map.Entry<String, String[]> entry : invocation.getController().getParaMap().entrySet()) {
                if (entry.getValue() != null && entry.getValue().length > 0) {
                    json.put(entry.getKey(), entry.getValue()[0]);
                }
            }
            //设置注解
            setAnnotation(invocation, json);
            invocation.invoke();
        } catch (CustomException e1) {
            throw e1;
        } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e2) {
            e2.printStackTrace();
            throw new Exception("POST映射错误:" + e2.getMessage());
        }
        //删除上传的文件
        try {
            if (invocation.getController().getRequest().getContentType().contains("multipart/form-data")) {
                for (UploadFile uploadFile : invocation.getController().getFiles()) {
                    uploadFile.getFile().delete();
                }
            }
        } catch (Exception e) {

        }
    }

    private void setAnnotation(Invocation invocation, JSONObject json) throws CustomException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        for (int index = 0; index < invocation.getMethod().getParameters().length; index++) {
            Parameter parameter = invocation.getMethod().getParameters()[index];
            if (parameter.getAnnotation(ModelPara.class) != null) {
                //ModelPara类型的注解
                Object instance = parameter.getType().getDeclaredConstructor().newInstance();
                Method setParaMethod = parameter.getType().getMethod("set", String.class, Object.class);
                for (Map.Entry<String, Object> entry : json.entrySet()) {
                    Object o = entry.getValue();
                    Class c = fieldClassMap.get(parameter.getType()).get(entry.getKey());
                    if (c != null) {
                        //参数类型转化
                        o = BaseDataConvertUtil.convert(o, c);
                        try {
                            setParaMethod.invoke(instance, entry.getKey(), o);
                        } catch (InvocationTargetException e) {
                            if (e.getCause() == null || e.getCause().getMessage() == null || !e.getCause().getMessage().contains("The attribute name does not exist")) {
                                throw e;
                            }
                        }
                    }
                }
                invocation.setArg(index, instance);
            } else if (parameter.getAnnotation(PostPara.class) != null) {
                //PostPara类型的注解
                Object o = json.get(parameter.getName());
                if (o != null) {
                    if (parameter.getType().isAssignableFrom(o.getClass())) {
                        invocation.setArg(index, o);
                    } else {
                        //参数类型转化
                        if (!BaseDataConvertUtil.inConvertType(o)) {
                            o = o.toString();
                        }
                        o = BaseDataConvertUtil.convert(o, parameter.getType());
                        if (o != null) {
                            if (parameter.getType().isAssignableFrom(o.getClass())) {
                                invocation.setArg(index, o);
                            } else {
                                //字段类型错误:%s,应为%s或其子类
                                throw new CustomException(ErrorCodeConstant.B1002, parameter.getName(),
                                        parameter.getType().getSimpleName());
                            }
                        }
                    }
                }
            } else {
//                invocation.setArg(index, null);
            }
        }
    }
}



ModelPara类

package com.xx.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ModelPara {
}

PostPara类

package com.xx.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PostPara {
}


评论区

山东小木

2020-08-20 21:34

JFinal里有一个paraGetter可以自行扩展 比拦截器方便得多啊

lxhxka

2020-08-21 10:42

@山东小木 paraGetter其实不是很方便,需要给每个类型创建一个paraGetter,太麻烦了。

山东小木

2020-08-21 12:19

@lxhxka 可以使用一个paragetter做成万能参数获取器 动态判断是get 还是post 是json rawdata还是form提交 获取数据转换成map 然后可以封装得到model bean 各种类型数据

lxhxka

2020-08-21 14:13

@山东小木 没太明白你的意思。比如我有两个接口,都用post+json。接收不同的对象,怎么使用同一个 paraGetter 注入形参。

久伴轻尘

2020-08-24 08:59

@lxhxka 可以看看我这个获取方式
https://gitee.com/jbqc/future-template-server/blob/master/future-org/src/main/java/com/jiubanqingchen/future/org/admin/BaseController.java
我认定 extData为get请求的参数 rawData为post提交的参数,可以同时获取get与post,获取的方法写到了baseController作为父类,取值只用调用一下即可

lxhxka

2020-08-24 10:24

@久伴轻尘 这种方式挺好的,但是我更喜欢形参注入的形式。

久伴轻尘

2020-08-24 11:35

@lxhxka 都可以把,各自喜好不同,我倒是更喜欢这种