小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与「掘力星计划>」,赢取创作大礼包,挑战创作激励金。
在项目开发过程中我们可能与这样的需求:需要拦截用户的特定浏览权限,比如对于一些公开页面不需要访问权限,对于一些特定的页面需要登录后才能访问。对于这个场景我们通常可以通过拦截器的方式来进行处理。
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/*");
}
}