spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码
1.背景
在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下
2.代码
package com.qianxingniwo.log; import com.alibaba.fastjson.JSON; import com.qianxingniwo.exception.ParamException; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * @Copyright (C) * @Author: * @Date: 2019/4/8 10:11 * @Description: <p> * aop的几个重要概念 * 切面(做什么事情,切入后要执行的业务) * 切入点(在什么地点,具体到方法,一般使用通配符 或 注解) * 切入时机(在什么时候,方法执行前,方法执行后,抛异常的时候) * </p> */ @Aspect//定义切面 @Component //加入spring容器 @SuppressWarnings("all")//注解主要用在取消一些编译器产生的警告 public class SystemLogAspect { /** * 本地异常日志记录对象 */ private static final Logger log = LoggerFactory.getLogger(SystemLogAspect.class); /** * Controller层切点 */ @Pointcut("execution(* com.qianxingniwo.*.controller.*Controller.*(..))") public void controllerAspect() { } /** * 可以修改请求参数,如实际生成中,将请求参数解密等 * * @param joinPoint * @return * @throws Throwable */ @Around("controllerAspect()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("@Around=1=方法执行前" + System.currentTimeMillis()); Object[] obj = joinPoint.getArgs(); System.out.println("@Around=2=请求参数" + JSON.toJSONString(obj)); // Object obj2 = joinPoint.proceed(); // System.out.println("@Around=3=方法后" + System.currentTimeMillis() + "--" + obj2); // System.out.println("@Around:被织入的目标对象为:" + joinPoint.getTarget()); // System.out.println("@Around:原返回值:" + JSON.toJSONString(obj2) + ",这是返回结果的后缀"); // JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj[0])); //通过反射实例化参数对象 //获取字节码 Class<?> aClass = obj[0].getClass(); //实例化对象 Object instance = aClass.newInstance(); //获取执行方法 获取父类方法 setDataList //Method method = aClass.getDeclaredMethod("put", Object.class); Method method = aClass.getSuperclass().getMethod("put", Object.class); List<Integer> dataList = new ArrayList<>(); dataList.add(1); dataList.add(2); //执行方法 method.invoke(instance, dataList); // jsonObject.put("dataList", dataList); obj[0] = instance; //obj[0] = MAPPER.writeValueAsString(""); System.out.println("=====修改参数=========="); return joinPoint.proceed(obj); } /** * 切入时机 * * @param joinPoint * @Description 前置通知 用于拦截Controller层记录用户的操作 */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) throws ParamException { System.out.println("@Before==" + System.currentTimeMillis()); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); Thread.currentThread().setName(UUID.randomUUID().toString().substring(0, 12)); String params = ""; if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) { String data = JSON.toJSONString(joinPoint.getArgs()[0]); params += data; } //获取用户请求方法的参数并序列化为JSON格式字符串 //打印请求内容 String url = request.getRequestURL().toString(); log.info("===============请求内容==============="); log.info("请求地址:" + url); log.info("请求方式:" + request.getMethod()); log.info("请求类方法:" + joinPoint.getSignature()); log.info("请求类方法参数:" + params); log.info("===============请求内容==============="); } @After("controllerAspect()") public void After(JoinPoint point) { System.out.println("@After==" + System.currentTimeMillis()); /* System.out.println("@After:模拟释放资源..."); System.out.println("@After:目标方法为:" + point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName()); System.out.println("@After:参数为:" + Arrays.toString(point.getArgs())); System.out.println("@After:被织入的目标对象为:" + point.getTarget());*/ } /** * 统一修改响应结果,如加密等 * * @param joinPoint * @param o * @throws Exception */ @AfterReturning(returning = "o", pointcut = "controllerAspect()") public void methodAfterReturing(JoinPoint joinPoint, Object o) throws Exception { System.out.println("@AfterReturning==" + System.currentTimeMillis()); System.out.println("@AfterReturning:模拟日志记录功能..."); log.info("--------------返回内容----------------"); log.info("Response内容:" + JSON.toJSONString(o)); log.info("--------------返回内容----------------"); /* ResponseMessage responseMessage = (ResponseMessage) o; byte[] a = Base64Utils.encode(JSON.toJSONString(o).getBytes()); responseMessage.setMsg(new String(a )); log.info("请求返回值【{}】", object.toString());*/ } @AfterThrowing("controllerAspect()") public void AfterThrowing() { System.out.println("@AfterThrowing==" + System.currentTimeMillis()); System.out.println("异常通知...."); } }
执行结果如下:
3.执行流程图解
4.aop统一处理空字符串转为null的处理
package com.common.aop; import com.alibaba.fastjson.JSON; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @Copyright (C) * @Author: LI DONG PING * @Date: 2020-10-20 11:15 * @Description: */ @Aspect @Component @SuppressWarnings("all") public class ParamAspect { /** * */ @Pointcut("execution(* com.sys.controller.*Controller.*(..))") public void controllerAspect2() { } @Pointcut("execution(* com.common.base.BaseController.*(..))") public void controllerAspect() { } /** * 将空字符串参数设置为null * * @param joinPoint * @return * @throws Throwable */ @Around("controllerAspect() || controllerAspect2()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { Object[] obj = joinPoint.getArgs(); for (int i = 0; i < obj.length; i++) { Object o = obj[i]; String jsonString = JSON.toJSONString(o); Class<?> aClass = o.getClass(); Field[] fields = aClass.getDeclaredFields(); for (int j = 0; j < fields.length; j++) { String fieldName = fields[j].getName(); if ("serialVersionUID".equals(fieldName)) { continue; } Class type = fields[j].getType(); if (type != String.class) { continue; } Object value = aClass.getMethod("get" + upperCase(fieldName)).invoke(o); if (value != null && "".equals(value.toString())) { Method method = o.getClass().getMethod("set" + upperCase(fieldName), type); //将值设为null method.invoke(o, new Object[]{null}); } } } return joinPoint.proceed(obj); } public String upperCase(String str) { return str.substring(0, 1).toUpperCase() + str.substring(1); } }
完美!