在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
相关产品推荐
相关产品推荐

