SpringBoot自定义注解+AOP切面实现日志监控

项目层级

SpringBoot自定义注解+AOP切面实现日志监控_第1张图片

1.引入依赖

<dependency>
  <groupId>org.springframework.bootgroupId>
  <artifactId>spring-boot-starter-webartifactId>
dependency>

<dependency>
  <groupId>org.projectlombokgroupId>
  <artifactId>lombokartifactId>
  <optional>trueoptional>
dependency>

<dependency>
  <groupId>org.springframework.bootgroupId>
  <artifactId>spring-boot-starter-aopartifactId>
dependency>

2.数据传输类


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @Author: Zoups
 * @Date: 2023/01/16/14:02
 * @Description: 数据传输类
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LogDTO {

    /**
     * 注解上的描述
     */
    private String operation;

    /**
     * 请求时间
     */
    private Date requestTime;

    /**
     * 执行方法
     */
    private String method;

    /**
     * URL
     */
    private String url;


    /**
     * ip地址
     */
    private String ip;

    /**
     * 响应状态码
     */
    private String status;

}

3定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: Zoups
 * @Date: 2023/01/16/13:52
 * @Description: 日志注解
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    String value() default "";
}

4定义工具类

日志工具类

import com.example.annotationlog.aspect.LoggerAspect;
import com.example.annotationlog.dto.LogDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;

/**
 * @Author: Zoups
 * @Date: 2023/01/16/14:00
 * @Description: 日志工具类
 */
public class LogUtil {

    private static final Logger logger = LoggerFactory.getLogger(LoggerAspect.class);

    /**
     * 打印日志
     * @param sysLog
     * @param dateFormat
     * @param result
     */
    public static void printlnLog(LogDTO sysLog, SimpleDateFormat dateFormat, Object result){
        logger.info("--------------------请求日志---------------------");
        logger.info("请求IP地址 == "+sysLog.getIp());
        logger.info("请求方法路径 == "+sysLog.getMethod());
        logger.info("请求接口方法名 == "+sysLog.getOperation());
        logger.info("请求URL == "+sysLog.getUrl());
        logger.info("请求时间 == "+dateFormat.format(sysLog.getRequestTime()));
        logger.info("响应状态 == "+sysLog.getStatus());
        logger.info("响应内容 == "+result);
    }
}

Http工具类

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @Author: Zoups
 * @Date: 2023/01/16/14:19
 * @Description:
 */
public class HttpUtils {

    /**
     * 尝试获取当前请求的HttpServletResponse实例
     *
     * @return HttpServletResponse
     */
    public static HttpServletResponse getHttpServletResponse() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取IP地址
     *
     * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {

        String ip = request.getHeader("x-forwarded-for");
        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.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

}

5.定义日志切面

import com.example.annotationlog.annotation.Log;
import com.example.annotationlog.dto.LogDTO;
import com.example.annotationlog.utils.HttpUtils;
import com.example.annotationlog.utils.LogUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
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.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author: Zoups
 * @Date: 2023/01/16/13:54
 * @Description: 日志切面
 */

@Aspect
@Component
public class LoggerAspect {

    @Pointcut("@annotation(com.example.annotationlog.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 环绕通知 记录正常请求
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Date date = new Date(beginTime);//接口开始请求时间
        // 执行方法
        Object result = point.proceed();

        //异步保存日志
        saveLog(point,date,result);
        return result;
    }

    /**
     * 保存日志 可在此方法将日志保存至数据库
     * @param joinPoint
     * @param requestTime 请求时间
     * @param result 响应内容
     * @throws InterruptedException
     */
    private void saveLog(ProceedingJoinPoint joinPoint,Date requestTime,Object result) throws InterruptedException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogDTO sysLog = new LogDTO();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestURI = request.getRequestURI();
        sysLog.setUrl(requestURI);
        sysLog.setRequestTime(requestTime);
        Log syslog = method.getAnnotation(Log.class);
        if (syslog != null) {
            // 注解上的描述
            sysLog.setOperation(syslog.value());
        }
        int status = HttpUtils.getHttpServletResponse().getStatus();
        sysLog.setStatus(String.valueOf(status));
        sysLog.setIp(HttpUtils.getIpAddr(request));
        LogUtil.printlnLog(sysLog,new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"),result);
    }
}

6.测试Controller

import com.example.annotationlog.annotation.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: Zoups
 * @Date: 2023/01/16/14:06
 * @Description: 测试控制器
 */

@RestController
@RequestMapping("test")
public class TestController {

    @Log("测试")
    @GetMapping("logTest")
    public String getLogTest(){
        return "回家躺被窝";
    }
}

控制台打印结果

SpringBoot自定义注解+AOP切面实现日志监控_第2张图片

你可能感兴趣的:(spring,boot,java,spring)