一、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) 調用。