天天看點

springboot AOP 切面配合自定義注解擷取行為日志

擷取swagger APIOperation上的注解,進行記錄檔輸出,非常友善。

1.自定義注解

//指明了修飾的這個注解的使用範圍,即被描述的注解可以用在哪裡
@Target(ElementType.METHOD)
//指明修飾的注解的生存周期,即會保留到哪個階段(RUNTIME: 運作級别保留,編譯後的class檔案中存在,在jvm運作時保留,可以被反射調用)
@Retention(RetentionPolicy.RUNTIME)
//指明修飾的注解,可以被例如javadoc此類的工具文檔化,隻負責标記,沒有成員取值
@Documented
public @interface RecordLog {

}
           

2.切面類

@Component
//把目前類辨別為一個切面供容器讀取
@Aspect
public class LogAspect {

    @Resource
    private SystemLogRepository logRepository;

    //用戶端請求,大部分資訊可以在這裡面擷取到
    @Resource
    private HttpServletRequest request;
    
    //将添加了RecordLog這個注解的地方作為一個切入點
    @Pointcut("@annotation(com.xxx.RecordLog)")
    public void logPointCut() {
    }

    /**
     * 方法正常退出時執行
     */
    @AfterReturning(pointcut = "logPointCut()")
    public void doAfterReturning(JoinPoint joinPoint) {
        try {
            saveLog(joinPoint, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //這個方法用于對切面擷取到的資料進行處理,根據實際應用場景可以選擇存到資料庫或者列印到日志檔案中
    private void saveLog(JoinPoint joinPoint, String e) throws Exception {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        //擷取ApiOperation注解的value,同樣的方法可以擷取你加在切入點方法上的注解的各種參數      
        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());
        //擷取請求方法(POST、GET等)
        operationLog.setBusinessType(request.getMethod());
        //擷取方法名
        operationLog.setOperationMethod(methodSignature.getName());
        operationLog.setUserId(userId);
        operationLog.setUrl(request.getRequestURL().toString());
        //擷取調用方本地ip位址
        operationLog.setUserIp(InetAddress.getLocalHost().getHostAddress());
        //擷取請求參數并轉換成json格式
        operationLog.setOperationParam(JSON.toJSONString(joinPoint.getArgs()));
        operationLog.setStatus(e == null ? 0 : 1);
        operationLog.setErrorMessage(e);
        operationLog.setOperationTime(new Date());
        logRepository.save(operationLog);
    }

    /**
     * 方法抛出異常時執行
     */
    @AfterThrowing(pointcut = "logPointCut()", throwing = "exception")
    public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
        try {
            saveLog(joinPoint, exception.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           

本篇文章中隻用到了doAfterThrowing和doAfterReturning,通常根據業務場景選擇切面方法在什麼時候執行,以後用到其他場景再來更新

參考文章:

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