自定义的参数校验

代码已更新

API层面(拦截器):
    Override
    public void intercept(Invocation inv) {
        Method method = inv.getMethod();
        Validated annotation = method.getAnnotation(Validated.class);
        if (annotation == null) {
            annotation = inv.getTarget().getClass().getAnnotation(Validated.class);
        }

        if (annotation != null) {
            /**得到参数*/
            Parameter[] parameters = method.getParameters();

            if (parameters != null && ArrayUtil.isNotEmpty(parameters)) {
                for (int i = 0; i < parameters.length; i++) {
                    Parameter parameter = parameters[i];
                    if (parameter != null) {
                        /**得到参数注解*/
                        Annotation[] annotations = parameter.getAnnotations();
                        if (annotations != null) {
                            for (Annotation parameterAnnotation : annotations) {
                                if (parameterAnnotation != null) {
                                    if (MapUtil.isNotEmpty(ValidateAbstract.validates)) {
                                        Set<Class<?>> classes = ValidateAbstract.validates.keySet();
                                            /**注解是否符合指定校验类型*/
                                            if (ValidateAbstract.validates.containsKey(parameterAnnotation.annotationType())) {
                                                /**得到校验类*/
                                                ValidateAbstract iValidate = ValidateAbstract.validates.get(parameterAnnotation.annotationType());
                                                /**校验是否符合规则*/
                                                if (iValidate.supports(method, parameter, parameterAnnotation.annotationType())) {
                                                    /**校验*/
                                                    Result verify = iValidate.verify(parameterAnnotation, inv.getArg(i), method, parameter);
                                                    /**code != 0 为失败 */
                                                    if (verify.getCode() != 0) {
                                                        inv.getController().renderJson(verify);
                                                        return;
                                                    }
                                                }
                                            }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        inv.invoke();
    }
 
 
      真正做验证的验证器
      
    public abstract class ValidateAbstract<T extends Annotation> implements IValidate<T>{
    
        protected Boolean isSupports = false;
    
        protected T annotation;
    
        /**二级验证支持子类实现 */
        protected abstract boolean supportsParameter(Parameter parameter,Class<T> t);
    
        /**子类*/
        public static Map<Class<?>, ValidateAbstract> validates = new HashMap<>();
    
        /**一级验证支持*/
        @Override
        public boolean supports(Method method, Parameter parameter,Class<T> t) {
            this.isSupports =  method != null && (method.getAnnotation(Validated.class) != null
                                                                                ?true:method.getDeclaringClass().getAnnotation(Validated.class)!= null);
            if(this.isSupports){
                this.isSupports = supportsParameter(parameter,t);
            }
            return isSupports;
        }
    
        /** 验证 */
        @Override
        public Result verify(T t,Object o, Method method, Parameter parameter) {
            if(isSupports){
                if(method==null || parameter == null){
                    throw new ValidateException("错误的调用:hehh.core.validation.verifier.ValidateAbstract Method verify("+t.getClass()+",java.lang.Object,java.lang.reflect.Method,java.lang.reflect.Parameter) method Parameter not null");
                }
                this.annotation = t;
                return verifyParameter(o,method,parameter);
            }
            throw new ValidateException("错误的调用:hehh.core.validation.verifier.ValidateAbstract 不支持验证.:"+method.getName()+" "+parameter.getName());
        }
    
        /** 真正验证的方法 */
        protected abstract Result verifyParameter(Object o, Method method, Parameter parameter);
    }
    
    
    现已实现常用的验证(包括service层的)有:
          AssertFalse 不为null时必须是false
          AssertTrue 不为null时必须是true
          Digits 被注释的元素必须是一个数字,其值必须在可接受的范围内 
 * 且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
         Future 被注释的元素必须是一个将来的日期 type1 :毫秒、2:秒、3:分、4:时 、5:天
               6:周、7:月、8:年
         Past 必须是将来的日期       
         Max 最大值
         Min 最小值
         NotBlank 字符串不为空
         NotEmpty 数组 集合 不为空
         NotNull  不允许为null
         Size 验证长度 字符串 数组 集合
         Pattern 匹配指定正则 
    
    
     在项目启动时,获取 ValidateAbstract 子类放入静态变量中,
     在拦截器中根据使用的注解去获取对应的验证器,然后进行验证。 拦截器代码同样适合验证service方法
     
     
     
     地址:https://gitee.com/heHouHui/jfinal_validated.git
     
     我不生成代码,我只是代码的搬运工


     

           

评论区

静态代码块

2018-12-26 14:38

需要自定义时,只需要实现ValidateAbstract 类,自定义个注解 在verifyParameter方法中实现自己的验证规则

JFinal

2018-12-26 14:51

通过 inv.getMethod().getAnnotation(...) 这种灵活扩展 Interceptor 的方式在 jfinal 文档中都未提及,赞一个这种探索方案

静态代码块

2018-12-26 14:58

@JFinal 多谢波总夸奖,我是看到jfinal的AOP 实现 和ParaGetter 才想到用这种方案的.不过我在测试过程中全局的me.addGlobalServiceInterceptor(validateServiceInterceptor); service拦截器不知道怎么进不去,难道需要提前全局增强吗?

JFinal

2018-12-26 15:53

@静态代码块 me.addGlobalServiceInterceptor(...) 这个只针对业务层拦截器,控制层用的是 me.add(...)

静态代码块

2018-12-26 16:17

@JFinal 是啊,我就想在业务层上也使用这个验证。所以才配置这个

静态代码块

2018-12-26 16:17

补充项目地址:https://gitee.com/heHouHui/jfinal_validated.git

静态代码块

2018-12-26 16:18

@JFinal 这个针对业务层的拦截器,对业务层不生效,百思不得其解

JFinal

2018-12-26 16:20

@静态代码块 jfinal 中的全局拦截分为 controller 层的全局拦截, 以及 controller 层之外的全局拦截,这个 controller 之外的我称之为业务层,并不太贴切

区分一下:
me. addGlobalServiceInterceptor(...)
me.addGlobalActionInterceptor(...) 就好

静态代码块

2018-12-26 16:26

@JFinal 这个了解您出的文档上面有些,现在的问题是,我copy了一份针对非controller的拦截器,也配置了全局(addGlobalServiceInterceptor 方式) 但是我在调用方法是没有进入拦截器 我用的是@Inject 注入

JFinal

2018-12-26 16:28

@静态代码块 单步调试一下, 父类的注入要用 Aop.get(...),不能用 @Inject

静态代码块

2018-12-26 16:42

@JFinal 也不是父类就是一个简单的类型,我看了一下通过@Inject 获取的是一个cglib 的代理类,但是还是不进拦截器,

JFinal

2018-12-26 16:52

@静态代码块 单步调试一下,看内部的拦截器都配置上了哪些,跟踪一下 InterceptorManager 这个类

热门分享

扫码入社