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

在Spring OncePerRequestFilter中获取Controller方法名可行吗?

问题描述

我有一个SpringBoot 2.6.14 Web应用,正在使用Spring的OncePerRequestFilter记录HTTP请求和响应的相关信息,代码示例如下:

@Slf4j(topic = "logger")
public class LoggingFilter extends OncePerRequestFilter {

  private final ObjectMapper mapper;

  public LoggingFilter(ObjectMapper mapper) {
      super();
      this.mapper = mapper;
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    
    ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

    // 省略其他日志记录逻辑
}

我已经能记录URI、请求类型(GET、POST等)、主机及其他有用信息,但无法获取Controller的签名或仅方法名。查阅资料得知可通过HandlerInterceptor实现,但我必须使用Filter。

例如,我有如下Controller:

@RestController
@RequestMapping("/api/v1")
public class SomeController {

  @GetMapping("/all")
  public ResponseEntity<List<Some>> findAll() {
      List<Some> result = service.findAll();
      return new ResponseEntity<>(result, HttpStatus.OK);
  }
}

调用该接口时,我能获取路径/api/v1/all,但还想得到findAll()方法名。请问不使用HandlerInterceptor是否可行?

解决方案

可行,无需依赖HandlerInterceptor,核心是利用Spring MVC的RequestMappingHandlerMapping获取请求对应的Controller方法信息,具体实现步骤如下:

  • 注入映射处理器:在Filter中注入Spring容器的RequestMappingHandlerMapping实例,它维护了请求路径到Controller方法的映射关系。
  • 匹配请求到方法:在doFilterInternal中调用getHandler方法传入当前请求,拿到HandlerExecutionChain后提取HandlerMethod。
  • 提取方法信息:通过HandlerMethod直接获取方法名、类名等信息。

修改后的Filter代码示例:

@Slf4j(topic = "logger")
public class LoggingFilter extends OncePerRequestFilter {

  private final ObjectMapper mapper;
  private final RequestMappingHandlerMapping requestMappingHandlerMapping;

  // 构造函数注入依赖
  public LoggingFilter(ObjectMapper mapper, RequestMappingHandlerMapping requestMappingHandlerMapping) {
      super();
      this.mapper = mapper;
      this.requestMappingHandlerMapping = requestMappingHandlerMapping;
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    
    ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

    try {
        // 获取请求对应的处理器链
        HandlerExecutionChain handlerChain = requestMappingHandlerMapping.getHandler(request);
        if (handlerChain != null) {
            Object handler = handlerChain.getHandler();
            // 判断是否为Controller方法
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                String methodName = handlerMethod.getMethod().getName();
                String controllerName = handlerMethod.getBeanType().getSimpleName();
                log.info("请求对应Controller方法: {}.{}", controllerName, methodName);
            }
        }
        // 继续执行过滤器链
        filterChain.doFilter(requestWrapper, responseWrapper);
    } finally {
        // 确保响应内容被正确输出
        responseWrapper.copyBodyToResponse();
    }
}

注意点:

  • Spring Boot默认会自动配置RequestMappingHandlerMapping,直接注入即可,无需额外配置。
  • 该方式仅对标注@RequestMapping系列注解的Controller方法有效,对于静态资源等其他处理器需做判断过滤。
  • 提前调用getHandler会触发请求映射匹配,但不会影响正常请求流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:40:17