双拦截链+aop实现智能参数检查

双拦截链+aop实现智能参数检查

注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Documented
public @interface CheckEmail {
    String msg() default "email format invalid";
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotEmpty {

  String msg() default "字段不能为空";
  
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotNull {

  String msg() default "字段不能为NULL";
  
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Documented
public @interface CheckUser {
    String msg() default "current user dose not exist";
}


/**
 * 标注在参数bean上,表示需要对该参数校验
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidParam {
  
  
}

aspect

@Component
@Aspect
public class FieldVerify {


    private List<Handler> paramChainHandler = new ArrayList<>();
    {
        paramChainHandler.add(new NotNullHandler());//null
        paramChainHandler.add(new NotEmptyHandler());//空值,“null”,“undefined”
        paramChainHandler.add(new CheckEmailHandler());//邮箱格式
        paramChainHandler.add(new CheckUserHandler());//用户是否存在检查
        paramChainHandler.add(new ReleaseHandler());//释放的handler,以后要再加节点应该加在此节点前
        paramChainHandler.add(new ValidParamHandler());//处理@ValidParam
    }


    @Before("execution(* com.ruoyi.project.app.controller.box.*.*(..))")
    public void fieldVerify(JoinPoint point) throws Exception {
        //获取参数对象
        Object[] args = point.getArgs();
        //获取方法参数
        MethodSignature signature = (MethodSignature) point.getSignature();
        Parameter[] parameters = signature.getMethod().getParameters();

        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            for(Handler handler:paramChainHandler){
                if(handler instanceof ValidParamHandler){
                    handler.handler(parameter,args);
                }else{
                    if(handler.handler(parameter,args[i])){
                        //ReleaseHandler释放掉整条链
                        break;
                    }
                }
            }
        }
    }

}

handler

public interface Handler {
    /**
     * 处理器接口
     * 拦截链某节点处理成功,说明参数不符合要求,则会抛出异常
     * 如果返回false说明参数正常,应交由下一个节点处理
     * 如果返回true(只有这个ReleaseHandler会返回true),应该释放掉整条链的执行
     * @param element 参数Parameter对象或者Field属性
     * @param obj 参数对象
     * @return
     */
    boolean handler(AnnotatedElement element, Object obj) throws IllegalAccessException;

}
public class CheckEmailHandler implements Handler{

    @Override
    public boolean handler(AnnotatedElement element, Object obj) {
        Class<?> clazzType = null;
        CheckEmail checkEmail = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            clazzType = parameter.getType();
            checkEmail = parameter.getAnnotation(CheckEmail.class);
        }else if(element instanceof Field){
            Field field = (Field) element;
            clazzType = field.getType();
            checkEmail = field.getAnnotation(CheckEmail.class);
        }
        if(clazzType==String.class&&checkEmail != null&&!RegexValidate.validationEmail((String)obj)){
            throw new RuntimeException(checkEmail.msg());
        }
        return false;
    }
}

public class CheckUserHandler implements Handler {
    @Override
    public boolean handler(AnnotatedElement element, Object obj) {
        CheckUser checkUser = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            checkUser = parameter.getAnnotation(CheckUser.class);
        }else if(element instanceof Field){
            Field field = (Field) element;
            checkUser = field.getAnnotation(CheckUser.class);
        }
        if(checkUser!=null){
            if(null==SpringUtils.getBean(IAppUserService.class).selectAppUserById((Long)obj)){
                throw new RuntimeException(checkUser.msg());
            }
        }
        return false;
    }
}
public class NotEmptyHandler implements Handler{
    @Override
    public boolean handler(AnnotatedElement element,Object obj) {
        Class<?> clazzType = null;
        NotEmpty notEmpty = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            clazzType = parameter.getType();
            notEmpty = parameter.getAnnotation(NotEmpty.class);
        }else if(element instanceof Field){
            Field field = (Field) element;
            clazzType = field.getType();
            notEmpty = field.getAnnotation(NotEmpty.class);
        }

        if(clazzType==String.class&&notEmpty != null&&StringUtils.isInvalid((String) obj)){
            throw new RuntimeException(notEmpty.msg());
        }
        return false;
    }
}
public class NotNullHandler implements Handler{
    @Override
    public boolean handler(AnnotatedElement element, Object obj) {
        NotNull notNull = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            notNull = parameter.getAnnotation(NotNull.class);
        }else if(element instanceof Field){
            Field field = (Field) element;
            notNull = field.getAnnotation(NotNull.class);
        }

        if (notNull != null && obj == null) {
            throw new RuntimeException(notNull.msg());
        }
        return false;
    }
}
public class ReleaseHandler implements Handler {
    @Override
    public boolean handler(AnnotatedElement element, Object obj) {
        Class<?> clazzType = null;
        ValidParam validParam = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            clazzType = parameter.getType();
            validParam = parameter.getAnnotation(ValidParam.class);
        }else if(element instanceof Field){
            Field field = (Field) element;
            clazzType = field.getType();
            validParam = field.getAnnotation(ValidParam.class);
        }

        if (clazzType.isAssignableFrom(HttpServletRequest.class) || clazzType.isAssignableFrom(HttpSession.class) ||
                clazzType.isAssignableFrom(HttpServletResponse.class) || validParam == null) {
            //逻辑到这里就是参数已经没必要再检查了,因为满足上述条件之一就没必要在检查参数,应该释放整条链
            return true;
        }
        return false;
    }
}
public class ValidParamHandler implements Handler {

    private List<Handler> validParamChainHandler = new ArrayList<>();
    {
        validParamChainHandler.add(new NotNullHandler());//null
        validParamChainHandler.add(new NotEmptyHandler());//空值,“null”,“undefined”
        validParamChainHandler.add(new CheckEmailHandler());//邮箱格式
        validParamChainHandler.add(new CheckUserHandler());//用户是否存在检查
    }

    @Override
    public boolean handler(AnnotatedElement element, Object obj) throws IllegalAccessException {
        //到这里一定是参数标注了ValidParam注解

        Class<?> paramClazz = null;
        if(element instanceof Parameter){
            Parameter  parameter = (Parameter) element;
            paramClazz = parameter.getType();
        }else if(element instanceof Field){
            Field field = (Field) element;
            paramClazz = field.getType();
        }

        //获取类型所对应的参数对象,实际项目中Controller中的接口不会传两个相同的自定义类型的参数,所以此处直接使用findFirst()
        Class<?> finalParamClazz = paramClazz;
        Object arg = Arrays.stream((Object[])obj).filter(ar -> finalParamClazz.isAssignableFrom(ar.getClass())).findFirst().get();
        //得到参数的所有成员变量
        Field[] declaredFields = paramClazz.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            //二次责任链
            for(Handler handler:validParamChainHandler){
                handler.handler(field,field.get(arg));
            }
        }
        return false;
    }
}

用法

单一参数

public Result sendEmailCode(@NotEmpty @CheckEmail @PathVariable @ApiParam("邮件地址") String email)

bean参数

 public Result register(@RequestBody @ValidParam AccountVo account){}

@ApiModel("账户实体")
public class AccountVo implements Serializable {

    @ApiModelProperty("邮箱")
    @CheckEmail
    @NotEmpty
    private String email;

    @NotEmpty
    @ApiModelProperty("密码")
    private String password;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值