注解实现校验前端参数

注解实现校验前端参数

环境

jdk1.6 + SSM

原理

切面拦截controller方法,然后捕获带@CheckParam注解方法参数实例,最后反射实例校验。突破口在于第二点,这里参考了SpringMVC是如何解析@RequestParam,底层实现有兴趣可以跟进去瞅瞅。Spring源码例子如下:

类名org.springframework.web.bind.annotation.support.HandlerMethodInvoker#resolveHandlerArguments

MethodParameter methodParam = new MethodParameter(handlerMethod, i);
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());

例子

校验model的fillInstructions字段

controller

@RequestMapping(value = "update" )
@ResponseBody
public ResultBean update(@CheckParam ProgramMaterialModel materialModel, HttpServletRequest request){
    return ResultBean.ok();
}

model

public class ProgramMaterialModel  implements Serializable{
    private static final long serialVersionUID = 4081985131881304723L;
    @CheckParam(notNull = true)
    private String fillInstructions;
}

annotation

@Target(value={ElementType.PARAMETER,ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckParam {
    boolean notNull()  default false;
}

aspect

package com.minstone.apprprograminterface.common.annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author lianxp
 * @Title: ${file_name}
 * @Package ${package_name}
 * @Description: ${todo}
 * @date 2018/3/29 9:21
 */
@Component
@Aspect
public class CheckParamAspect {
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void methodPointCut() {
    }

    /**
     * 环绕切入方法
     * @author lianxp
     * @date 2018/3/29 9:33
     * @param
     **/
    @Around("methodPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature msig =  (MethodSignature) point.getSignature();
        Method method = msig.getMethod();
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        Object[] args = point.getArgs();
        for (int i = 0; i < args.length; i++) {
            Object obj = args[i];
            MethodParameter mp = new MethodParameter(method,i);
            mp.initParameterNameDiscovery(u);
            GenericTypeResolver.resolveParameterType(mp, method.getClass());//Spring处理参数
            //String paramName = mp.getParameterName();//参数名
            CheckParam anno = mp.getParameterAnnotation(CheckParam.class);//参数注解
            if(anno != null){
                check(obj);
            }
        }
        return point.proceed();

    }

    /**
     * 校验成员变量
     * @author lianxp
     * @date 2018/3/29 9:56
     * @param 
     **/
    private void check(Object obj) throws IllegalAccessException {
        Class clazz  = obj.getClass();
        for(Field field : clazz.getDeclaredFields()){
            CheckParam cp = field.getAnnotation(CheckParam.class);
            if(cp != null){
                 check(obj,clazz, field,cp);
            }
        }
    }

    /**
     * 取出注解,校验变量
     * @author lianxp
     * @date 2018/3/29 10:01
     * @param
     **/
    private void check(Object obj, Class clazz, Field field, CheckParam cp) throws IllegalAccessException {
        if(cp.notNull()){
            field.setAccessible(true);
            Object f = field.get(obj);
            if(StringUtils.isEmpty(f)){
                throw  new IllegalArgumentException("类" + clazz.getName() + "成员" + field.getName() + "检测到非法参数");
            }
        }
    }
}

测试

浏览器直接访问调controller

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值