spring aop拦截Controller做参数校验

来源:互联网 发布:sql update多条记录 编辑:程序博客网 时间:2024/06/06 15:16

       在项目中,我们会对入参做校验,这些参数的校验逻辑我们会写很多次.能不能将这些参数的校验逻辑提出来呢?答案是可以.Spring 有自己的validate工具方法,我个人感觉不是太好远,想自己定制更加契合自己项目的校验机制.经过哆哆嗦嗦的研究,有点结果,现在贴出来,大家一起看看!

       我曾经写过一个工具类,就是会在Service层的方法上加上自定义的注解,利用Spring aop拦截标注注解的方法,如果有缓存就返回缓存,如果没有,则会从数据库取出或者重新计算,

以达到提高吞吐率.实践证明还是挺好用的.

        经过以上描述,我们今天的关键词就有了,就是:Spring,Spring MVC,Spring AOP,java反射,java注解

       

一,Controller的拦截

     一般的,我们项目中bean的管理和mvc的配置是分开的,之前轻松的给service层加上了aop切面,但是用之前的方法发现不好使.为什么?因为Controller是归mvc层管理的,按照原来的方法,根本拦截不到controller的方法.

     1,将切面配置在spring 的bean.xml中,需要协调Controller注解(以后我再补上原因)

     2,将切面配置在spring 的mvc.xml中,这样不用协调Controller注解.

     

<bean id="validateAdvitor" class="com.test.rest.api.web.validators.ParamValidateAdvisor"/><aop:config proxy-target-class="true"><aop:aspect ref="validateAdvitor"><aop:pointcut expression="@annotation(com..rest.api.web.validators.annos.Validate)" id="validateCut"/><aop:around method="validate" pointcut-ref="validateCut"/></aop:aspect></aop:config>

二,Advisor

package com.test.rest.api.web.validators;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.List;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.test.common.enums.ErrorCode;import com.test.framework.common.util.Check;import com.est.rest.api.util.ResponseUtil;import com.test.rest.api.web.validators.annos.Must;import com.test.rest.api.web.validators.annos.Validate;/** * 参数验证 * @author michael.bai * @date 2016年12月20日 */public class ParamValidateAdvisor{private Logger logger = LoggerFactory.getLogger(ParamValidateAdvisor.class);/** * 校验入参 * @param point * @throws Throwable  */public Object validate(ProceedingJoinPoint point) throws Throwable{logger.info("开始拦截接口入参!");Object[] objs = point.getArgs();MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();//检测Annotation[][] annos = method.getParameterAnnotations();boolean flag = validateParameterAnnotation(annos);//虽然方法加了注解,但是参数么有注解,passif(!flag){return point.proceed(objs);}//得到标注@Validate注解的参数List<Param> params = AnnotationHelper.getParms(method,objs);if(!Check.NuNList(params)){for(Param param : params){String validRes = validateDetail(param);if(!Check.NuNString(validRes)){logger.info("客户端上报参数错误详细信息:{}",validRes);return ResponseUtil.message(ErrorCode.CLIENT_ERROR.getCode(), "客户端上报参数错误");}}}//没有错误就沿着毛主席的路线继续前进!return point.proceed(objs);}/** * 具体的校验逻辑,返回警告信息 * @param obj * @return * @throws IllegalAccessException  * @throws IllegalArgumentException  */private String validateDetail(Param param) throws IllegalArgumentException, IllegalAccessException{Validate val = (Validate)param.getAnno();boolean isVali = val.isValidate();StringBuilder sb = new StringBuilder();if(isVali){if(val.isForm() == true){String res = validateForm(param);append(sb,res);}else{String res = validateCommon(param);append(sb,res);}}return sb.toString();}private void append(StringBuilder sb,String res){if(!Check.NuNString(res)){sb.append("_");sb.append(res);}}/** * 验证是否有某个注解 * @param annos * @param validate * @return */private boolean validateParameterAnnotation(Annotation[][] annos){boolean flag = false;for(Annotation[] at : annos){for(Annotation a : at){if(a.annotationType() == Validate.class){flag = true;}}}return flag;}private String  validateCommon(Param param){String res = null;if(Check.NuNObject(param.getValue())){res = param.getName()+"的参数值为空!";}return res;}private String validateForm(Param param) throws IllegalArgumentException, IllegalAccessException{Class<?> clazz = param.getValue().getClass();Field[] fields = clazz.getDeclaredFields();StringBuilder sb = new StringBuilder();for(Field f : fields){Annotation[] annos = f.getAnnotations();if(!Check.NuNArray(annos)){String paramName = param.getName()+"."+f.getName();Must must = (Must)annos[0];if(must.isMust()){f.setAccessible(true);Object obj = f.get(param.getValue());Class<?> type = f.getType();if(type.isArray()){Object[] arr = (Object[])obj;if(Check.NuNArray(arr)){append(sb, paramName+"不能为空!");}}else if(type.isPrimitive()){if(type == int.class){int intObj = (int)obj;if(intObj <= 0){append(sb, paramName+"不能小于等于0!");}}else if(type == long.class){long longObj = (long)obj;if(longObj <= 0){append(sb, paramName+"不能小于等于0!");}}}else if(type == String.class){if(Check.NuNString((String)obj)){append(sb, paramName+"不能为空!");}}}}}return sb.toString();}}

三,注解

    1,Validate

     

package com.test.rest.api.web.validators.annos;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 校验注解 * @author michael.bai * @date 2016年12月20日 */@Target({ElementType.PARAMETER,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface Validate {public boolean isValidate() default true;public boolean isForm() default false;}

2,Must

 

package com.test.rest.api.web.validators.annos;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 必须的 * @author michael.bai * @date 2016年12月20日 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Must {public boolean isMust() default true;}

四,AnnotationHelper

   

package com.test.rest.api.web.validators;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.reflect.MethodSignature;import com.test.rest.api.web.validators.annos.Validate;/** * 注解帮助类 * @author michael.bai * @date 2016年12月20日 */public class AnnotationHelper {/** * 获取MethodSignature * @param point * @return */public static Signature getMethod(ProceedingJoinPoint point){MethodSignature sign = (MethodSignature) point.getSignature();return sign;}/** * 获取参数列表 * @param point * @return */public static Object[] getArgs(ProceedingJoinPoint point){return point.getArgs();}/** * 获取参数的描述 * @param method * @param objs * @return */public static List<Param> getParms(Method method,Object[] objs){Annotation[][] annos = method.getParameterAnnotations();Class<?>[] paramTypes = method.getParameterTypes();List<Param> params = new ArrayList<Param>();for(int i=0;i<annos.length;i++){for(int j=0;j<annos[i].length;j++){//如果出现指定的注解类型if(annos[i][j].annotationType() == Validate.class){Param param = new Param(paramTypes[i].getSimpleName(),        paramTypes[i].getName(),//名称                                        paramTypes[i],//参数类型                                                        objs[i],//参数值                                        annos[i][j]);//筛选出的注解params.add(param);}}}return params;}}

五,Param

package com.test.rest.api.web.validators;import java.lang.annotation.Annotation;/** * 方法参数类 * @author michael.bai * @date 2016年12月28日 */public class Param {private String simpleName;//简单名字private String name;//名字private Class<?> type;//类型private Object value;//值private Annotation anno;//注解public Param() {super();}public Param(String simpleName,String name, Class<?> type, Object value, Annotation anno) {super();this.simpleName = simpleName;this.name = name;this.type = type;this.value = value;this.anno = anno;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Class<?> getType() {return type;}public void setType(Class<?> type) {this.type = type;}public Object getValue() {return value;}public void setValue(Object value) {this.value = value;}public Annotation getAnno() {return anno;}public void setAnno(Annotation anno) {this.anno = anno;}public String getSimpleName() {return simpleName;}public void setSimpleName(String simpleName) {this.simpleName = simpleName;}@Overridepublic String toString() {return "Param [simpleName=" + simpleName + ", name=" + name + ", type=" + type + ", value=" + value + ", anno="+ anno + "]";}}



六,TestForm

     

package com.test.rest.api.web.validators;import java.io.Serializable;import com.test.rest.api.web.validators.annos.Must;public class TestForm implements Serializable{private static final long serialVersionUID = 1L;@Mustprivate int age;@Mustprivate String[] pics;@Mustprivate long goodsIds;public String[] getPics() {return pics;}public void setPics(String[] pics) {this.pics = pics;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public long getGoodsIds() {return goodsIds;}public void setGoodsIds(long goodsIds) {this.goodsIds = goodsIds;}}

七,TestController

     

package com.test.rest.api.web.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.test.rest.api.web.validators.TestForm;import com.test.rest.api.web.validators.annos.Validate;@Controller@RequestMapping("/best")public class TestController {@RequestMapping("/test")@ResponseBody@Validatepublic Object test(Integer age,String name,@Validate(isForm=true) TestForm form){System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBB");return age +":您好!";}}

八,测试结果

 

2 0
原创粉丝点击