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不需要配置任何东西

启动项目:

 

 

当然可以配置文件输出的级别,制定输出的文件夹

posted @ 2019-05-19 21:51  菩提树下的丁春秋  阅读(3185)  评论(0编辑  收藏  举报