You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中使用Aspect仅记录请求体而非所有参数?

解决Spring AOP无法精准匹配@RequestBody参数的问题

我明白你遇到的困扰了——你的Aspect当前没有精准捕获到@RequestBody标记的请求体参数,反而记录了所有传入的参数。这是因为args(.., @RequestBody requestBody)的写法在参数匹配上存在歧义,Spring AOP无法准确识别出仅带有该注解的参数,尤其是当方法包含多个参数时更容易出错。

下面给你两种可靠的解决方案,推荐第二种,适配性更强:

方案一:优化切入点表达式(适用于参数位置固定的场景)

如果你的控制器方法中@RequestBody参数的位置固定(比如是唯一参数或最后一个参数),可以修改切入点的args表达式,精准绑定目标参数:

// 当@RequestBody是方法唯一参数时
@Before("logRequestMapping() && executeController() && args(@RequestBody requestBody)")
public void logRequestBody(JoinPoint joinPoint, Object requestBody) {
    LOGGER = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
    if (requestBody != null) {
        LOGGER.info("Method : {}, Request Body:{}", 
            LOGGER.getName() + "." + joinPoint.getSignature().getName(), 
            MaskingUtil.jsonifyAndMask(requestBody));
    }
}

这种写法的局限性在于,如果@RequestBody参数在参数列表中间,或者方法存在多个参数,匹配逻辑就会失效。

方案二:手动识别@RequestBody参数(通用解决方案)

这种方法通过遍历方法参数和对应的注解,精准定位带有@RequestBody的参数,同时可以直接判断参数是否为null,决定是否输出日志,适配所有参数位置的情况:

import org.springframework.web.bind.annotation.RequestBody;
import java.lang.reflect.Method;
import org.aspectj.lang.reflect.MethodSignature;

// 省略其他必要导入

@Before("logRequestMapping() && executeController()")
public void logRequestBody(JoinPoint joinPoint) {
    // 获取方法签名与反射对象
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method targetMethod = methodSignature.getMethod();
    // 获取参数注解数组与参数值数组
    Annotation[][] paramAnnotations = targetMethod.getParameterAnnotations();
    Object[] paramValues = joinPoint.getArgs();

    // 获取目标类的Logger实例
    LOGGER = LoggerFactory.getLogger(joinPoint.getTarget().getClass());

    // 遍历参数,查找带有@RequestBody注解的参数
    for (int i = 0; i < paramAnnotations.length; i++) {
        for (Annotation annotation : paramAnnotations[i]) {
            if (annotation instanceof RequestBody) {
                Object requestBody = paramValues[i];
                // 仅当请求体不为null时输出日志
                if (requestBody != null) {
                    LOGGER.info("Method : {}, Request Body:{}", 
                        LOGGER.getName() + "." + methodSignature.getName(), 
                        MaskingUtil.jsonifyAndMask(requestBody));
                }
                // 通常一个方法仅一个@RequestBody,找到后直接退出循环
                return;
            }
        }
    }
}

这个方案的优势:

  • 不受参数位置限制,无论@RequestBody在参数列表的哪个位置都能精准捕获
  • 直接判断请求体是否为null,避免空值日志输出
  • 逻辑清晰,避免切入点表达式的匹配歧义

另外,建议把LOGGER的初始化移到类级别(如果不需要目标类的Logger的话):

private static final Logger LOGGER = LoggerFactory.getLogger(YourAspectClassName.class);

如果确实需要使用目标控制器类的Logger,当前在方法内获取的方式是可行的。

内容的提问来源于stack exchange,提问作者Atul Agrawal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:44:25