文章目录
过滤器和拦截器的区别详解
过滤器(Filter)和拦截器(Interceptor) 是 Web 开发中常用的工具,它们可以在请求处理流程中拦截请求或响应,用于完成某些通用功能或业务逻辑控制。尽管它们有很多相似之处,但本质上是两个完全不同的概念。以下是两者的详细区别及使用场景。
一、基本概念
1. 过滤器(Filter)
- 定义:过滤器是基于 Servlet 规范的,运行在 Servlet 容器中,作用于请求和响应的整个生命周期。
- 实现:实现 Java EE 的
javax.servlet.Filter
接口,必须在 Web 应用的部署描述文件(如web.xml
)中配置,或者通过注解配置。 - 功能:
- 请求预处理(例如请求参数校验、敏感词过滤)。
- 响应后处理(例如统一格式化响应数据、压缩响应内容)。
- 主要用于处理通用的、横切的功能。
2. 拦截器(Interceptor)
- 定义:拦截器是基于框架(如 Spring)的组件,运行在应用层,作用于业务方法的调用前后。
- 实现:实现
HandlerInterceptor
接口,并在 Spring 配置中声明。 - 功能:
- 拦截业务层方法调用(如权限校验、日志记录)。
- 更接近业务逻辑,可以操作 Spring 上下文中的 Bean 和其他资源。
二、核心区别
特性 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
来源 | 属于 Java EE Servlet 规范的一部分。 | 属于 Spring 框架的一部分。 |
触发时机 | 在请求进入 Servlet 之前和响应离开 Servlet 之后执行。 | 在控制器(Controller)方法调用的前后执行。 |
作用范围 | 针对所有资源(静态资源、动态资源),甚至包括 JSP 和 HTML。 | 仅针对 Spring MVC 的控制器方法(如 @RequestMapping )。 |
实现方式 | 实现 javax.servlet.Filter 接口。 | 实现 HandlerInterceptor 接口。 |
依赖容器 | 依赖于 Servlet 容器(如 Tomcat)。 | 依赖于 Spring 框架。 |
执行顺序 | 比拦截器先执行(更靠近底层)。 | 比过滤器后执行(更靠近业务逻辑)。 |
配置方式 | 配置在 web.xml 文件中或使用 @WebFilter 注解。 | 配置在 Spring 的配置类中,或使用 @Component 和 WebMvcConfigurer 。 |
应用场景 | 通用功能(如跨域、编码设置、数据压缩等)。 | 业务逻辑相关(如权限验证、登录校验、日志记录等)。 |
三、执行流程对比
请求从客户端到服务器的执行顺序为:
- 过滤器(Filter):处理所有请求。
- Servlet:核心业务逻辑处理。
- 拦截器(Interceptor):控制器方法调用前后拦截请求。
请求的处理流程通常为:
客户端请求 → 容器 → 过滤器 → Servlet → 拦截器 → 控制器(Controller)方法 → 响应
这种触发顺序使得过滤器更适合处理底层的通用逻辑,而拦截器更贴近业务逻辑。
四、具体实现
1. 过滤器的实现
基于函数回调机制,通过调用 FilterChain.doFilter()
来控制请求的继续执行。
使用 javax.servlet.Filter
接口开发过滤器,需要实现以下三个方法:
示例代码如下:
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
// 这里可以初始化一些还没被加载的配置等
System.out.println("过滤器初始化:init() 方法执行。");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器执行前逻辑:请求处理开始。");
chain.doFilter(request, response); // 放行请求,交给下一个过滤器或 Servlet。
System.out.println("过滤器执行后逻辑:响应处理结束。");
}
@Override
public void destroy() {
System.out.println("过滤器销毁:destroy() 方法执行。");
}
}
常用场景:
- 日志记录:记录每个请求的 IP、URL 等信息。
- 安全过滤:屏蔽不合法的请求。
- 设置编码:统一请求和响应的字符集编码。
- 数据压缩:对返回的数据进行 gzip 压缩。
2. 拦截器的实现
基于动态代理实现,通过 HandlerInterceptor
接口定义拦截逻辑。拦截器通常需要注册到 Spring 配置中,执行流程包括:
2.1. preHandle
方法
- 作用:请求方法执行前调用,用于处理请求前的逻辑。通常用于权限验证、日志记录、输入验证等。
- 返回值:必须返回
true
或false
,true
表示请求继续往下处理(进入下一个拦截器或目标方法),false
表示请求被拦截,后续的拦截器和目标方法不会被执行。
常见场景:
- 权限检查:检查用户是否已登录、是否有权限访问某个资源。
- 日志记录:记录请求的详细信息,比如请求参数、请求时间等。
2. 2. postHandle
方法
- 作用:请求处理后、视图渲染前调用。通常用于对目标方法返回的模型数据进行修改或增强,或者记录请求处理的时间等。
- 返回值:没有返回值,
ModelAndView
对象可以在该方法中被修改。
常见场景:
- 在响应返回之前,对视图数据进行修改。例如,向模型中添加额外的属性。
- 记录请求处理的时间,做一些后续的处理,日志记录等。
2.3. afterCompletion
方法
- 作用:请求处理完成后、视图渲染之后调用。通常用于资源的清理工作,比如释放数据库连接、记录请求处理的完成时间等。
- 返回值:没有返回值,可以用来处理异常的情况或做一些日志记录工作。
常见场景:
- 资源清理:例如关闭数据库连接、文件流等。
- 异常处理:可以用于记录异常信息或发送异常报告。
- 性能监控:记录请求的总处理时间,进行性能分析。
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("拦截器 preHandle:请求处理前执行。");
// 检查用户是否已登录
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect("/login"); // 如果未登录,重定向到登录页面
return false; // 拦截请求,不继续执行
}
return true; // 请求继续处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("拦截器 postHandle:请求处理后,但未渲染视图时执行。");
// 可以修改 ModelAndView,比如添加公共的属性到模型
if (modelAndView != null) {
modelAndView.addObject("footer", "Footer content");
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("afterCompletion:请求完全处理后,视图渲染后");
// 记录请求处理的时间
long startTime = (long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("请求处理时间:" + (endTime - startTime) + "ms");
// 如果有异常,可以记录或做进一步处理
if (ex != null) {
System.out.println("发生了异常:" + ex.getMessage());
}
}
}
配置拦截器:
将拦截器加入到 Spring 配置中:
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 {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/login", "/static/**"); // 排除特定路径
}
}
五、应用场景总结
过滤器适合场景
- 跨域处理(CORS)。
- URL 访问限制。
- 字符集设置。
- 日志记录。
- 数据压缩。
拦截器适合场景
- 用户身份验证。
- 权限控制。
- 请求统计。
- 业务逻辑预处理或后置操作。
- 系统日志记录(业务级别)。
六、总结
- 过滤器 面向底层,关注请求和响应的整体生命周期,适合处理通用功能。
- 拦截器 面向业务层,关注控制器方法的调用,适合处理业务逻辑相关功能。
- 两者各有侧重点,开发时需根据具体需求选择合适的工具来实现功能。
博客主页: 总是学不会.