在 SpringMVC 中,拦截器(Interceptor)和过滤器(Filter)都用于对请求进行预处理或后处理,但它们在所属规范、作用范围、执行时机等方面有显著区别,具体如下:
1. 所属规范不同
- 过滤器(Filter):属于Java EE Servlet 规范的一部分,是 Servlet 容器(如 Tomcat)层面的组件,不依赖于 Spring 框架,可在任何 Java Web 项目中使用。
- 拦截器(Interceptor):是SpringMVC 框架自身提供的组件,依赖于 Spring 容器,仅在 SpringMVC 项目中生效。
2. 实现接口不同
- 过滤器:需实现
javax.servlet.Filter接口,核心方法为doFilter(ServletRequest, ServletResponse, FilterChain)。 - 拦截器:需实现
org.springframework.web.servlet.HandlerInterceptor接口,核心方法为:preHandle:Controller 方法执行前调用;postHandle:Controller 方法执行后、视图渲染前调用;afterCompletion:视图渲染完成后调用。
3. 作用范围不同
- 过滤器:可拦截所有请求(包括静态资源如 CSS/JS、JSP、Servlet、非 SpringMVC 处理的请求等),只要在配置的
urlPatterns范围内都会被拦截。 - 拦截器:仅拦截SpringMVC 处理的请求(即通过 DispatcherServlet 分发到 Controller 的请求),对静态资源、非 SpringMVC 管理的 Servlet 等请求不生效(除非特殊配置)。
4. 执行时机不同
- 过滤器:在请求进入 Servlet 容器后、Servlet(如 DispatcherServlet)处理前执行,且在响应返回给客户端前也可能执行(通过 FilterChain 传递)。
- 拦截器:在 DispatcherServlet 处理请求的过程中执行,具体阶段由其三个方法决定:
preHandle:DispatcherServlet 调用 Controller 前;postHandle:Controller 执行完但视图未渲染前;afterCompletion:视图渲染完成后。
5. 生命周期管理不同
- 过滤器:由 Servlet 容器(如 Tomcat)管理生命周期,随容器启动而初始化(
init方法),随容器关闭而销毁(destroy方法)。 - 拦截器:由 Spring 容器管理,属于 Spring 的 Bean,可通过 Spring 的依赖注入(DI)获取其他 Bean,参与 Spring 的生命周期(如初始化、销毁回调)。
6. 配置方式不同
- 过滤器:
- 传统方式:在
web.xml中配置<filter>和<filter-mapping>; - 注解方式:使用
@WebFilter注解,并通过 Servlet 容器扫描生效。
- 传统方式:在
- 拦截器:需在 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(当前执行的 Controller 方法)、ModelAndView等 SpringMVC 内部对象,能更精细地控制请求流程。
8. 典型应用场景
- 过滤器:常用于通用功能,如字符编码设置(
CharacterEncodingFilter)、跨域处理(CorsFilter)、敏感词过滤、请求日志记录等。 - 拦截器:常用于与业务相关的功能,如登录状态验证、权限校验、Controller 方法执行时间统计、事务管理等。
总结
过滤器是 Servlet 层面的 “全局拦截”,作用范围更广但功能较基础;拦截器是 SpringMVC 层面的 “精细拦截”,依赖 Spring 容器,可深度集成业务逻辑。实际开发中,两者可配合使用(如过滤器处理编码,拦截器处理登录验证)。
分别给出SpringMVC拦截器和过滤器的代码示例
已完成思考
下面分别给出 SpringMVC 拦截器和过滤器的代码示例,结合实际场景(拦截器实现登录验证,过滤器实现请求日志记录)进行说明。
一、过滤器(Filter)示例
场景:记录所有请求的 URL、方法及执行时间,基于 Servlet 规范实现。
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 {
// 过滤器初始化(容器启动时执行)
@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. 放行请求(继续执行后续过滤器或Servlet)
chain.doFilter(request, response); // 必须调用,否则请求会被拦截
// 3. 后处理:记录请求结束时间和耗时
long endTime = new Date().getTime();
System.out.println("====== 请求结束:耗时 " + (endTime - startTime) + "ms ======\n");
}
// 过滤器销毁(容器关闭时执行)
@Override
public void destroy() {
System.out.println("LogFilter销毁...");
}
}
2. 过滤器生效配置(Spring Boot 环境)
在 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);
}
}
说明:传统 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方法执行前调用(核心拦截逻辑)
@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. 验证登录状态
if (user == null) {
// 未登录:重定向到登录页
response.sendRedirect(request.getContextPath() + "/login");
return false; // 中断请求,不再执行后续Controller
} else {
// 已登录:放行
return true; // 继续执行Controller方法
}
}
// Controller方法执行后、视图渲染前调用
@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( // 排除不需要拦截的路径(登录页、静态资源等)
"/login",
"/doLogin", // 登录提交接口
"/css/**",
"/js/**",
"/images/**"
);
}
}
关键区别体现
- 过滤器的
doFilter方法需要手动调用chain.doFilter放行,而拦截器通过preHandle的返回值(true/false)控制是否放行。 - 拦截器可直接操作
ModelAndView等 SpringMVC 内部对象(如postHandle方法),过滤器仅能访问ServletRequest/ServletResponse。 - 过滤器拦截所有请求(包括静态资源),拦截器仅拦截 SpringMVC 管理的请求(通过
DispatcherServlet的请求)
浙公网安备 33010602011771号