1. 程式人生 > >aop實現記錄日誌

aop實現記錄日誌

1、建立springboot專案

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>
    </dependencies>


</project>

log4j.xml
 

# LOG4J配置
log4j.rootCategory=INFO, stdout, file, errorfile                       //級別,控制檯,檔案,錯誤的日誌
log4j.category.com.yy=DEBUG, bootfile                                  //com.yy包底下所有產生的日誌都會給它一個檔案 my.log
log4j.logger.error=errorfile

# 控制檯輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

# root日誌輸出
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender          //每天會產生一個日誌檔案
log4j.appender.file.file=D:/logs/all.log
log4j.appender.file.DatePattern='.'yyyy-MM-dd                          //年月日的命名檔案
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

# error下的日誌輸出
log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.errorfile.file=D:/logs/error.log
log4j.appender.errorfile.DatePattern='.'yyyy-MM-dd
log4j.appender.errorfile.Threshold = ERROR
log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout
log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

# com.newer下的日誌輸出
log4j.appender.bootfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.bootfile.file=D:/logs/my.log
log4j.appender.bootfile.DatePattern='.'yyyy-MM-dd
log4j.appender.bootfile.layout=org.apache.log4j.PatternLayout
log4j.appender.bootfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L ---- %m%n

application.properties

server.port=8088

logging.level.*=debug

2、切面:

package com.example.demo.common.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
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.util.Arrays;
/**
 * web請求日誌切面類---專門針對控制層,如誰被請求了,花了多少時間,請求傳送的引數,返回得值等
 * @author yy
 */
@Aspect     // 表示一個切面bean
@Component  // bean容器的元件註解。雖然放在contrller包裡,但它不是控制器。如果注入service,但我們又沒有放在service包裡
@Order(3)   // 有多個日誌時,ORDER可以定義切面的執行順序(數字越大,前置越後執行,後置越前執行)
public class WebLogAspect {
    //定義一個日誌記錄器
    Logger logger=LoggerFactory.getLogger(this.getClass());
    //定義一個執行緒本地變數,記錄各個執行緒開始的時間
    ThreadLocal<Long> starttime=new ThreadLocal<Long>();

    /**
     * 定義一個切入點
     */
    @Pointcut("execution(public * com.*.*.controller.*.*(..))")
    public void weblog(){
    }
    @Before("weblog()")
    public void doBefore(JoinPoint joinPoint){
        logger.info("前置通知");
        starttime.set(System.currentTimeMillis());

        //獲取servlet請求物件---因為這不是控制器,這裡不能注入HttpServletRequest,但springMVC本身提供ServletRequestAttributes可以拿到
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        logger.info("URL:"+request.getRequestURL().toString());
        logger.info("Method:"+request.getMethod());
        logger.info("CLASS_METHOD:"+joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
        logger.info("ARGS:"+ Arrays.toString(joinPoint.getArgs()));

    }
    //方法的返回值注入ret
    @AfterReturning(returning = "ret",pointcut = "weblog()")
    public void doafter(Object ret) {
        logger.info("後置通知:");
        logger.info("RESPONSE:" + ret);       // 響應的內容---方法的返回值responseEntity
        logger.info("SPEND:" + (System.currentTimeMillis() - starttime.get()));
    }
}

3、目標:
 

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {
    @RequestMapping("/home")
    public String home() {
        return "Hello World!";
    }
}