springboot+aop切點記錄請求和響應信息

来源:https://www.cnblogs.com/wangrudong003/archive/2018/11/07/9925336.html
-Advertisement-
Play Games

本篇主要分享的是springboot中結合aop方式來記錄請求參數和響應的數據信息;這裡主要講解兩種切入點方式,一種方法切入,一種註解切入;首先創建個springboot測試工程並通過maven添加如下依賴: 先來說方法的切點方式,需要創建個名為LogAspect的組件類,然後用@Aspect註解修 ...


  本篇主要分享的是springboot中結合aop方式來記錄請求參數和響應的數據信息;這裡主要講解兩種切入點方式,一種方法切入,一種註解切入;首先創建個springboot測試工程並通過maven添加如下依賴:

        <!-- AOP -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!--阿裡 FastJson依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.44</version>
        </dependency>

  先來說方法的切點方式,需要創建個名為LogAspect的組件類,然後用@Aspect註解修飾組件類,再通過設置方法切入點方式做公共日誌記錄,如下創建切入點:

    //切點入口 Controller包下麵所有類的所有方法
    private final String pointcut = "execution(* com.platform.Controller..*(..))";

    //切點
    @Pointcut(value = pointcut)
    public void log() {
    }

  這裡的execution( com.platform.Controller..(..))主要的意思是:切入點入口是Controller包下麵所有類的所有方法;再來通過@Around環繞註解方法裡面做請求參數和響應信息的記錄,如下代碼:

    @Around(value = "log()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        StringBuilder sbLog = new StringBuilder("\n");
        try {
            sbLog.append(String.format("類名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));

            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            sbLog.append(String.format("方法:%s\r\n", methodSignature.getMethod().getName()));

            Object[] args = proceedingJoinPoint.getArgs();
            for (Object o : args) {
                sbLog.append(String.format("參數:%s\r\n", JSON.toJSON(o)));
            }

            long startTime = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
            sbLog.append(String.format("耗時:%ss", endTime - startTime));
        } catch (Exception ex) {
            sbLog.append(String.format("異常:%s", ex.getMessage()));
        } finally {
            logger.info(sbLog.toString());
        }
        return result;
    }

  此刻主要代碼就完成了,再來我們配置下日誌的記錄方式;首先在 resources目錄增加名為logback-spring.xml的文件,其配置信息如:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!--
 3   ~ Author:shenniu003
 4   ~ Copyright (c) 2018.
 5   -->
 6 
 7 <configuration debug="false" scan="true" scanPeriod="1 seconds">
 8 
 9     <springProperty scope="context" name="appname" source="logging.logback.appname"/>
10     <springProperty scope="context" name="logLevel" source="logging.logback.level"/>
11     <springProperty scope="context" name="logPath" source="logging.logback.path"/>
12 
13     <property name="logPathAll" value="${logPath}/${appname}.log"/>
14 
15     <contextName>logback</contextName>
16 
17     <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
18         <!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter" >
19              <level>WARN</level>
20          </filter>-->
21         <encoder>
22             <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
23         </encoder>
24     </appender>
25 
26     <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
27         <file>${logPathAll}</file>
28         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
29             <fileNamePattern>${logPathAll}.%d{yyyy-MM-dd}.zip</fileNamePattern>
30         </rollingPolicy>
31         <encoder>
32             <pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
33             </pattern>
34         </encoder>
35     </appender>
36 
37     <root level="${logLevel}">
38         <appender-ref ref="console"/>
39         <appender-ref ref="file"/>
40     </root>
41 
42 </configuration>

  然後application.yml的配置信息如:

1 logging:
2   config: classpath:logback-spring.xml
3   logback:
4     level: info #info ,debug
5     path: /home/app/data/applogs/weblog
6     appname: web

  此刻日誌和公共的aop記錄類都完成了,我們需要創建個測試用例,其代碼如:

1     @PostMapping("/addUser")
2     public ResponseEntity<MoStudent> addUser(@RequestBody MoStudent moStudent) throws Exception {
3         moStudent.setNumber(UUID.randomUUID().toString());
4 //        throw new Exception("錯誤了");
5         return new ResponseEntity<>(moStudent, HttpStatus.OK);
6     }

  最後,通過postman模擬post請求,能夠得到如下的日誌結果:

  

  上面的方式切入點是所有方法,所有方法都記錄日誌可能有是不是需求想要的,此時可以通過註解的方式來標記想記錄日誌的方法;先來創建個日誌註解:

 1 @Target(ElementType.METHOD)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Documented
 4 public @interface LogAnnotation {
 5     /**
 6      * 描述
 7      *
 8      * @return
 9      */
10     String des() default "";
11 }

  同樣再來創建註解的切入點:

1     //匹配方法上包含此註解的方法
2     private final String annotationPointCut = "@annotation(com.platform.Aop.LogAnnotation)";
3 
4     //註解切點
5     @Pointcut(value = annotationPointCut)
6     public void logAnnotation() {
7     }

  再通過@Around註解綁定具體的操作方法:

 1     @Around(value = "logAnnotation()")
 2     public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
 3         Object result = null;
 4         StringBuilder sbLog = new StringBuilder("\n");
 5         try {
 6             sbLog.append(String.format("類名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
 7 
 8             MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
 9             Method method = methodSignature.getMethod();
10             LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
11             if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
12                 sbLog.append(String.format("說明:%s\r\n", logAnnotation.des()));
13             }
14             sbLog.append(String.format("方法:%s\r\n", method.getName()));
15 
16             Object[] args = proceedingJoinPoint.getArgs();
17             for (Object o : args) {
18                 sbLog.append(String.format("參數:%s\r\n", JSON.toJSON(o)));
19             }
20 
21             long startTime = System.currentTimeMillis();
22             result = proceedingJoinPoint.proceed();
23             long endTime = System.currentTimeMillis();
24             sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
25             sbLog.append(String.format("耗時:%ss", endTime - startTime));
26         } catch (Exception ex) {
27             sbLog.append(String.format("異常:%s", ex.getMessage()));
28         } finally {
29             logger.info(sbLog.toString());
30         }
31         return result;
32     }

  這個方法里需要註意的是註解方式相比第一種其實就多瞭如下幾行代碼:

1             Method method = methodSignature.getMethod();
2             LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
3             if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
4                 sbLog.append(String.format("說明:%s\r\n", logAnnotation.des()));
5             }

  下麵是註解測試用例:

1     @LogAnnotation(des = "註解記錄日誌")
2     @PostMapping("/addUser01")
3     public ResponseEntity<MoStudent> addUser01(@RequestBody MoStudent moStudent) throws Exception {
4         moStudent.setNumber(UUID.randomUUID().toString());
5         return new ResponseEntity<>(moStudent, HttpStatus.OK);
6     }

  如下是LogAspect.java的所有代碼:

  1 /*
  2  * Author:shenniu003
  3  * Copyright (c) 2018.
  4  */
  5 
  6 package com.platform.Aop;
  7 
  8 import com.alibaba.fastjson.JSON;
  9 import org.aspectj.lang.ProceedingJoinPoint;
 10 import org.aspectj.lang.annotation.*;
 11 import org.aspectj.lang.reflect.MethodSignature;
 12 import org.slf4j.Logger;
 13 import org.slf4j.LoggerFactory;
 14 import org.springframework.stereotype.Component;
 15 
 16 import java.lang.reflect.Method;
 17 
 18 /**
 19  * Created by Administrator on 2018/11/5.
 20  * springboot+aop切點記錄請求和響應信息
 21  */
 22 @Component
 23 @Aspect
 24 public class LogAspect {
 25 
 26     //切點入口 Controller包下麵所有類的所有方法
 27     private final String pointcut = "execution(* com.platform.Controller..*(..))";
 28 
 29     //匹配方法上包含此註解的方法
 30     private final String annotationPointCut = "@annotation(com.platform.Aop.LogAnnotation)";
 31 
 32     private Logger logger = LoggerFactory.getLogger(LogAspect.class);
 33 
 34     //切點
 35     @Pointcut(value = pointcut)
 36     public void log() {
 37     }
 38 
 39     @Around(value = "log()")
 40     public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
 41         Object result = null;
 42         StringBuilder sbLog = new StringBuilder("\n");
 43         try {
 44             sbLog.append(String.format("類名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
 45 
 46             MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
 47             sbLog.append(String.format("方法:%s\r\n", methodSignature.getMethod().getName()));
 48 
 49             Object[] args = proceedingJoinPoint.getArgs();
 50             for (Object o : args) {
 51                 sbLog.append(String.format("參數:%s\r\n", JSON.toJSON(o)));
 52             }
 53 
 54             long startTime = System.currentTimeMillis();
 55             result = proceedingJoinPoint.proceed();
 56             long endTime = System.currentTimeMillis();
 57             sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
 58             sbLog.append(String.format("耗時:%ss", endTime - startTime));
 59         } catch (Exception ex) {
 60             sbLog.append(String.format("異常:%s", ex.getMessage()));
 61         } finally {
 62             logger.info(sbLog.toString());
 63         }
 64         return result;
 65     }
 66 
 67     //註解切點
 68     @Pointcut(value = annotationPointCut)
 69     public void logAnnotation() {
 70     }
 71 
 72     @Around(value = "logAnnotation()")
 73     public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
 74         Object result = null;
 75         StringBuilder sbLog = new StringBuilder("\n");
 76         try {
 77             sbLog.append(String.format("類名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
 78 
 79             MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
 80             Method method = methodSignature.getMethod();
 81             LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
 82             if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
 83                 sbLog.append(String.format("說明:%s\r\n", logAnnotation.des()));
 84             }
 85             sbLog.append(String.format("方法:%s\r\n", method.getName()));
 86 
 87             Object[] args = proceedingJoinPoint.getArgs();
 88             for (Object o : args) {
 89                 sbLog.append(String.format("參數:%s\r\n", JSON.toJSON(o)));
 90             }
 91 
 92             long startTime = System.currentTimeMillis();
 93             result = proceedingJoinPoint.proceed();
 94             long endTime = System.currentTimeMillis();
 95             sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
 96             sbLog.append(String.format("耗時:%ss", endTime - startTime));
 97         } catch (Exception ex) {
 98             sbLog.append(String.format("異常:%s", ex.getMessage()));
 99         } finally {
100             logger.info(sbLog.toString());
101         }
102         return result;
103     }
104 }
View Code
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 公司推進Jenkins自動化部署,因為web站點都是集群部署,部署需要測試指定伺服器web服務是否成功啟動,頁面是否正常訪問,經過不斷baidu發現,python的request模塊可以很好的解決這一問題。本文記錄瞭解決這一問題的過程。 安裝包管理工具pip 安裝requests模塊 請求http資 ...
  • 之前介紹的各類變數都是單獨聲明的,倘若要求定義相同類型的一組變數,則需定義許多同類型的變數,顯然耗時耗力且不宜維護。為此,編程語言引入了數組的概念,每個數組都由一組相同類型的數據構成,對外有統一的數組名稱,對內通過序號區分每個數據元素。數組類型由基本的變數類型擴展而來,在基本類型後面加上一對方括弧, ...
  • HTTP連接管理: 1.誤解的Connection首部 當http報文經過中間客戶端到服務端中間的各種代理設備時,對標簽中列出的頭信息進行刪除,close是事務結束後關掉此條連接 2.消除串列化的時延 並行連接:多條TCP連接發起併發的HTTP請求 持久連接:重用TCP連接,消除連接和關閉時延 管道... ...
  • ''' 輸入2,5,列印: 1 2 3 4 5 6 7 8 9 10 ''' #行數 m = int(input('請輸入一個整數')) n = int(input('請在輸入一個整數')) for i in range(m): for j in range(n): num = i * n + j ... ...
  • TCP三次握手階段 三次握手總述 第一階段: 概念:半連接池 三次握手正常狀態 三次握手異常狀態syn_rcvd TCP四次揮手階段 四層揮手總述 UDP與TCP的區別 示例:如下圖訪問如下網址就會出現下麵的信息https://www.cnblogs.com/huwentao/p/9845379.h ...
  • 1.原因現在還不知,試了幾個地方可以和不可以 ...
  • 一、變數 1、實例變數(又叫欄位、屬性) 創建對象時給對象賦值 形式: self.xxx = xxx 訪問: 對象名.xxx 只能由對象訪問 1 class Person: 2 def __init__(self,age,name): 3 self.name = name #實例變數 4 self. ...
  • 步驟: 點擊Project->Properties->Libraries->Add External Class Folder.. ->選擇你的文件路徑->確定 1.點擊擊Project->Properties 2.選擇Libraries後點擊Add External Class Folder 3. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...