在 SpringMVC 中,攔截器(Interceptor)和過濾器(Filter)都用于對請求進行預處理或后處理,但它們在所屬規(guī)范、作用范圍、執(zhí)行時機等方面有顯著區(qū)別,具體如下:
1. 所屬規(guī)范不同
- 過濾器(Filter):屬于Java EE Servlet 規(guī)范的一部分,是 Servlet 容器(如 Tomcat)層面的組件,不依賴于 Spring 框架,可在任何 Java Web 項目中使用。
- 攔截器(Interceptor):是SpringMVC 框架自身提供的組件,依賴于 Spring 容器,僅在 SpringMVC 項目中生效。
2. 實現接口不同
- 過濾器:需實現
javax.servlet.Filter接口,核心方法為doFilter(ServletRequest, ServletResponse, FilterChain)。 - 攔截器:需實現
org.springframework.web.servlet.HandlerInterceptor接口,核心方法為:preHandle:Controller 方法執(zhí)行前調用;postHandle:Controller 方法執(zhí)行后、視圖渲染前調用;afterCompletion:視圖渲染完成后調用。
3. 作用范圍不同
- 過濾器:可攔截所有請求(包括靜態(tài)資源如 CSS/JS、JSP、Servlet、非 SpringMVC 處理的請求等),只要在配置的
urlPatterns范圍內都會被攔截。 - 攔截器:僅攔截SpringMVC 處理的請求(即通過 DispatcherServlet 分發(fā)到 Controller 的請求),對靜態(tài)資源、非 SpringMVC 管理的 Servlet 等請求不生效(除非特殊配置)。
4. 執(zhí)行時機不同
- 過濾器:在請求進入 Servlet 容器后、Servlet(如 DispatcherServlet)處理前執(zhí)行,且在響應返回給客戶端前也可能執(zhí)行(通過 FilterChain 傳遞)。
- 攔截器:在 DispatcherServlet 處理請求的過程中執(zhí)行,具體階段由其三個方法決定:
preHandle:DispatcherServlet 調用 Controller 前;postHandle:Controller 執(zhí)行完但視圖未渲染前;afterCompletion:視圖渲染完成后。
5. 生命周期管理不同
- 過濾器:由 Servlet 容器(如 Tomcat)管理生命周期,隨容器啟動而初始化(
init方法),隨容器關閉而銷毀(destroy方法)。 - 攔截器:由 Spring 容器管理,屬于 Spring 的 Bean,可通過 Spring 的依賴注入(DI)獲取其他 Bean,參與 Spring 的生命周期(如初始化、銷毀回調)。
6. 配置方式不同
- 過濾器:
- 傳統(tǒng)方式:在
web.xml中配置<filter>和<filter-mapping>; - 注解方式:使用
@WebFilter注解,并通過 Servlet 容器掃描生效。
- 傳統(tǒng)方式:在
- 攔截器:需在 SpringMVC 配置類中通過
WebMvcConfigurer的addInterceptors方法注冊,例如:java運行@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/**") // 攔截路徑 .excludePathPatterns("/login"); // 排除路徑 } }
7. 可訪問的資源不同
- 過濾器:僅能訪問
ServletRequest和ServletResponse對象,無法直接獲取 SpringMVC 的內部組件(如 Controller 方法、ModelAndView 等)。 - 攔截器:可通過參數直接獲取
HandlerMethod(當前執(zhí)行的 Controller 方法)、ModelAndView等 SpringMVC 內部對象,能更精細地控制請求流程。
8. 典型應用場景
- 過濾器:常用于通用功能,如字符編碼設置(
CharacterEncodingFilter)、跨域處理(CorsFilter)、敏感詞過濾、請求日志記錄等。 - 攔截器:常用于與業(yè)務相關的功能,如登錄狀態(tài)驗證、權限校驗、Controller 方法執(zhí)行時間統(tǒng)計、事務管理等。
總結
過濾器是 Servlet 層面的 “全局攔截”,作用范圍更廣但功能較基礎;攔截器是 SpringMVC 層面的 “精細攔截”,依賴 Spring 容器,可深度集成業(yè)務邏輯。實際開發(fā)中,兩者可配合使用(如過濾器處理編碼,攔截器處理登錄驗證)。
分別給出SpringMVC攔截器和過濾器的代碼示例
已完成思考
下面分別給出 SpringMVC 攔截器和過濾器的代碼示例,結合實際場景(攔截器實現登錄驗證,過濾器實現請求日志記錄)進行說明。
一、過濾器(Filter)示例
場景:記錄所有請求的 URL、方法及執(zhí)行時間,基于 Servlet 規(guī)范實現。
1. 過濾器實現類
java
運行
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
// 注解方式配置過濾器:攔截所有請求(/*)
@WebFilter(urlPatterns = "/*", filterName = "logFilter")
public class LogFilter implements Filter {
// 過濾器初始化(容器啟動時執(zhí)行)
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LogFilter初始化...");
}
// 核心過濾邏輯
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 1. 預處理:記錄請求開始時間、URL、方法
HttpServletRequest httpRequest = (HttpServletRequest) request;
String url = httpRequest.getRequestURL().toString();
String method = httpRequest.getMethod();
long startTime = new Date().getTime();
System.out.println("====== 請求開始:" + method + " " + url + " ======");
// 2. 放行請求(繼續(xù)執(zhí)行后續(xù)過濾器或Servlet)
chain.doFilter(request, response); // 必須調用,否則請求會被攔截
// 3. 后處理:記錄請求結束時間和耗時
long endTime = new Date().getTime();
System.out.println("====== 請求結束:耗時 " + (endTime - startTime) + "ms ======\n");
}
// 過濾器銷毀(容器關閉時執(zhí)行)
@Override
public void destroy() {
System.out.println("LogFilter銷毀...");
}
}
2. 過濾器生效配置(Spring Boot 環(huán)境)
在 Spring Boot 啟動類上添加
@ServletComponentScan注解,開啟 Servlet 組件掃描(使@WebFilter生效):java
運行
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan // 掃描Servlet組件(Filter、Servlet、Listener)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
說明:傳統(tǒng) Web 項目可在
web.xml中配置過濾器,替代注解方式:xml
<filter>
<filter-name>logFilter</filter-name>
<filter-class>com.example.filter.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>logFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 攔截所有請求 -->
</filter-mapping>
二、攔截器(Interceptor)示例
場景:驗證用戶是否登錄(檢查 Session 中是否有用戶信息),未登錄則重定向到登錄頁,基于 SpringMVC 框架實現。
1. 攔截器實現類
java
運行
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
// Controller方法執(zhí)行前調用(核心攔截邏輯)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 1. 獲取Session
HttpSession session = request.getSession();
Object user = session.getAttribute("loginUser"); // 假設登錄后用戶信息存于Session的"loginUser"鍵
// 2. 驗證登錄狀態(tài)
if (user == null) {
// 未登錄:重定向到登錄頁
response.sendRedirect(request.getContextPath() + "/login");
return false; // 中斷請求,不再執(zhí)行后續(xù)Controller
} else {
// 已登錄:放行
return true; // 繼續(xù)執(zhí)行Controller方法
}
}
// Controller方法執(zhí)行后、視圖渲染前調用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 可在這里修改ModelAndView(如添加公共數據)
if (modelAndView != null) {
modelAndView.addObject("currentTime", System.currentTimeMillis());
}
}
// 視圖渲染完成后調用(通常用于資源清理)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
// 例如:記錄異常日志
if (ex != null) {
System.out.println("請求處理異常:" + ex.getMessage());
}
}
}
2. 攔截器注冊配置
通過 SpringMVC 配置類注冊攔截器,并指定攔截 / 排除路徑:
java
運行
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 WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注冊登錄攔截器
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 攔截所有路徑
.excludePathPatterns( // 排除不需要攔截的路徑(登錄頁、靜態(tài)資源等)
"/login",
"/doLogin", // 登錄提交接口
"/css/**",
"/js/**",
"/images/**"
);
}
}
關鍵區(qū)別體現
- 過濾器的
doFilter方法需要手動調用chain.doFilter放行,而攔截器通過preHandle的返回值(true/false)控制是否放行。 - 攔截器可直接操作
ModelAndView等 SpringMVC 內部對象(如postHandle方法),過濾器僅能訪問ServletRequest/ServletResponse。 - 過濾器攔截所有請求(包括靜態(tài)資源),攔截器僅攔截 SpringMVC 管理的請求(通過
DispatcherServlet的請求)
浙公網安備 33010602011771號