在 Spring 过滤器中获取控制器方法名称

问题描述 投票:0回答:1

我有一个 SpringBoot 2.6.14 WebApp,我正在使用 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 ecc..)、主机和其他一些有用的信息,但我无法检索

Controller
签名,或只是名称。谷歌搜索后我发现我可以用
HandlerInterceptor
来实现这一点,但我必须使用过滤器。

例如,如果我有一个像下面这样的

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
可以吗?

spring-boot http spring-mvc filter
1个回答
0
投票

不过这是可能的! 这是我的完整解决方案..

过滤器类配置:

@Configuration
public class FilterConfig {

  @Bean
  @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
  FilterRegistrationBean<LoggingFilter> logFilter(DispatcherServlet dispatcher) {
     FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
     registrationBean.setFilter(new LoggingFilter(dispatcher));
     registrationBean.addUrlPatterns("/api/v1/test/*");
     registrationBean.setOrder(Ordered.LOWEST_PRECEDENCE);
     return registrationBean;
  }

}

过滤器:

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

  private final DispatcherServlet dispatcher;

  public LoggingFilter(DispatcherServlet dispatcher) {
    super();
    this.dispatcher = dispatcher;
  }

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

    ServletRequestPathUtils.parseAndCache(request);
    
    List<HandlerMapping> mapping = dispatcher.getHandlerMappings();
    List<HandlerExecutionChain> chain = new ArrayList<>();
    mapping.forEach(item -> {
        try {
            HandlerExecutionChain c = item.getHandler(requestWrapper);
            chain.add(c);
        } catch (Exception e) {
            log.error(e);
        }
    });
    
    List<HandlerExecutionChain> resource = chain.stream().filter(i -> i != null).collect(Collectors.toList());
    HandlerExecutionChain hEc = resource.stream().findFirst().orElse(null);
    HandlerMethod handlerMethod = (HandlerMethod) hEc.getHandler();
    Method method = handlerMethod.getMethod(); // All INFO about the method called by request
    
    log.info(method.getName()); // method name
    ......
    responseWrapper.copyBodyToResponse();

}

也许不完全兼容,但如果您无法注册拦截器,这是实现结果的一种方法。

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.