【SpringMVC笔记】 - 10 - 拦截器(Interceptor)

【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. 自定义拦截器(三步)

  1. 实现 HandlerInterceptor 接口
  2. 重写三个核心方法
  3. 交给 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)

前提条件
  1. 开启包扫描:<context:component-scan base-package="com.zzz"/>
  2. 拦截器添加 @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. 核心规则

  1. 只要任意一个拦截器 preHandle 返回 false所有 postHandle 都不执行
  2. 仅对该拦截器之前已执行 preHandle 的拦截器逆序执行 afterCompletion
  3. 控制器方法不会执行

2. 示例:Interceptor2.preHandle return false

执行顺序:

  1. Interceptor1.preHandle(true)
  2. Interceptor2.preHandle(false)→ 触发拦截
  3. 逆序执行已通过的拦截器 afterCompletion:Interceptor1.afterCompletion
  4. 后续所有流程终止

控制台输出:

复制代码
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(...);
    }
}

七、拦截器执行总结

  1. 执行顺序
    • preHandle:配置顺序 1→2→3
    • postHandle:逆序 3→2→1
    • afterCompletion:逆序 3→2→1
  2. 拦截规则
    • 一个 false → 所有 postHandle 不执行
    • 仅已通过 preHandle 的拦截器逆序执行 afterCompletion
    • 控制器方法不执行
  3. 适用场景
    • 登录 / 权限:preHandle
    • 日志 / 参数处理:preHandle + postHandle
    • 资源释放 / 异常记录:afterCompletion
相关推荐
one_love_zfl1 小时前
java面试-微服务篇
java·微服务·面试
郝学胜-神的一滴2 小时前
系统设计:新鲜事系统扩展与优化
java·python·职场和发展·php·软件工程·软件构建
爱吃烤鸡翅的酸菜鱼2 小时前
Maven中BOM(Bill of Materials)的使用详解
java·中间件·maven·源代码管理
XS0301062 小时前
Java 基础(七)多态
java·开发语言
wljt2 小时前
Spring boot学习笔记六:SpringBoot实用技术整合
spring boot·笔记·学习
不知名的老吴2 小时前
一文读懂:单例模式的经典案例分析
java·开发语言·单例模式
yaoxin5211232 小时前
388. Java IO API - 处理事件
java·服务器·数据库
JAVA学习通2 小时前
AI 工作流编排系统的任务拆分、重试与观测:2026年工程实践深度解析
java·人工智能·spring
凤山老林2 小时前
27-Java final 关键字
java·开发语言