Spring基於註解的環繞通知實現請求方法日誌記錄
使用註解AOP實現方法日誌記錄,免去重複寫日誌儲存的麻煩。該方案能記錄方法請求引數,返回結果等資訊
程式碼結構:
1.自定義註解
package com.example.demo.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在方法上使用該註解時,Spring會自動儲存被註解方法的請求引數和返回資訊到log表
* 儲存的基礎欄位包括:
* businessItemId:方法名稱
* requestParameter:請求的引數名稱以及引數值
* responseContent:請求的返回
* result:如果程式正常執行則儲存success,否則儲存failure
* types:傳參中的logType(根據註解中的傳參決定,非必填)
* typesName:types對應的名稱
* businessId:傳參中的businessId欄位(根據註解中的傳參決定,非必填)
* createTime:建立時間
* updateTime:更新時間
* note:如果程式異常執行,note欄位儲存e.getMessage()
* @author shengsheng
*/
// 方法註解
@Target(ElementType.METHOD)
// 執行時可見
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnno {
/**
* log的types欄位
* @return
*/
String logType() default "";
/**
* log的businessId欄位
* @return
*/
String businessId() default "";
}
2.切面實現
package com.example.demo.aop;
import com.alibaba.fastjson.JSON;
import com.example.demo.entity.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Log的AOP實現日誌
* @author shengsheng
*
*/
@Component
@Aspect
public class LogAspect {
/*@Autowired
private LogMapper logMapper;*/
@Pointcut("@annotation(com.example.demo.aop.LogAnno)")
public void logPointCut() {
}
/**
* 環繞通知記錄日誌通過註解匹配到需要增加日誌功能的方法
* @param pjp
* @return
* @throws Throwable
*/
@Around("logPointCut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
Log log = new Log();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature)signature;
// 1.方法執行前的處理,相當於前置通知
// 獲取正在訪問的類
Class executionClass = pjp.getTarget().getClass();
// 獲取訪問的方法的名稱
String methodName = pjp.getSignature().getName();
// 獲取正在訪問的方法
Method executionMethod =methodSignature.getMethod();
// 獲取訪問的方法的引數
Object[] args = pjp.getArgs();
//獲取方法中的引數名稱
ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
String[] parameterNames = pnd.getParameterNames(executionMethod);
log.setBusinessItemId(methodName);
if((parameterNames!=null)&&(parameterNames.length>0)&&(args!=null)&&(args.length>0)){
Map<String,Object> requestParams = new HashMap<>(args.length);
for (int i = 0 ;i<parameterNames.length;i++) {
requestParams.put(parameterNames[i],args[i]);
}
//設定請求引數
log.setRequestParameter(JSON.toJSONString(requestParams));
}
LogAnno annotation = executionMethod.getAnnotation(LogAnno.class);
//獲取註解中的types欄位
String logTypeStr = annotation.logType();
if(!StringUtils.isEmpty(logTypeStr)){
Integer logType = Integer.valueOf(logTypeStr);
log.setTypes(logType);
log.setTypesName("");
}
String businessId = annotation.businessId();
log.setBusinessId(businessId);
Object result = null;
try {
//讓代理方法執行
result = pjp.proceed();
// 2.後置通知
log.setResult("success");
} catch (Exception e) {
// 3.異常通知
log.setResult("failure");
log.setNote(e.getMessage());
} finally {
// 4.最終通知
Date now = new Date();
log.setCreateTime(now);
log.setResponseContent(JSON.toJSONString(result));
log.setUpdateTime(now);
System.out.println(log);
//入庫
// logMapper.insertSelective(log);
}
return result;
}
}
3.在方法上使用註解
package com.example.demo.utils;
import com.example.demo.aop.LogAnno;
import org.springframework.stereotype.Component;
/**
* description:
*
* @author shengsheng
* @date 2020/9/24 16:32
*/
@Component
public class CalculateUtils {
//使用註解
@LogAnno(logType = "1",businessId = "div")
public Integer div(Integer a,Integer b){
return a/b;
}
}
4.測試
package com.example.demo.test;
import com.example.demo.utils.CalculateUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* description:
*
* @author shengsheng
* @date 2020/9/24 16:48
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculateTest {
@Autowired
private CalculateUtils calculateUtils;
@Test
public void test() {
Integer div = calculateUtils.div(1, 1);
System.out.println(div);
}
}
5.測試結果
Log{id=null, types=1, typesName='', businessId='div', businessItemId='div', result='success', requestParameter='{"a":1,"b":1}', responseContent='1', note='null', createTime=Thu Sep 24 17:12:57 CST 2020, updateTime=Thu Sep 24 17:12:57 CST 2020}
相關文章
- 運用Spring Aop,一個註解實現日誌記錄Spring
- 基於AOP和ThreadLocal實現日誌記錄thread
- Spring AOP 實現業務日誌記錄Spring
- SpringBoot記錄HTTP請求日誌Spring BootHTTP
- Spring Aop基於註解的實現Spring
- Apache 記錄請求響應時間日誌Apache
- Rust 實現日誌記錄功能Rust
- laravel如何利用中介軟體優雅的記錄請求日誌Laravel
- spring和ehcache整合,實現基於註解的快取實現Spring快取
- PHP日誌記錄方法PHP
- spring基於註解配置實現事務控制Spring
- [轉載] spring aop 環繞通知around和其他通知的區別Spring
- Spring boot學習(六)Spring boot實現AOP記錄操作日誌Spring Boot
- Laravel 實現使用中介軟體記錄所有請求資訊以及日誌純 JSON 格式儲存LaravelJSON
- 使用Spring Request-Reply實現基於Kafka的同步請求響應SpringKafka
- 欄位修改記錄操作日誌的實現
- 基於註解的6.0許可權動態請求框架——JPermission框架
- Spring Cloud Gateway 之 請求應答日誌列印SpringCloudGateway
- Java Web之基於註解的Spring MVC環境配置JavaWebSpringMVC
- 基於.NetCore3.1系列 —— 日誌記錄之自定義日誌元件NetCore元件
- 日誌模組(一標頭檔案就實現了日誌記錄)
- Spring Boot利用AOP獲取使用者操作實現日誌記錄Spring Boot
- 記錄 | 實習日誌 9
- .net core基於HttpClient實現的網路請求庫HTTPclient
- php日誌,記錄日誌PHP
- Laravel8記錄請求和返回日誌Laravel
- 基於註解的 Spring MVC詳解SpringMVC
- Spring Boot AOP 掃盲,實現介面訪問的統一日誌記錄Spring Boot
- Spring基於註解的IoC配置Spring
- Spring基於註解的aop配置Spring
- Spring(5、基於註解的事物)Spring
- Grafana系列-Loki-基於日誌實現告警GrafanaLoki
- JAVA基礎-註解記錄Java
- WebApi系列~基於單請求封裝多請求的設計~請求的安全性設計與實現WebAPI封裝
- 基於註解的 PHP 列舉類實現PHP
- thinkphp 利用中介軟體 實現日誌操作記錄PHP
- 基於.NetCore3.1系列 —— 日誌記錄之日誌配置揭祕NetCore
- 請問為什麼越來越多的技術偏向於基於註解的實現方式?