springboot项目利用AOP完成接口请求日志输出

本文介绍如何使用 Spring Boot 和 AOP 实现统一的日志记录功能,包括请求 URL、HTTP 方法、Controller 调用详情、客户端 IP 地址及请求参数等。通过配置 Maven 依赖和自定义切面类,实现对 RESTful API 的全面监控。

在这里插入图片描述

今天不想说废话,直接正儿八经的上教学,按照步骤来,没毛病~

配置

引入maven依赖

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

代码

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


@Component
@Aspect
@Slf4j
public class LogAop {
    @Autowired
    HttpServletRequest request;

    //换行符
    private final static String LINE_SEPARATOR = System.lineSeparator();

    @Pointcut("execution(public * com.example.demo.controller..*.*(..))")
    public void apiPointCut() {
    }

    @Around("apiPointCut()")
    public Object apiAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        //打印出参
        log.info("Response Args  : {}", new Gson().toJson(result));
        //执行耗时
        log.info("Time-Consuming : {} ms",System.currentTimeMillis()-startTime,LINE_SEPARATOR);
        return result;
    }

    @Before("apiPointCut()")
    public void beforeReturning(JoinPoint joinPoint) {
        //开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //打印相关请求参数
        log.info("=============== Start ===============");
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.info("Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
    }


    @After("apiPointCut()")
    public void doAfter(){
//        接口结束后换行,方便分割查看
        log.info("=============== End ===============");
    }

}

效果图

postman请求

在这里插入图片描述

日志打印

在这里插入图片描述
就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这
在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo
一个爱分享 J a v a 、生活的小人物, \color{#008B8B}{一个爱分享Java、生活的小人物,} 一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞! \color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!
在这里插入图片描述

<think>我们正在使用Spring Boot AOP实现接口请求日志记录。根据引用内容,我们可以总结出以下步骤: 1. 添加依赖:在`pom.xml`中添加Spring Boot AOP依赖。 2. 创建切面类:使用`@Aspect`注解标记的类,定义切面。 3. 定义切点:通过表达式指定哪些方法需要记录日志(例如,所有Controller中的方法)。 4. 编写通知:在方法执行前后(或异常时)记录日志,可以使用`@Before`、`@After`、`@Around`等注解。 5. 获取请求信息:在通知方法中,可以通过`JoinPoint`获取方法名、参数等信息,也可以注入`HttpServletRequest`来获取请求信息。 6. 记录日志:将获取的信息输出日志文件或数据库。 下面我们详细说明每个步骤。 ### 1. 添加依赖 在`pom.xml`中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` ### 2. 创建切面类 创建一个类,用`@Aspect`和`@Component`注解标记,这样Spring就会将其识别为一个切面并管理。 ### 3. 定义切点 使用`@Pointcut`注解定义切点表达式,例如: ```java @Pointcut("execution(* com.example.demo.controller..*.*(..))") public void controllerPointcut() {} ``` 这个切点表示`com.example.demo.controller`包下所有类的所有方法。 ### 4. 编写通知 我们通常使用`@Around`通知,因为它可以在方法执行前后都进行操作,并且可以控制方法是否执行。但也可以使用`@Before`和`@After`。 ### 5. 获取请求信息 我们可以通过`JoinPoint`获取方法签名、参数等信息。同时,为了获取HTTP请求信息,我们可以注入`HttpServletRequest`。 ### 6. 记录日志 在通知方法中,我们可以使用日志框架(如SLF4J)记录日志,也可以将日志存入数据库(如引用[2]所述)。 下面是一个完整的切面类示例,记录每个Controller方法的请求信息(包括请求时间、方法名、参数等)和耗时: ```java 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.slf4j.Logger; import org.slf4j.LoggerFactory; 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; @Aspect @Component public class RequestLogAspect { private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class); // 定义切点:controller包下的所有方法 @Pointcut("execution(* com.example.demo.controller..*.*(..))") public void controllerPointcut() {} @Around("controllerPointcut()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); // 获取请求信息 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录请求信息 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())); // 执行方法 Object result = joinPoint.proceed(); // 计算耗时 long endTime = System.currentTimeMillis(); logger.info("Response: {}", result); // 注意:如果返回结果很大,可能不适合打印,可以酌情处理 logger.info("Time Cost: {} ms", endTime - startTime); return result; } } ``` 注意:上面的示例中,我们打印了返回结果,这在生产环境中可能会因为返回结果过大而不适合,所以可以根据实际情况调整。 ### 扩展:记录到数据库 如果需要将日志记录到数据库,可以按照引用[2]中的方法设计数据库表,并在切面中调用Service层将日志信息保存到数据库。 ### 总结 通过以上步骤,我们可以在Spring Boot应用中利用AOP实现接口请求日志记录。这种方法非侵入式,只需添加一个切面类,即可统一处理所有Controller的请求日志。 §§相关问题§§ 1. 如何优化AOP日志记录的性能? 2. 如何避免记录敏感信息的日志? 3. 如何将日志记录到数据库?</think>### Spring Boot AOP 实现接口请求日志记录方法 以下是使用 Spring Boot AOP 实现接口请求日志记录的完整步骤: --- #### 1. **添加依赖** 在 `pom.xml` 中添加 AOP 依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` --- #### 2. **创建切面类** 定义切面类处理日志记录逻辑: ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; @Aspect @Component public class RequestLogAspect { // 定义切点:拦截所有Controller层方法 @Pointcut("execution(* com.example.controller..*.*(..))") public void requestLogPointcut() {} // 前置通知:记录请求信息 @Before("requestLogPointcut()") public void logRequest(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); // 构建日志信息 String log = String.format("Request | Time: %s | IP: %s | Method: %s | URI: %s | Args: %s", LocalDateTime.now(), request.getRemoteAddr(), request.getMethod(), request.getRequestURI(), Arrays.toString(joinPoint.getArgs())); System.out.println(log); // 实际项目中替换为Logger } // 后置通知:记录响应信息 @AfterReturning(pointcut = "requestLogPointcut()", returning = "result") public void logResponse(JoinPoint joinPoint, Object result) { String log = String.format("Response | Time: %s | Method: %s | Result: %s", LocalDateTime.now(), joinPoint.getSignature().getName(), result); System.out.println(log); // 实际项目中替换为Logger } } ``` --- #### 3. **关键配置说明** - **切点表达式**:`execution(* com.example.controller..*.*(..))` 表示拦截 `com.example.controller` 包下所有类的所有方法。 - **获取请求信息**:通过 `RequestContextHolder` 获取当前 HTTP 请求对象。 - **日志内容**: - **请求日志**:时间、客户端 IP、HTTP 方法、URI、参数。 - **响应日志**:时间、方法名、返回值。 --- #### 4. **扩展功能** ##### (1) 记录到数据库(引用[2]) 设计日志表结构: ```sql CREATE TABLE api_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, ip VARCHAR(20), method VARCHAR(10), uri VARCHAR(255), args TEXT, result TEXT, create_time DATETIME ); ``` 在切面中注入 `JdbcTemplate` 或 `Repository` 保存日志。 ##### (2) 添加 Trace ID(引用[5]) 实现分布式链路追踪: ```java // 在请求头中添加 traceId String traceId = UUID.randomUUID().toString(); MDC.put("traceId", traceId); // 使用 SLF4J 的 MDC // 日志格式中增加 %X{traceId} // 示例:logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%X{traceId}] %-5level %logger{36} - %msg%n ``` ##### (3) 排除敏感参数 使用自定义注解过滤敏感字段: ```java @Before("requestLogPointcut()") public void logRequest(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { if (args[i] instanceof UserDTO) { args[i] = ((UserDTO) args[i]).maskPassword(); // 脱敏处理 } } // 记录脱敏后的参数 } ``` --- #### 5. **优化建议** 1. **性能优化**: - 异步记录日志:使用 `@Async` 注解异步保存日志。 - 批量插入:攒批处理数据库写入(如每 10 条批量插入)[^2]。 2. **动态开关**: 通过配置中心动态启停日志: ```java @Before("requestLogPointcut() && @annotation(enableLogging)") public void logIfEnabled(JoinPoint joinPoint, EnableLogging enableLogging) { if (enableLogging.value()) { ... } } ``` --- #### **总结** 通过 AOP 实现接口日志记录的核心步骤: 1. 添加 `spring-boot-starter-aop` 依赖。 2. 定义切面类,使用 `@Pointcut` 定位拦截范围。 3. 通过 `@Before` 记录请求信息,`@AfterReturning` 记录响应信息。 4. 结合 `HttpServletRequest` 和 `JoinPoint` 获取请求上下文。 5. 扩展功能:数据库存储、链路追踪、敏感信息过滤。 > 此方法避免了业务代码耦合,统一处理日志逻辑[^1][^3],适用于监控、审计、调试等场景[^5]。 ---
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值