本篇主要分享的是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