在咱們平常的開發過程當中,咱們能夠經過接口日誌去查看這個接口的一些詳細信息。好比客戶端的IP,客戶端的類型,響應的時間,請求的類型,請求的接口方法等等,咱們能夠對這些數據進行統計分析,提取出咱們想要的信息。html
這裏,咱們使用的是Spring的兩大殺器之AOP,經過在Controller層定義切點,而後對請求對象進行分析獲取接口信息,同時開啓一個ThreadLocal來記錄響應時間。java
@Aspect
:將一個類定義爲切面類。@Pointcut
:定義一個切入點。@Before
:在切入點開始處切入內容。@After
:在切入點結尾處切入內容。@AfterReturning
:在切入點返回內容以後切入內容(能夠用來對處理返回值作一些加工處理。@Around
:在切入點先後切入內容,並本身控制什麼時候執行切入點自身的內容@AfterThrowing
:用來處理當切入內容部分拋出異常以後的處理邏輯。@Order
:在切入點前的操做,按order的值由小到大執行;在切入點後的操做,按order的值由大到小執行。首先,咱們須要新增引入aop的依賴,以及用於分析客戶端信息的UserAgentUtils包,還有用於@Slf4j
打印日誌的Lombok的包:spring
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>eu.bitwalker</groupId> <artifactId>UserAgentUtils</artifactId> <version>1.20</version> </dependency>
在以前的統一返回值和異常處理中咱們已經定義過這個類,這裏是對其進行完善。這裏我再把代碼再寫一下:數據庫
@Aspect @Order(5) @Component @Slf4j public class ResponseAop
直接在這裏定義基本類型會有同步問題,因此咱們定義一個ThreadLocal對象來記錄消耗的時間。api
ThreadLocal<Long> startTime = new ThreadLocal<>();
這裏須要注意的是切點的寫法,必定要正確才能保證AOP生效!這裏附上一些簡單的寫法,後續會單獨開一章講解execution表達式的書寫。瀏覽器
execution(public * *(..))
execution(* set*(..))
execution(* com.xyz.service.Service.*(..))
execution(* com.xyz.service.*.*(..))
xecution(* com.xyz.service..*.*(..))
/** * 切點 */ @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))") public void httpResponse() { }
@Before("httpResponse()") public void doBefore(JoinPoint joinPoint){ //開始計時 startTime.set(System.currentTimeMillis()); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //打印請求的內容 UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));//獲取請求頭中的User-Agent log.info("接口路徑:{}" , request.getRequestURL().toString()); log.info("瀏覽器:{}", userAgent.getBrowser().toString()); log.info("瀏覽器版本:{}",userAgent.getBrowserVersion()); log.info("操做系統: {}", userAgent.getOperatingSystem().toString()); log.info("IP : {}" , request.getRemoteAddr()); log.info("請求類型:{}", request.getMethod()); log.info("類方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); log.info("請求參數 : {} " + Arrays.toString(joinPoint.getArgs())); }
@AfterReturning(returning = "ret" , pointcut = "httpResponse()") public void doAfterReturning(Object ret){ //處理完請求後,返回內容 log.info("方法返回值:{}" , ret); log.info("方法執行時間:{}毫秒", (System.currentTimeMillis() - startTime.get())); }
下面,咱們對一個接口進行訪問:spring-boot
2019-02-21 21:03:31.358 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 接口路徑:http://localhost:8090/users 2019-02-21 21:03:31.359 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 瀏覽器:CHROME 2019-02-21 21:03:31.359 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 瀏覽器版本:72.0.3626.109 2019-02-21 21:03:31.360 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 操做系統: MAC_OS_X 2019-02-21 21:03:31.360 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : IP : 0:0:0:0:0:0:0:1 2019-02-21 21:03:31.360 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 請求類型:GET 2019-02-21 21:03:31.360 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 類方法 : indi.viyoung.viboot.apilog.controller.UserController.findAll 2019-02-21 21:03:31.360 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 請求參數 : {} [] ... 2019-02-21 21:03:31.393 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 方法返回值:ReturnVO{code='2000', message='操做成功', data=[User(id=10000001, password=123456, userName=vi-young), User(id=10000002, password=123456, userName=vi-young), User(id=10000003, password=123123, userName=lxt), User(id=10000004, password=123456, userName=yangwei)]} 2019-02-21 21:03:31.393 INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop : 方法執行時間:36毫秒
能夠看出,咱們已經獲取到咱們想要的信息~工具
在後面的應用實戰中,咱們會將這些信息保存到數據庫中,而且使用一些數據分析工具進行分析。測試
您的推薦是對我最大的幫助!spa
原文出處:https://www.cnblogs.com/viyoung/p/10416230.html