经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
spring boot+自定义 AOP 实现全局校验的实例代码
来源:jb51  时间:2019/4/10 8:27:46  对本文有异议

最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常。。。

仅凭代码 去控制参数的校验,有时候是冗余的,但通过框架支持的 去控制参数的校验,是对于开发者很友好,先看下面的例子

  1. @NotEmpty(message="手机号不能为空")
  2. @Size(min=11,max=11,message="手机号码长度不正确")
  3. @Pattern(regexp=StringUtils.REGEXP_MOBILE,message="手机号格式不正确")
  4. private String mobile;

这是spring boot支持的 校验注解,然后我们在 contoller层 加上@Valid 注解 就可以达到校验的目的。这是一种框架自带的

本章 就展示一种 自定义的 AOP 校验,首先 写一个注解,注解里面可以写上 我们需要校验的规则, 比如长度,正则。。。

  1. @Documented
  2. @Target({ElementType.FIELD,ElementType.METHOD})
  3. @Retention(RetentionPolicy.RUNTIME)
  4. public @interface ValidateParam {
  5. int min() default 0;
  6. int max() default Integer.MAX_VALUE;
  7. String message() default "params is not null";
  8. String regexp();
  9. Class<?>[] groups() default { };
  10. Class<? extends Payload>[] payload() default { };
  11. boolean isNotNull() default true;
  12. }

然后定义一个AOP类

  1. package com.onecard.primecard.common.aop;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.ParameterizedType;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.regex.Pattern;
  8. import org.aspectj.lang.JoinPoint;
  9. import org.aspectj.lang.ProceedingJoinPoint;
  10. import org.aspectj.lang.annotation.Around;
  11. import org.aspectj.lang.annotation.Aspect;
  12. import org.aspectj.lang.annotation.Before;
  13. import org.aspectj.lang.annotation.Pointcut;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.context.ApplicationContext;
  17. import org.springframework.context.support.ClassPathXmlApplicationContext;
  18. import org.springframework.stereotype.Component;
  19. import com.jfcf.core.dto.ResultData;
  20. import com.onecard.core.support.util.StringUtils;
  21. import com.onecard.primecard.common.annotation.ValidateParam;
  22. import com.onecard.primecard.common.utils.ResultDataUtil;
  23. /**
  24. * 全局 切面类(校验参数)
  25. *
  26. * @author Administrator
  27. *
  28. */
  29. @Aspect
  30. @Component
  31. public class GobalHandlerAspect {
  32. private static Logger logger = LoggerFactory.getLogger(GobalHandlerAspect.class);
  33. @Pointcut("execution(* 包名.controller..*.*(..)) && execution(* 包名.controller..*.*(..))")
  34. public void checkAspect(){};
  35. @Before("checkAspect()")
  36. public void befor(JoinPoint joinPoint) throws Exception{
  37. //前置统一输出参数
  38. Object[] args = joinPoint.getArgs();
  39. if(args != null && args.length>0){
  40. Object obj = args[0];
  41. ParameterizedType pt = (ParameterizedType)obj.getClass().getGenericSuperclass();
  42. Class<?> classzz = (Class<?>) pt.getActualTypeArguments()[0];
  43. logger.info("【小X卡】-【请求实体入参】:"+classzz.newInstance().toString());
  44. }
  45. }
  46. @Around("checkAspect()")
  47. public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
  48. //校验参数
  49. Object[] args = joinPoint.getArgs();
  50. Object obj = null;
  51. if(args != null && args.length > 0){
  52. obj = args[0];
  53. Class classzz = obj.getClass();
  54. //没有顺序和秩序的数组
  55. Field[] fieldArray = classzz.getDeclaredFields();
  56. ArrayList<Field> fieldList = new ArrayList<Field>(Arrays.asList(fieldArray));
  57. String res = checkParam(fieldList,obj);
  58. if(StringUtils.isNotNull(res)){
  59. return ResultDataUtil.result(ResultData.STATUS_PARAM_ERROR, res);
  60. }
  61. }
  62. return joinPoint.proceed();
  63. }
  64. private String checkParam(ArrayList<Field> fieldList, Object obj) throws Exception {
  65. for(Field field : fieldList){
  66. ValidateParam validateParam = field.getAnnotation(ValidateParam.class);
  67. logger.info("【小X卡】获取注解值:"+validateParam.isNotNull()+"min="+validateParam.min()+"max="+validateParam.max());
  68. Method method = obj.getClass().getMethod("get"+getMethodName(field.getName()));
  69. logger.info("【小X卡】入参实体方法名称:"+method.getName());
  70. if(method != null){
  71. Object val = method.invoke(obj);
  72. logger.info("【小x卡】回调方法:"+val);
  73. if(validateParam != null && validateParam.isNotNull() == true){
  74. if(null == val || "".equals(val) ){
  75. return field.getName()+"必填参数为空";
  76. }
  77. }
  78. if(validateParam.min()==11 && validateParam.max() == 11){
  79. if(val.toString().length() != 11){
  80. return field.getName()+"请输入参数正确的长度";
  81. }
  82. }
  83. if(validateParam.regexp().equals(StringUtils.REGEXP_MOBILE)){
  84. if(!Pattern.matches(StringUtils.REGEXP_MOBILE, val.toString())){
  85. return field.getName()+"参数格式错误";
  86. }
  87. }
  88. }
  89. }
  90. return null;
  91. }
  92. /**
  93. * 方法首字母大写
  94. * @param fieldName
  95. * @return
  96. */
  97. private String getMethodName(String fieldName) {
  98. StringBuffer buffer = new StringBuffer();
  99. String firstLetter = fieldName.substring(0, 1).toUpperCase();
  100. return buffer.append(firstLetter).append(fieldName.substring(1, fieldName.length())).toString();
  101. }
  102. }

定义一个切点 @Pointcut, 用execution 表达式,去获取要校验的 某个类 和某个方法, 也就是连接点,然后 用定义一个通知,上面代码中有2个通知,一个前置通知@Before,一个环绕通知@Around,我们使用功能最强大的环绕通知。

通过上面的代码可以看出  首先获取参数,然后通过反射机制 获取 入参对象中的全部字段, 再去获取 我们在字段中加 我们自定义注解的字段,通过反射方法的回调,获取字段值,对值做判断, 返回校验结果。

总结

以上所述是小编给大家介绍的spring boot+自定义 AOP 实现全局校验的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号