Springboot 自定义注解+AOP实现参数不能为空
一:自定义注解类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
二:AOP
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
三:实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
参数 custId,inpName为InsurancePolicyParam实体类的属性。
AOP各种通知
前置通知
方法执行前开始执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
带返回值的后置通知
方法正常执行后执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
异常通知
代码执行中出现异常后执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
先执行前置通知,然后代码,然后异常通知,然后后置通知。