在项目开发过程中我们可能与这样的需求:需要拦截用户的特定浏览权限,比如对于一些公开页面不需要访问权限,对于一些特定的页面需要登录后才能访问。对于这个场景我们通常可以通过拦截器的方式来进行处理。
Spring MVC 的拦截器与 Java Servlet 的过滤器功能类型,它主要是对用户的请求进行处理,通常在权限验证,记录日志,用户登录状态判断等功能场景使用。
注: 基础环境 JDK 17 、Spring 6.x、Tomcat 10.x
拦截器的定义
通常我们可以通过实现 HandlerInterceptor 接口进行自定义拦截器的定义。
HandlerInterceptor
示例代码如下(注意我的 servlet 是 jakarta.servlet
):
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class TestInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行 System.out.println(" ======= >>>> afterCompletion 方法执行"); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行 System.out.println(" ======= >>>> postHandle 方法执行"); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // preHandle方法在控制器的处理请求方法调用之后,解析视图之前执行 System.out.println(" ======= >>>> preHandle 方法执行"); return false; } }
在上述拦截器的定义中实现了 HandlerInterceptor 接口,并实现了接口中的 3 个方法。有关这 3 个方法的描述如下。
- preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
- postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
- afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。
拦截器的配置
让自定义的拦截器生效需要在 Spring MVC 的配置文件中进行配置,配置示例代码如下:
XML 方式
<!-- 配置拦截器 --> <mvc:interceptors> <!-- 配置一个全局拦截器,拦截所有请求 --> <bean class="interceptor.TestInterceptor" /> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/**" /> <!-- 配置不需要拦截作用的路径 --> <mvc:exclude-mapping path="" /> <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 --> <bean class="interceptor.Interceptor1" /> </mvc:interceptor> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/gotoTest" /> <!-- 定义在<mvc: interceptor>元素中,表示匹配指定路径的请求才进行拦截 --> <bean class="interceptor.Interceptor2" /> </mvc:interceptor> </mvc:interceptors>
在上述示例代码中, <mvc:interceptors> 元素用于配置一组拦截器,其子元素 定义的是全局拦截器,即拦截所有的请求。 <mvc:interceptor> 元素中定义的是指定路径的拦截器,其子元素 <mvc:mapping> 用于配置拦截器作用的路径,该路径在其属性 path 中定义。如上述示例代码中,path 的属性值“/**”表示拦截所有路径,“/gotoTest”表示拦截所有以“/gotoTest”结尾的路径。如果在请求路径中包含不需要拦截的内容,可以通过 <mvc:exclude-mapping> 子元素进行配置。
需要注意的是,<mvc:interceptor> 元素的子元素必须按照 <mvc:mapping.../>、<mvc:exclude-mapping.../>、<bean.../> 的顺序配置。
注解方式
我们通过注解的方式配置如下:
/** * 注意:spring 6 中已经删除了 WebMvcConfigurerAdapter * 我们使用过程中实现 WebMvcConfigurer 接口即可 */ @Configuration public class TestConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new TestInterceptor()).addPathPatterns("/app/*"); } }