獲取行為日志對(duì)日常排查bug能夠起到一定的幫助褪尝,使用自定義注解記錄行為日志是非常便捷的一種方式
1.自定義注解
//指明了修飾的這個(gè)注解的使用范圍,即被描述的注解可以用在哪里
@Target(ElementType.METHOD)
//指明修飾的注解的生存周期期犬,即會(huì)保留到哪個(gè)階段(RUNTIME: 運(yùn)行級(jí)別保留河哑,編譯后的class文件中存在,在jvm運(yùn)行時(shí)保留龟虎,可以被反射調(diào)用)
@Retention(RetentionPolicy.RUNTIME)
//指明修飾的注解璃谨,可以被例如javadoc此類的工具文檔化,只負(fù)責(zé)標(biāo)記鲤妥,沒有成員取值
@Documented
public @interface RecordLog {
}
2.切面類
@Component
//把當(dāng)前類標(biāo)識(shí)為一個(gè)切面供容器讀取
@Aspect
public class LogAspect {
@Resource
private SystemLogRepository logRepository;
//客戶端請(qǐng)求佳吞,大部分信息可以在這里面獲取到
@Resource
private HttpServletRequest request;
//將添加了RecordLog這個(gè)注解的地方作為一個(gè)切入點(diǎn)
@Pointcut("@annotation(com.xxx.RecordLog)")
public void logPointCut() {
}
/**
* 方法正常退出時(shí)執(zhí)行
*/
@AfterReturning(pointcut = "logPointCut()")
public void doAfterReturning(JoinPoint joinPoint) {
try {
saveLog(joinPoint, null);
} catch (Exception e) {
e.printStackTrace();
}
}
//這個(gè)方法用于對(duì)切面獲取到的數(shù)據(jù)進(jìn)行處理,根據(jù)實(shí)際應(yīng)用場(chǎng)景可以選擇存到數(shù)據(jù)庫或者打印到日志文件中
private void saveLog(JoinPoint joinPoint, String e) throws Exception {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
//獲取ApiOperation注解的value棉安,同樣的方法可以獲取你加在切入點(diǎn)方法上的注解的各種參數(shù)
ApiOperation annotation = method.getAnnotation(ApiOperation.class);
String userId = request.getParameter("userId");
SystemOperationLog operationLog = new SystemOperationLog();
operationLog.setOperationId(UUID.randomUUID().toString().replace("-", ""));
operationLog.setTitle(annotation.value());
//獲取請(qǐng)求方法(POST底扳、GET等)
operationLog.setBusinessType(request.getMethod());
//獲取方法名
operationLog.setOperationMethod(methodSignature.getName());
operationLog.setUserId(userId);
operationLog.setUrl(request.getRequestURL().toString());
//獲取調(diào)用方本地ip地址
operationLog.setUserIp(InetAddress.getLocalHost().getHostAddress());
//獲取請(qǐng)求參數(shù)并轉(zhuǎn)換成json格式
operationLog.setOperationParam(JSON.toJSONString(joinPoint.getArgs()));
operationLog.setStatus(e == null ? 0 : 1);
operationLog.setErrorMessage(e);
operationLog.setOperationTime(new Date());
logRepository.save(operationLog);
}
/**
* 方法拋出異常時(shí)執(zhí)行
*/
@AfterThrowing(pointcut = "logPointCut()", throwing = "exception")
public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
try {
saveLog(joinPoint, exception.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
本篇文章中只用到了doAfterThrowing和doAfterReturning,通常根據(jù)業(yè)務(wù)場(chǎng)景選擇切面方法在什么時(shí)候執(zhí)行贡耽,以后用到其他場(chǎng)景再來更新
參考文章:
https://www.cnblogs.com/hyc-ana/p/9325618.html
https://www.cnblogs.com/jap6/p/10637429.html
https://blog.csdn.net/fz13768884254/article/details/83538709