一、Filter
(过滤器)和 Interceptor
(拦截器)
在 SpringMVC 中,Filter
(过滤器)和 Interceptor
(拦截器)都是对请求和响应进行预处理和后处理的重要工具,但它们存在本质区别,属于不同层面的机制:
1-1、Filter(过滤器)
属于 Servlet 规范的一部分
和 Spring 无关,作用于整个 Web 应用(包括静态资源、Servlet、SpringMVC 控制器等)
是在 SpringMVC 前进行处理的。
1、使用场景:
编码处理(如统一设置 request 编码)
权限校验、登录验证(不依赖 Spring Bean)
请求日志记录
XSS 防护、跨域设置
2、编写方式:
@WebFilter(urlPatterns = "/*") // 或在 web.xml 中配置
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("Filter: 请求前...");chain.doFilter(request, response); // 放行System.out.println("Filter: 响应后...");}
}
3、特点总结:
生命周期由 Servlet 容器管理
在 DispatcherServlet(SpringMVC 核心)之前执行
无法使用 Spring 的依赖注入(因为不是 Spring Bean)
1-2、Interceptor(拦截器)
是 SpringMVC 提供的机制
只会拦截进入 DispatcherServlet 的请求(也就是经过 SpringMVC 控制器的)
属于 Spring 容器管理,可以使用依赖注入
1、使用场景:
控制器权限校验(如登录检查)
日志记录、性能分析
国际化、视图数据填充
API 接口签名校验等
2、编写方式:
(1). 实现 HandlerInterceptor 接口:
public class MyInterceptor implements HandlerInterceptor {// 请求前@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("Interceptor: 控制器前");return true; // false 则中断执行}// 控制器执行后,视图渲染前@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception {System.out.println("Interceptor: 控制器后");}// 完全结束后(包括视图渲染)@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) throws Exception {System.out.println("Interceptor: 完成后");}
}
(2). 注册拦截器(Java 配置方式):
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/static/**");}
}
3、特点总结:
生命周期由 Spring 管理,可注入 Bean
只拦截 Controller 请求,静态资源不会被拦截
更适合业务层逻辑(如认证授权、日志记录等)
1-3、两者对比总结:
对比项 | Filter | Interceptor |
---|---|---|
所属规范 | Servlet 规范 | Spring 框架 |
拦截范围 | 所有请求(静态资源、Servlet) | 只拦截 SpringMVC 控制器请求 |
执行时机 | DispatcherServlet 之前 | DispatcherServlet 之后 |
配置方式 | @WebFilter 或 web.xml | 实现 HandlerInterceptor 接口 |
注入 Spring Bean | 否 | 是 |
控制执行流程 | 不能直接终止控制器方法执行 | 可以通过 preHandle 控制是否继续 |
1-4、实际建议:
Filter: 用于与 Spring 无关的通用功能(如编码、日志、跨域等)
Interceptor: 用于控制器相关的逻辑(如登录校验、权限控制)
如果你只是处理 SpringMVC 控制器请求,推荐使用 Interceptor,它更灵活、易于与 Spring 的其他功能结合使用。
二、拦截器的执行流程图
浏览器请求在 SpringMVC 中的执行顺序:
1. 浏览器发送请求(HTTP 请求)
↓
2. Filter.doFilter()(过滤器处理)
↓
3. DispatcherServlet.doDispatch()↓3.1 调用 HandlerInterceptor.preHandle()(前置拦截器)↓
4. Controller 方法执行(处理业务逻辑)
↓
5. HandlerInterceptor.postHandle()(后置拦截器:控制器执行后,视图渲染前)
↓
6. 视图解析与渲染(如返回 Thymeleaf、JSP、JSON 等)
↓
7. HandlerInterceptor.afterCompletion()(请求完成后,清理资源)
↓
8. Filter.doFilter() 后处理部分继续执行(回到过滤器的“响应后”部分)
↓
9. 响应返回给浏览器
阶段 | 处理组件 | 方法 | 说明 |
---|---|---|---|
1 | Filter | doFilter(request, response) | 最先执行的组件(如编码设置、日志) |
2 | DispatcherServlet | doDispatch() | SpringMVC 核心分发器 |
3 | Interceptor | preHandle() | 在 Controller 前执行,可中断流程 |
4 | Controller | 处理请求的方法(比如 @GetMapping ) | 执行业务逻辑 |
5 | Interceptor | postHandle() | Controller 执行后,视图渲染前 |
6 | 视图解析 | 渲染返回的页面或 JSON | 渲染 View、封装 Model |
7 | Interceptor | afterCompletion() | 整个请求执行完,做资源清理、异常处理等 |
8 | Filter | doFilter 后段 | Filter 的“响应后”逻辑 |
9 | 浏览器 | 展示响应结果 | 最终结果返回给用户 |
三、拦截器的配置
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor接口;或者继承HandlerInterceptorAdapter类(已过时)
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
3-1、步骤一:编写一个类,实现handerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {// 前置处理(Controller方法调用前)@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("前置处理:preHandle");return true; // 返回true才会继续调用后面的拦截器或Controller}// 后置处理(Controller方法调用后,但视图未渲染前)@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception {System.out.println("后置处理:postHandle");}// 完成后处理(视图渲染后,一般用于资源清理)@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) throws Exception {System.out.println("最终处理:afterCompletion");}
}
重写里面的三个方法:
- preHandle
- postHandle
- afterCompletion(渲染视图之后)
3-2、在springMVC.xml中配置拦截器
1、配置方式一:bean
<!-- 配置拦截器 --><mvc:interceptors><bean class="com.wsbazinga.controller.MyInterceptorController"></bean></mvc:interceptors>
页面返回值:
2、配置方式二:ref
<!-- 配置拦截器 --><mvc:interceptors><!--<bean class="com.wsbazinga.controller.MyInterceptor"></bean>--><ref bean="myInterceptor"></ref></mvc:interceptors>
【注意】:
此时,拦截器类:MyInterceptor,要加上@Component注解,才能被IOC容器注入,并配置在ref中!
【注意】:
方式一,方式二,所有的请求都会被拦截!
3、配置方式三:可以指定拦截
<!-- 配置拦截器 -->
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/> <!-- 拦截所有路径 --><mvc:exclude-mapping path="/login"/> <!-- 排除拦截的url --><bean class="com.example.interceptor.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>
【注意】:
拦截器和过滤器不同,拦截所有请求用的是:/**,而不是/*!
4、使用 Java 配置类(推荐,Spring Boot/Spring 5 常用)
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/login", "/css/**", "/js/**"); // 放行登录、静态资源}
}
四、多个拦截器的执行顺序
在 SpringMVC 中使用 多个拦截器 时,它们的执行顺序由你在配置时的注册顺序决定,就像“拦截器栈”。
4-1、多个拦截器的preHandle()都返回true
假设你注册了两个拦截器:
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");registry.addInterceptor(new SecondInterceptor()).addPathPatterns("/**");
}
那么执行顺序是:
方法名 | 执行顺序 |
---|---|
preHandle() | 先注册的先执行:First → Second(顺序) |
postHandle() | 先注册的后执行:Second → First(倒序) |
afterCompletion() | 先注册的后执行:Second → First(倒序) |
示例:假设两个拦截器打印日志
public class FirstInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(...) {System.out.println("First - preHandle");return true;}@Overridepublic void postHandle(...) {System.out.println("First - postHandle");}@Overridepublic void afterCompletion(...) {System.out.println("First - afterCompletion");}
}public class SecondInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(...) {System.out.println("Second - preHandle");return true;}@Overridepublic void postHandle(...) {System.out.println("Second - postHandle");}@Overridepublic void afterCompletion(...) {System.out.println("Second - afterCompletion");}
}
输出结果将是:
First - preHandle
Second - preHandle
Second - postHandle
First - postHandle
Second - afterCompletion
First - afterCompletion
总结:
方法 | 顺序说明 |
---|---|
preHandle() | 注册顺序执行(1 → 2 → 3) |
postHandle() | 注册反向顺序(3 → 2 → 1) |
afterCompletion() | 注册反向顺序(3 → 2 → 1) |
如果中断请求 | 后续 preHandle() 不执行,已执行的 afterCompletion() 执行 |
4-2、多个拦截器中,有一个拦截器的 preHandle()
返回了 false
1、后续拦截器的 preHandle()
不会再执行
拦截链中断,SpringMVC 不会再往下调用后面的拦截器或 Controller 方法。
2、Controller 方法 不会被执行
SpringMVC 直接终止请求流程,不会进入控制器。
3、已成功通过的拦截器(即 preHandle()
返回 true)的afterCompletion()
仍然会执行
SpringMVC 会把之前已经通过的拦截器的
afterCompletion()
方法 按反顺序执行,用于清理资源。
示例:
假设我们注册了 3 个拦截器,顺序如下:
registry.addInterceptor(new Interceptor1());
registry.addInterceptor(new Interceptor2());
registry.addInterceptor(new Interceptor3());
拦截器2 的 preHandle()
返回 false
:
public class Interceptor2 implements HandlerInterceptor {@Overridepublic boolean preHandle(...) {System.out.println("Interceptor2 - preHandle");return false; // 拦截住!}@Overridepublic void afterCompletion(...) {System.out.println("Interceptor2 - afterCompletion");}
}
打印结果将是:
Interceptor1 - preHandle
Interceptor2 - preHandle (返回 false,终止)
Interceptor1 - afterCompletion
注意:
Interceptor3
的任何方法都不会执行!postHandle()
都不会执行!因为 Controller 都没进去!afterCompletion()
只对 已成功通过的拦截器(即preHandle()
返回 true) 调用。