aop切面打印日志


切面日志类

主要包含几个模块:

  1. @Before: 前置通知
  2. @After: 后置通知
  3. @AfterThrowing: 异常通知
  4. @AfterReturning: 最终通知
  5. @Around: 环绕通知
    package demo.aop;
    
    import lombok.extern.slf4j.Slf4j;
    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.servlet.http.HttpServletRequest;
    import java.time.LocalDateTime;
    import java.util.Arrays;
    
    @Aspect
    @Component
    @Slf4j
    public class WebLogAspect {
     /**
     * 进入方法时间戳
     */
     private Long startTime;
     /**
     * 方法结束时间戳(计时)
     */
     private Long endTime;
     public WebLogAspect() {
     }
     /**
      * 定义请求日志切入点,其切入点表达式有多种匹配方式,这里是指定路径
      *第一个.*代表controller下所有的类
      * 第二个.*代表每个类里面的方法
      * (..)代表每个方法中的参数
     */
     //@Pointcut("@annotation(com.demo.annotation.Log)") // 通过注解
     @Pointcut("execution(public * demo.controller.*.*(..))")
     public void webLog() {
     }
    
     /**
     * 前置通知:
     * 1. 在执行目标方法之前执行,比如请求接口之前的登录验证;
     * 2. 在前置通知中设置请求日志信息,如开始时间,请求参数,注解内容等
     *
     * @param joinPoint
     * @throws Throwable
     */
     @Before("webLog()")
     public void doBefore(JoinPoint joinPoint) {
    
      // 接收到请求,记录请求内容
      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      HttpServletRequest request = attributes.getRequest();
      
      // 获取参数
      Map<String, Object> map = new HashMap<>();
      request.getParameterMap().forEach((key, value) -> map.put(key, value[0]));
      
      //打印请求的内容
      startTime = System.currentTimeMillis();
      log.info("请求开始时间:{}" + LocalDateTime.now());
      log.info("请求Url : {}" + request.getRequestURL().toString());
      log.info("请求方式 : {}" + request.getMethod());
      log.info("请求ip : {}" + request.getRemoteAddr());
      log.info("请求方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
      log.info("请求参数 : {}" + Arrays.toString(joinPoint.getArgs()));
     }
    
     /**
     * 返回通知:
     * 1. 在目标方法正常结束之后执行
     * 1. 在返回通知中补充请求日志信息,如返回时间,方法耗时,返回值,并且保存日志信息
     *
     * @param ret
     * @throws Throwable
     */
     @AfterReturning(returning = "ret", pointcut = "webLog()")
     public void doAfterReturning(Object ret) throws Throwable {
         endTime = System.currentTimeMillis();
         log.info("请求结束时间:{}" + LocalDateTime.now());
         log.info("请求耗时:{}" + (endTime - startTime));
         // 处理完请求,返回内容
         log.info("请求返回 : {}" + ret);
     }
    
     /**
     * 异常通知:
     * 1. 在目标方法非正常结束,发生异常或者抛出异常时执行
     * 1. 在异常通知中设置异常信息,并将其保存
     *
     * @param throwable
     */
     @AfterThrowing(value = "webLog()", throwing = "throwable")
     public void doAfterThrowing(Throwable throwable) {
         // 保存异常日志记录
         log.error("发生异常时间:{}" + LocalDateTime.now());
         log.error("抛出异常:{}" + throwable.getMessage());
     }
    }

操作日志如何和系统日志区分开

  1. logback配置

    //不同业务日志记录到不同的文件
    <appender name="businessLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/business.log</File>
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/业务A.%d.%i.log</fileNamePattern>
            <maxHistory>90</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>"%d{yyyy-MM-dd HH:mm:ss.SSS} %t %-5level %X{userId} %logger{30}.%method:%L - %msg%n"</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- additivity=false时不会在往上一级root打印,只在当前appender打印 -->
    <logger name="businessLog" additivity="false" level="INFO">
        <appender-ref ref="businessLogAppender"/>
    </logger>
  2. Java 代码配置

    //记录特定日志的声明
    private final Logger businessLog = LoggerFactory.getLogger("businessLog");
     
    //日志存储
    businessLog.info("日志");

评论