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

  

   完美!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM