【SpringMVC笔记】 - 10 - 拦截器
一、拦截器概述
1. 拦截器是什么
SpringMVC 拦截器(Interceptor)是SpringMVC 框架提供的请求拦截组件 ,作用于请求进入控制器前后、视图渲染完成后,可对请求与响应做统一处理,功能类似 Web 过滤器(Filter),但作用层面与使用场景更聚焦。
2. 核心作用场景
- 登录验证:未登录用户拦截并跳转登录页
- 权限校验:按用户角色控制接口访问权限
- 请求日志:统一记录请求 URL、参数、耗时、异常
- 响应处理:统一添加响应头、封装返回格式
- 性能监控:统计接口执行时间
3. 拦截器 vs 过滤器(核心区别)
| 对比项 | 过滤器 Filter | 拦截器 Interceptor |
|---|---|---|
| 所属技术 | Servlet 规范 | SpringMVC 框架 |
| 拦截范围 | 所有请求(静态资源、Servlet、Controller) | 仅进入 SpringMVC 前端控制器的请求 |
| 执行时机 | 请求进入容器前、响应离开容器后 | 请求进入 Controller 前后、视图渲染后 |
| 核心能力 | 修改请求 / 响应、编码、请求头、状态码 | 控制器前置 / 后置处理、权限、日志 |
| 依赖容器 | 依赖 Servlet 容器 | 依赖 SpringMVC 容器 |
| 执行顺序 | 先执行 Filter,再执行 Interceptor | 后执行 Interceptor |
4. 整体执行顺序
Filter → Interceptor.preHandle → Controller → Interceptor.postHandle → 视图渲染 → Interceptor.afterCompletion → Filter
二、拦截器的创建与基本配置
1. 自定义拦截器(三步)
- 实现
HandlerInterceptor接口 - 重写三个核心方法
- 交给 Spring 管理(
@Component)
2. 三个核心方法
java
public interface HandlerInterceptor {
// 1. 控制器方法执行前调用(唯一有返回值)
// 返回 true:放行;返回 false:拦截
default boolean preHandle(...) throws Exception {
return true;
}
// 2. 控制器方法执行后、视图渲染前调用
default void postHandle(...) throws Exception {
}
// 3. 视图渲染完成后调用(无论是否异常都会执行)
default void afterCompletion(...) throws Exception {
}
}
3. 代码示例(Interceptor1/2/3)
java
@Component
public class Interceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(...) {
System.out.println("Interceptor1 -> preHandle");
return true;
}
@Override
public void postHandle(...) {
System.out.println("Interceptor1 -> postHandle");
}
@Override
public void afterCompletion(...) {
System.out.println("Interceptor1 -> afterCompletion");
}
}
说明:Interceptor2、Interceptor3 代码结构完全一致,仅打印标识不同。
4. 基本配置(springmvc.xml)
前提条件
- 开启包扫描:
<context:component-scan base-package="com.zzz"/> - 拦截器添加
@Component注解
配置方式(按注册顺序执行)
xml
<mvc:interceptors>
<!-- 按顺序注册拦截器:1 → 2 → 3 -->
<ref bean="interceptor1"/>
<ref bean="interceptor2"/>
<ref bean="interceptor3"/>
</mvc:interceptors>
注意:基本配置默认拦截所有请求。
三、多拦截器完整执行流程(全放行)
1. 执行顺序规则
- preHandle :按配置顺序执行(1→2→3)
- postHandle :按配置逆序执行(3→2→1)
- afterCompletion :按配置逆序执行(3→2→1)
2. 访问 /index 控制台输出
Interceptor1 -> preHandle
Interceptor2 -> preHandle
Interceptor3 -> preHandle
IndexController#toIndex() -->处理器方法执行了
Interceptor3 -> postHandle
Interceptor2 -> postHandle
Interceptor1 -> postHandle
Interceptor3 -> afterCompletion
Interceptor2 -> afterCompletion
Interceptor1 -> afterCompletion
四、拦截器拦截场景(preHandle 返回 false)
1. 核心规则
- 只要任意一个拦截器 preHandle 返回 false ,所有 postHandle 都不执行
- 仅对该拦截器之前已执行 preHandle 的拦截器 ,逆序执行 afterCompletion
- 控制器方法不会执行
2. 示例:Interceptor2.preHandle return false
执行顺序:
- Interceptor1.preHandle(true)
- Interceptor2.preHandle(false)→ 触发拦截
- 逆序执行已通过的拦截器 afterCompletion:Interceptor1.afterCompletion
- 后续所有流程终止
控制台输出:
Interceptor1 -> preHandle
Interceptor2 -> preHandle
Interceptor1 -> afterCompletion
五、拦截器高级配置(指定路径拦截 / 放行)
1. 配置语法
xml
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<!-- 放行指定请求 -->
<mvc:exclude-mapping path="/ok"/>
<!-- 绑定拦截器 -->
<ref bean="interceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
/index:被拦截/ok:直接放行,不经过该拦截器
2. 常用路径规则
/**:匹配所有路径(包含子路径)/user/*:匹配 /user/xxx 单层路径/user/**:匹配 /user 下所有路径
六、拦截器源码深度解析
1. 核心组件
DispatcherServlet:前端控制器,统一分发请求HandlerExecutionChain:处理器执行链,管理所有拦截器
2. DispatcherServlet#doDispatch 核心流程
java
protected void doDispatch(...) {
// 1. 顺序执行所有 preHandle
if (!mappedHandler.applyPreHandle(request, response)) {
return; // 拦截直接返回
}
// 2. 执行控制器方法
mv = ha.handle(...);
// 3. 逆序执行所有 postHandle
mappedHandler.applyPostHandle(...);
// 4. 渲染视图 + 逆序执行 afterCompletion
processDispatchResult(...);
}
3. HandlerExecutionChain 关键方法
(1)applyPreHandle(顺序执行 preHandle)
java'
boolean applyPreHandle(...) {
for (int i = 0; i < interceptorList.size(); i++) {
HandlerInterceptor interceptor = interceptorList.get(i);
if (!interceptor.preHandle(...)) {
// 拦截:逆序执行已通过的 afterCompletion
triggerAfterCompletion(...);
return false;
}
this.interceptorIndex = i; // 记录最后一个通过的拦截器下标
}
return true;
}
(2)applyPostHandle(逆序执行 postHandle)
java
void applyPostHandle(...) {
// 从后往前执行
for (int i = interceptorList.size() - 1; i >= 0; i--) {
interceptorList.get(i).postHandle(...);
}
}
(3)triggerAfterCompletion(逆序执行 afterCompletion)
java
void triggerAfterCompletion(...) {
// 仅执行到 interceptorIndex(最后一个通过的拦截器)
for (int i = this.interceptorIndex; i >= 0; i--) {
interceptorList.get(i).afterCompletion(...);
}
}
七、拦截器执行总结
- 执行顺序
- preHandle:配置顺序 1→2→3
- postHandle:逆序 3→2→1
- afterCompletion:逆序 3→2→1
- 拦截规则
- 一个 false → 所有 postHandle 不执行
- 仅已通过 preHandle 的拦截器逆序执行 afterCompletion
- 控制器方法不执行
- 适用场景
- 登录 / 权限:preHandle
- 日志 / 参数处理:preHandle + postHandle
- 资源释放 / 异常记录:afterCompletion