我正在开发一个使用 OncePerRequestFilter
使用传入的web请求执行一些自定义的类似日志的行为。此行为使用 HttpServletRequest
& HttpServletResponse
. 此外,过滤器同时使用 ContentCachingRequestWrapper
& ContentCachingResponseWrapper
访问请求/响应机构。
已经决定,我们只想在调用了特定spring控制器的方法时执行此行为,因为我们不想对其他控制器/执行器端点等执行此操作。是否有方法可以判断传入的请求是否将(或曾经)Map到控制器?
public class ExampleFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Can I tell here whether this will be mapping to an endpoint in
// ExampleController or NestedExampleController?
ContentCachingRequestWrapper requestToUse = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseToUse = new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(requestToUse, responseToUse);
// Can I tell here whether this was mapped to an endpoint in
// ExampleController or OtherExampleController?
} finally {
responseToUse.copyBodyToResponse(); // Write the cached body back to the real response
}
}
}
@RestController
@RequestMapping("/example")
public class ExampleController {
@GetMapping("/{id}")
public Example retrieveExample() {
return getValue(); // Retrieve the value
}
// ...
}
@RestController
@RequestMapping("/example/{id}/nested")
public class NestedExampleController {
@GetMapping("/{nestedId}")
public NestedExample retrieveNestedExample() {
return getValue(); // Retrieve the value
}
// ...
}
我对springmvc/boot的内部结构做了一些研究,我不确定是否有一种方法可以轻松地做到这一点。作为替代,我可以做一些手动url模式匹配,这可能不一定与控制器中的方法完全匹配,但可能会使我接近一个可以接受的解决方案。
总而言之:在web过滤器中有没有一种方法来判断传入请求是Map到控制器(在执行过滤器链之前)还是Map到控制器(在执行过滤器链之后)?
2条答案
按热度按时间vsikbqxv1#
您需要的基本上是一个面向应用程序特定部分的横切关注点—在本例中是日志记录。
这是面向方面编程最常见的用例之一,spring使用aspectj风格的切入点为其提供了内置支持。
您需要:
要在配置类的spring配置中启用aop,请执行以下操作:
定义一个方面,例如:
有关切入点表达式的详细信息,请参见本指南。
另一个常见的用例是对方法调用进行计时,尽管对于这种情况,类似于使用测微计(以及用于spring的测微计适配器)
@Timed
可能会更好。您还可以阅读参考文档,其中提供了大量关于spring中aop如何工作的信息。
注意:和几乎所有其他spring代理机制一样,来自目标对象内部的调用不会被代理,即。
this.otherControllerMethod()
不会被上述建议截取。同样地,private
方法也不能被拦截。有关更多信息,请参阅参考文件的第5.4.3节。最后一点,如果性能非常重要,您应该检查aspectj编译时或加载时编织,它消除了spring代理机制(spring aop在引擎盖下使用的机制)带来的一些开销。在您的情况下,这很可能不是必需的,但最好记住。
编辑以供评论:
谢谢!这种方法的一个警告是,它不允许我访问httpservletrequest或httpservletresponse,我正在使用它。如果我不需要的话,我知道这会有什么帮助。我发现我的问题中没有明确说明这个要求,所以我会相应地更新。
事实上,不幸的是,这种方法不可能直接做到这一点。如果你真的需要请求,那么
HandlerInterceptor
@darrenforsythe提到的方法是另一种可能的方法。如果你只想记录,我看不出你有什么理由绝对需要这个请求——除非你想提取特定的头并记录它们。在这种情况下,国际海事组织
OncePerRequestFilter
正如您最初尝试的那样,这会更好,因为您可以控制应用过滤器的请求(使用shouldNotFilter(HttpServletRequest request)
并在url上匹配)。pkbketx92#
经过一些额外的摸索和尝试,我发现控制器可以通过
RequestMappingHandlerMapping
豆子。当请求可以由控制器处理时,这将把请求Map到HandlerMethod
控制器的请求处理方法。为了更彻底、更真实地模拟spring的处理程序逻辑
DispatcherServlet
可以使用/模仿逻辑,而不是直接引用RequestMappingHandlerMapping
. 这将咨询所有处理程序,而不仅仅是RequestMappingHandlerMapping
.我不确定是否有一个更惯用的方法,它肯定觉得它跳过一些箍和挖掘到Spring内部有点太多。但至少在springweb5.2.7.release上,它似乎确实有效。