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
- spring aop拦截Controller做参数校验
- spring Aop拦截controller方法
- spring aop学习--拦截controller
- spring aop参数校验
- spring aop 拦截spring mvc controller
- spring4.x aop拦截spring mvc controller
- spring aop拦截controller层失效
- Spring AOP无法拦截Controller中的方法
- Spring Aop拦截controller配置注意事项
- Spring Boot -- Controller之Validate参数校验
- 使用Spring AOP预处理Controller的参数
- Spring AOP 对Spring MVC的Controller切面拦截不起作用
- Spring拦截器校验Json格式参数
- Spring AOP注解的方式校验参数
- 日志AOP拦截Controller
- Spring Aop自定义注解拦截Controller实现日志管理
- 基于Spring的Controller拦截器做性能监控
- SpringMVC的AOP拦截controller
- linux挂载新硬盘
- iOS 打包后 Export 导出4 个选项的含义
- Mac 下使用Xcode 配置Lua 环境并使用
- java poi 生成excel双表头
- 欢迎使用CSDN-markdown编辑器
- spring aop拦截Controller做参数校验
- 创建一个WiFi热点
- 2016yiqu
- Android引用Maven库AAR
- c/c++程序内存分配
- linux中的22个特殊字符
- RCNN算法详解
- OpenGL光照设置问题
- 数据挖掘十大算法- K-means 算法