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.執行流程圖解
完美!