AOP记录日志

71 阅读1分钟

AOP记录日志

package com.xxxxxxx.config;

import com.alibaba.fastjson.JSON;
import com.ly.traffic.ground.cxy.config.util.AopUtil;
import com.ly.traffic.ground.saas.base.helper.LoggerHelper;
import com.ly.traffic.ground.saas.util.Constants;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;

@Aspect
@Configuration
public class LogAopConfig {

    private LoggerHelper log = LoggerHelper.getLoggerHelper(Constants.ModuleName.OPEN_API, LogAopConfig.class.getSimpleName());
    /**
     * 进入方法时间戳
     */
    private Long startTime;
    /**
     * 方法结束时间戳(计时)
     */
    private Long endTime;

    /**
     * 排除健康检查url
     * 或者排除其他打印的非业务log请求
     * 这里使用 ThreadLocal 去排除
     * 当然也可以在拦截器里去排除
     */
    public static final String MONITOR_URL = "/monitor";

    private static final ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();

    public LogAopConfig() {
    }

    /**
     * 定义请求日志切入点,其切入点表达式有多种匹配方式,这里是指定路径
     */
    @Pointcut("execution(public * com.ly.traffic.ground.cxy.api..*.*(..))")
    public void webLogPointcut() {
    }

    /**
     * 前置通知:
     * 1. 在执行目标方法之前执行,比如请求接口之前的登录验证;
     * 2. 在前置通知中设置请求日志信息,如开始时间,请求参数,注解内容等
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLogPointcut()")
    public void doBefore(JoinPoint joinPoint) {

        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        try {
            if (request.getRequestURL().toString().contains(MONITOR_URL)){
                threadLocal.set(true);
                return;
            }

            //打印请求的内容
            startTime = System.currentTimeMillis();

            StringBuilder sb = new StringBuilder("");
            sb.append("请求Url : ").append(request.getRequestURL().toString()).append("\r\n");
            sb.append("请求方式 : ").append(request.getMethod()).append("\r\n");
            sb.append("请求ip : ").append(request.getRemoteAddr()).append("\r\n");
            sb.append("请求方法 : ").append(joinPoint.getSignature().getDeclaringTypeName()).append(".").append(joinPoint.getSignature().getName()).append("\r\n");
            String paramter = AopUtil.getString(joinPoint);
            sb.append("请求参数 : ").append(paramter);
            log.infoLog(sb.toString());
        }catch (Exception e){
            log.infoLog("doBefore print log : " + e.getMessage(), e);
        }
    }


    /**
     * 返回通知:
     * 1. 在目标方法正常结束之后执行
     * 1. 在返回通知中补充请求日志信息,如返回时间,方法耗时,返回值,并且保存日志信息
     *
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "webLogPointcut()")
    public void doAfterReturning(Object ret) throws Throwable {
        try {
            if (judge()) {
                return;
            }

            endTime = System.currentTimeMillis();

            StringBuilder sb = new StringBuilder("");
            sb.append("请求耗时 : ").append((endTime - startTime)).append("\r\n");
            sb.append("请求返回 : ").append(JSON.toJSONString(ret));

            log.infoLog(sb.toString());
        } catch (Exception e) {
            log.infoLog("doAfterReturning print log : " + e.getMessage(), e);
        }
    }

    private boolean judge() {
        if (!Objects.isNull(threadLocal.get()) && threadLocal.get()) {
            threadLocal.remove();
            return true;
        }
        return false;
    }

}