参考文档

 

Spring Boot 2.x 教程系列 | AOP 切面统一打印请求日志最佳实践:https://juejin.im/post/5c6cf099f265da2d8c7dc3b0

手把手教你如何优雅的使用Aop记录带参数的复杂Web接口日志:https://www.cnblogs.com/detectiveHLH/p/10361006.html

相关依赖

<!-- aop 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- 用于日志切面中,以 json 格式打印出入参(本来使用阿里的 FASTJSON, 但是对于文件上传的接口,打印参数会报错,换为 Gson) -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

打印日志

打印日志方案——重写请求和输出类的toString

@Override
public String toString() {
    return JSONObject.toJSONString(this);
}

打印日志

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.yixiu.crm.common.util.ResponseCode;
import com.yixiu.crm.common.util.ServerResponse;
import com.yixiu.crm.constants.EnumSuite;
import com.yixiu.crm.dao.mapper.CrmOptionLogMapper;
import com.yixiu.crm.dao.po.CrmOptionLog;
import com.yixiu.crm.model.OptionParam;
import com.yixiu.crm.model.PublicParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @Auther: shiaige.zheng
 * @Description: 通用的apo打印日志
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Resource
    private CrmOptionLogMapper crmOptionLogMapper;
    /**
     * Excel导出的url
     */
    private final static List<String> URL_EXCEL = Arrays.asList(
            // 公海导出
            "/crm/excelExport/openHotelList",
            // 私海导出
            "/crm/excelExport/selfHotelList",
            // 公海统计导出
            "/crm/excelExport/openHotelStatistics",
            // 拜访列表导出
            "/crm/excelExport/hotelVisitList",
            // 拜访统计导出
            "/crm/excelExport/hotelVisitVisitStatistics",
            // 陪访统计导出
            "/crm/excelExport/hotelVisitAccompanyingStatistics",
            // 已合作酒店列表导出
            "/crm/excelExport/DataBoardCooperativeHotelList",
            // 已合作酒店统计导出
            "/crm/excelExport/DataBoardCooperativeHotelstatistics",
            // 已合作差评详情导出
            "/crm/excelExport/DataBoardAnalysisOfBadCommentsByJoinDate",
            // 评论分析导出
            "/crm/excelExport/DataBoardAnalysisOfCommentsByDate",
            // 评分分析导出
            "/crm/excelExport/DataBoardHotelCommentScoreAnalysis"
    );

    /**
     * 用来记录请求进入的时间,防止多线程时出错,这里用了ThreadLocal
     */
    private static final ThreadLocal<Long> STAR_TIME = new ThreadLocal<>();

    /**
     * 定义切入点,controller下面的所有类的所有公有方法,这里需要更改成自己项目的
     */
    @Pointcut("execution(public * com.yixiu.crm.controller..*.*(..))")
    public void requestLog() {
    }

    /**
     * 方法之前执行,日志打印请求信息
     *
     * @param joinPoint joinPoint
     */
    @Before("requestLog()")
    public void doBefore(JoinPoint joinPoint) {
        STAR_TIME.set(System.currentTimeMillis());
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        // 打印请求相关参数
        log.info("========================================== Start ==========================================");
        log.info(new Date().toString());
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.info("Request Args   : {}", joinPoint.getArgs());
        log.info("========================================== Start ==========================================");
    }

    /**
     * 方法返回之前执行,打印才返回值以及方法消耗时间,同时获取入参和返参
     *
     * @param response 返回值
     */
    @AfterReturning(returning = "response", pointcut = "requestLog()")
    public void doAfterReturning(JoinPoint point, Object response) {
        log.info("=========================================== End ===========================================");
        log.info(new Date().toString());
        // 打印出参
        log.info("Response Args  : {}", response);
        //打印请求耗时
        log.info("Request spend times : [{}ms]", System.currentTimeMillis() - STAR_TIME.get());
        STAR_TIME.remove();
        log.info("=========================================== End ===========================================");
    }


    /**
     * 打印异常
     */
    @AfterThrowing(throwing = "ex", pointcut = "requestLog()")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        log.error("=========================================== End ===========================================");
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        log.error(new Date().toString());
        // 打印请求 url
        log.error("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.error("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.error("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.error("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.error("Request Args   : {}", joinPoint.getArgs());
        log.error("Method Signature: {}", joinPoint.getSignature());
        log.error("Throwable:", ex);
        //打印请求耗时
        log.error("Request spend times : [{}ms]", System.currentTimeMillis() - STAR_TIME.get());
        STAR_TIME.remove();
        log.error("=========================================== End ===========================================");
    }

}