这篇文章描述了Spring的HandlerInterceptor的定义,它与Java Servlet的HttpFilters的不同之处,以及HandlerInterceptor接口方法的概述以及如何在应用程序中配置它们。
在软件开发中,有很多情况下,您需要以某种方式捕获到服务器的请求并进行一些预处理或后处理。例如,当您需要验证是否在执行此路径之前授权用户访问特定路径时,必须进行身份验证。Spring作为Spring Web的一部分提供了一种使用SpringInterceptor对象的方法。它们允许在控制器处理处理程序之前或之后提供自定义逻辑。
什么是Spring HanlderInterceptor?
HandlerInterceptor是一个Spring Web接口,它允许实现组件以拦截客户端请求并提供自定义处理逻辑。这样的处理可以在Spring控制器处理请求之前或之后执行。处理程序拦截器实现org.springframework.web.servlet.HandlerInterceptor了提供三种核心方法的接口:
- boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler)
- void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mw)
- void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex)
开发人员可以注册任意数量的拦截器,以及将它们附加到特定的处理程序组并控制其顺序。此类功能将HandlerInterceptor与另一个工具HttpFilters关联。
创建HandlerInterceptor
如前所述,为了创建拦截器,开发人员必须实现HanlderInterceptor接口。由于其所有方法均为默认方法,因此您可以为所有方法或仅为所需方法提供实施。HanlderInterceptor通常用于实现基于令牌的身份验证。让我们看一下使用的基本情况HandlerInterceptor:
@Component |
在此代码段中,我们创建了一个自定义拦截器组件,以检查传入的请求是否确实附加了有效的身份验证令牌。请注意,与HttpFilters不同,HandlerInterceptor提供了对HttpServletRequest和HttpServletResponse组件的访问,因此您可以直接使用它们而无需从ServletRequestand 进行强制转换ServletResponse。
我们还将TokenInterceptor类注解为Spring的@Component,以使框架知道在基于注解的配置中以这种方式对其进行处理。
接口方式
接口提供了三种默认方法。本节概述了它们。
1. preHandle()
此方法拦截请求处理的执行。在控制器处理请求并返回布尔值(用于确定下一步处理)之前将其触发。如果方法返回truepreHandle(),则请求转到处理程序。如果返回错误,则请求被中断。此方法接受三个参数:
- HttpServletRequest 是当前的HTTP请求
- HttpServletResponse 是当前的HTTP响应
- Handler 是选择的处理程序对象来处理请求
如前所述,该方法可用于验证先决条件,例如令牌。我们还可以使用将信息传递给处理程序HttpServletRequest。看一下下面的代码片段:
@Override |
2.postHandle()
在 Spring控制器处理程序之后,但在呈现视图之前(如果您构建的是遵循MVC架构的应用程序),将触发此方法。因此,在这种情况下,您可以修改ModelAndView将要显示的内容并附加其他数据。此方法接受四个参数:
- HttpServletRequest 是当前的HTTP请求
- HttpServletResponse 是当前的HTTP响应
- Handler 是选择的处理程序对象来处理请求
- ModelAndView 是处理程序ModelAndView对象返回的。
作为使用这种方法的示例,我们可以提供一种情况,当我们想向用户显示用于渲染页面的时间时。为此,我们还需要首先使用捕获初始时间preHandle。看一下以下代码片段:
@Override |
3.afterCompletion()
最后,这里的第三个方法afterCompletion()是在处理程序处理完并向用户呈现视图之后调用。请注意,在处理程序执行的任何情况下都将调用此方法,但前提是相应的preHandle()方法返回true。它接受四个参数:
- HttpServletRequest 是当前的HTTP请求
- HttpServletResponse 是当前的HTTP响应
- Handler 是选择的处理程序对象来处理请求
- Exception是处理程序抛出的异常,除非,它是通过异常解析器处理的
我们可以使用这种方法来记录处理程序处理的结果,如以下代码所示:
// assume we have a logger |
配置
为了使用处理程序拦截器,我们需要使用自定义WebMvcConfigurer配置实例对其进行配置。下面的代码演示了令牌拦截器配置的基本用法:
@Configuration |
此代码将拦截器附加到所有处理程序。我们还用Spring注释了它,@Configuration以告诉框架它用于定义bean,并且Spring容器将在bean生成中使用。虽然,这是基本情况。我们还可以:
- 将拦截器附加到特定的路由/路由组
- 从特定路由/路由组中排除拦截器
- 定义拦截器执行的顺序
为此,我们需要处理InterceptorRegistration作为返回的对象addInterceptor()。
包含路径
要为特定路径或路由组附加拦截器,我们可以利用addPathPatterns()允许指定某些路径的方法。它有两个重载版本:
- addPathPatterns(List<String> patterns)以数组列表的形式接受一组模式
- addPathPatterns(String... patterns) 接受varagrs形式的模式
由于我们有令牌拦截器,因此我们希望将其应用于所有以开头的路由/secured/:
@Override |
排除路径
同样,我们可以从拦截器中排除一些路径。可以使用excludePathPatterns()method 来完成,它可以有两种形式:
- excludePathPatterns(List<String> patterns) 接受列表形式的模式
- excludePathPatterns(String... patterns) 接受模式作为varargs
比如我们要排除的路径/login,/signup并/restore-password从令牌验证(因为它们还没有任何安全):
@Override |
定义顺序
最后,如果我们使用多个HandlerInterceptor,我们可以指定它们的执行顺序。这是通过order()从InterceptorRegistration接受一个int数量的拦截器顺序(从0开始)的方法调用的。例如,我们有三个拦截器:一个用于验证令牌,第二个用于验证用户的订阅状态,最后记录:
@Configuration |