双拦截链+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&¬Empty != 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;
}