springboot整合aop實現網站訪問日志記錄


目的:

統一日志輸出格式,統計訪問網站的ip.

思路:

1、針對不同的調用場景定義不同的注解,目前想的是接口層和服務層。

2、我設想的接口層和服務層的區別在於:

  (1)接口層可以打印客戶端IP,而服務層不需要

  (2)接口層的異常需要統一處理並返回,而服務層的異常只需要向上拋出即可

3、就像Spring中的@Controller、@Service、@Repository注解那樣,雖然作用是一樣的,但是不同的注解用在不同的地方顯得很清晰,層次感一下就出來了

4、AOP去攔截特定注解的方法調用

5、為了簡化使用者的操作,采用Spring Boot自動配置

 

如果要直接用@Aspect注解的話,要在spring的配置文件中加入

<aop:aspectj-autoproxy />

 

那么我們這里要不要在程序的主類中增加@EnableAspectJAutoProxy來啟用呢?實際並不需要

 

 

好的也就是說,只要引入SpringAOP相關的jar包依賴,我們就可以開始相關的Aspet的編程了。有時候攔截器也是可以實現的,但是如果我們采用的是post請求,如果使用攔截器就需要從報文中讀取數據,

其實就是io流,只能獲取一次,所以在controller中無法獲取數據,所以攔截器的方法是不可行的.

首先需要引入依賴:

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

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


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

controller中:

package com.cxy.shibernate.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/***
 * @ClassName: HelloController
 * @Description:
 * @Auther: cxy
 * @Date: 2019/5/19:18:06
 * @version : V1.0
 */
@Controller
public class HelloController {
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ResponseBody
    public String hello(@RequestParam String name) {
        return "Hello " + name;
    }

}

工具類:

package com.cxy.shibernate.controller;

/***
 * @ClassName: HttpContextUtils
 * @Description:
 * @Auther: cxy
 * @Date: 2019/5/19:18:17
 * @version : V1.0
 */
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

public class HttpContextUtils {

    public static HttpServletRequest getHttpServletRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return servletRequestAttributes.getRequest();
    }
//獲取ip
    public static String getIpAddress() {
        HttpServletRequest request = getHttpServletRequest();
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        }else if (ip != null && ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip;
    }
}

切面:

package com.cxy.shibernate.controller;

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 javax.servlet.http.HttpServletRequest;
import java.util.Arrays;


/***
 * @ClassName: WebLogAspect
 * @Description:
 * @Auther: cxy
 * @Date: 2019/5/19:18:08
 * @version : V1.0
 */
@Aspect
@Order(5)
@Component
public class WebLogAspect {
    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    ThreadLocal<Long> startTime = new ThreadLocal<>();
    /**
   第一個*表示返回任何類型,com.cxy.shibernate.controller下任何類,任何方法,任何參數
     也可以加入參數限定例如com.cxy.shibernate.controller.*.*(..)&&args(name,..)

     下面那中表示方法也是對的,表示com.cxy.shibernate.下面任何子包下任何方法,任何參數
    **/
    @Pointcut("execution(public * com.cxy.shibernate..*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());

        // 接收到請求,記錄請求內容

        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        String ipAddress = HttpContextUtils.getIpAddress();

        // 記錄下請求內容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        logger.info("ip:"+ipAddress);

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請求,返回內容
        logger.info("RESPONSE : " + ret);
        logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
    }



}

啟動類:

package com.cxy.shibernate;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ShibernateApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShibernateApplication.class, args);
    }

}

在application.yml不需要配置任何東西

啟動項目:

 

 

當然可以配置文件輸出的級別,制定輸出的文件夾


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM