Springboot 自定义注解+AOP实现参数不能为空

一:自定义注解类

 1 package com.wing.my.cloud.system.modular.system.util.annotation;
 2 
 3 import java.lang.annotation.*;
 4 
 5 @Target({ElementType.PARAMETER, ElementType.METHOD})
 6 @Retention(RetentionPolicy.RUNTIME)
 7 @Documented
 8 public @interface CheckNullParams {
 9     String[] params();
10 }
View Code

二:AOP

  1 package com.wing.my.cloud.system.modular.system.util.aspect;
  2 
  3 import com.alibaba.fastjson.JSON;
  4 import com.alibaba.fastjson.JSONObject;
  5 import com.alibaba.fastjson.serializer.SerializerFeature;
  6 import com.wing.my.cloud.kernel.model.exception.ServiceException;
  7 import com.wing.my.cloud.system.modular.system.util.annotation.CheckNullParams;
  8 import lombok.extern.slf4j.Slf4j;
  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.Pointcut;
 13 import org.aspectj.lang.reflect.MethodSignature;
 14 import org.springframework.stereotype.Component;
 15 import org.springframework.util.StringUtils;
 16 import org.springframework.web.context.request.RequestContextHolder;
 17 import org.springframework.web.context.request.ServletRequestAttributes;
 18 
 19 import javax.servlet.http.HttpServletRequest;
 20 import java.util.*;
 21 
 22 /**
 23  * 校验参数不能为空
 24  * ProceedingJoinPoint只能用在环绕通知上。
 25  */
 26 @Slf4j
 27 @Aspect
 28 @Component
 29 public class CheckNullParamsAspect {
 30 
 31     private static String dateFormat = "yyyy-MM-dd HH:mm:ss";
 32 
 33     @Pointcut("@annotation(com.wing.my.cloud.system.modular.system.util.annotation.CheckNullParams)")
 34     public void paramNotNull(){}
 35 
 36     @Around("paramNotNull()")
 37     public Object  doAround(ProceedingJoinPoint joinPoint) throws Throwable{
 38         log.info("进入到环绕通知中");
 39         // 1、记录方法开始执行的时间
 40         long start = System.currentTimeMillis();
 41 
 42         // 2、打印请求参数
 43         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
 44         HttpServletRequest request = attributes.getRequest();
 45         String target = joinPoint.getSignature().getDeclaringTypeName();              // 全路径类名
 46         String classNm = target.substring(target.lastIndexOf(".") + 1, target.length()); // 类名截取
 47         String method = joinPoint.getSignature().getName();                          // 获取方法名
 48         Map<String, String> params = getAllRequestParam(request);                    // 获取请求参数
 49         log.info("{}.{} 接收参数: {}", classNm, method, JSON.toJSONString(params));
 50 
 51         CheckNullParams check = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckNullParams.class); // 获取注解
 52         String[] requiredFields = check.params();                                   // 获取注解参数
 53         // 3、必填参数非空校验
 54         Map<String,Object> result = validParams(params, requiredFields);
 55         if ((Boolean) result.get("boolean")) {
 56 
 57             Object object = joinPoint.proceed();        // 必填参数非空校验通过,执行方法,获取执行结果
 58             // 4、打印应答数据和方法耗时
 59             long time = System.currentTimeMillis() - start;
 60             log.info("{}.{} 应答数据: {}; 耗时 {} ms", classNm, method, JSONObject.toJSONStringWithDateFormat(object,
 61                     dateFormat, SerializerFeature.WriteMapNullValue), time);
 62             return object;
 63         } else {
 64             // 必填参数非空校验未通过,抛出异常,由GlobalExceptionHandler捕获全局异常,返回调用方“参数缺失”
 65             throw new ServiceException(500, "参数【" + result.get("param") + "】缺失或格式错误");
 66 
 67         }
 68 
 69     }
 70 
 71     /**
 72      * 校验传入参数params(非null)中是否必含requiredFields(非null)中的各个属性,且属性值非空
 73      *
 74      * @param params         传入参数
 75      * @param requiredFields 设置的非空属性数组
 76      * @return 校验通过返回true,否则返回false
 77      */
 78     private Map<String,Object> validParams(Map<String, String> params, String[] requiredFields) {
 79         Map<String, Object> map = new HashMap<>(2);
 80         if (requiredFields.length == 0) {
 81             // 无必送参数,直接返回true
 82             map.put("boolean", true);
 83             return map;
 84         } else {
 85             for (String field : requiredFields) {
 86                 if (StringUtils.isEmpty(params.get(field))) {
 87                     map.put("boolean", false);
 88                     map.put("param", field);
 89                     return map;
 90                 }
 91             }
 92             map.put("boolean", true);
 93             return map;
 94         }
 95     }
 96 
 97     /**
 98      * 获取请求参数
 99      */
100     public static Map<String, String> getAllRequestParam(HttpServletRequest request) {
101         Map<String, String> res = new HashMap<>();
102         Enumeration<?> temp = request.getParameterNames();
103         if (null != temp) {
104             while (temp.hasMoreElements()) {
105                 String en = (String) temp.nextElement();
106                 String value = request.getParameter(en);
107                 res.put(en, value);
108                 // 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
109                 if (StringUtils.isEmpty(res.get(en))) {
110                     res.remove(en);
111                 }
112             }
113         }
114         return res;
115     }
116 
117 }
View Code

三:实现

 1 @ApiImplicitParams({
 2             @ApiImplicitParam(name = "channelParam", value = "闲钱保渠道维护表实体类", dataType = "ChannelParam", paramType = "query", example = "xxx"),
 3     })
 4     @ResponseBody
 5     @ApiResource(name = "测试接口", path = "/test1")
 6     @CheckNullParams(params = {"custId","inpName"})  //参数不能为空
 7     public ResponseData test1( InsurancePolicyParam insurancePolicyParam) {
 8         testUserService.testExceptionAop(insurancePolicyParam);
 9         return ResponseData.success();
10     }
View Code

参数 custId,inpName为InsurancePolicyParam实体类的属性。

AOP各种通知

前置通知

方法执行前开始执行

1 @Before("declareJointPointExpression()")
2     public void beforeMethod(JoinPoint joinPoint) {
3         String methodName = joinPoint.getSignature().getName();
4         Object[] args = joinPoint.getArgs();
5 
6         System.out.println("这是切面开始打印出来的--->The method " + methodName + " begins with " + Arrays.asList(args));
7     }
View Code
1 //后置通知
2 //方法执行后开始执行
3 @After("declareJointPointExpression()")
4 public void afterMethod(JoinPoint joinPoint) {
5 String methodName = joinPoint.getSignature().getName();
6 System.out.println("这是切面结束打印出来的--->The method " + methodName + " ends");
7 }
View Code

带返回值的后置通知

方法正常执行后执行

1 @AfterReturning(value = "declareJointPointExpression()",
2             returning = "result")
3     public void afterReturningMethod(JoinPoint joinPoint,Object result) {
4         String methodName = joinPoint.getSignature().getName();
5         System.out.println("The method " + methodName + " ends with " + result);
6     }
View Code

异常通知

代码执行中出现异常后执行

1  @AfterThrowing(value = "exceptionLog()",throwing = "e")
2     public void afterThrowing(JoinPoint point, Exception e) throws Throwable {
3         String target = point.getSignature().getDeclaringTypeName();              // 全路径类名
4         String classNm = target.substring(target.lastIndexOf(".") + 1, target.length()); // 类名截取
5         String method = point.getSignature().getName();                          // 获取方法名
6         log.error("{}.{} 【异常信息】: {}", classNm, method, e.getMessage());
7     }
View Code

先执行前置通知,然后代码,然后异常通知,然后后置通知。

原文地址:https://www.cnblogs.com/bulrush/p/14004412.html