Spring MVC 拦截器与过滤器的区别
拦截器和过滤器都是请求处理链中的重要组件,但它们属于不同框架,作用范围和使用场景各不相同。
基本定义
| 组件 | 所属框架 | 实现接口 |
|---|---|---|
| 过滤器 | Servlet容器 | javax.servlet.Filter |
| 拦截器 | Spring MVC | org.springframework.web.servlet.HandlerInterceptor |
核心区别对比
| 对比项 | 过滤器 | 拦截器 |
|---|---|---|
| 所属框架 | Servlet容器(Tomcat等) | Spring MVC |
| 依赖Spring | 否 | 是 |
| 作用范围 | 所有请求(含静态资源) | 仅Controller请求 |
| 执行时机 | Servlet前后 | Controller前后 |
| 获取Handler信息 | 不能 | 能 |
| 访问Spring Bean | 需要额外配置 | 可直接注入 |
| 多个组件执行顺序 | 按注册顺序 | preHandle顺序,其他逆序 |
执行流程对比
Java
HTTP请求
↓
Filter1.doFilter() ─→ Filter2.doFilter() ─→ Filter3.doFilter()
↓ ↓
DispatcherServlet 请求继续传递
↓
Interceptor1.preHandle() → Interceptor2.preHandle()
↓
Controller处理
↓
Interceptor2.postHandle() → Interceptor1.postHandle()
↓
View渲染
↓
Interceptor2.afterCompletion() → Interceptor1.afterCompletion()
↓
Filter3响应处理 ← Filter2响应处理 ← Filter1响应处理
↓
HTTP响应
过滤器实现
Java
@Component
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化逻辑
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
log.info("过滤器 - 请求开始: {} {}", req.getMethod(), req.getRequestURI());
// 前置处理
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
// 继续执行后续过滤器或Servlet
chain.doFilter(request, response);
// 后置处理
long duration = System.currentTimeMillis() - startTime;
log.info("过滤器 - 请求完成: {} {}, 耗时: {}ms, 状态: {}",
req.getMethod(), req.getRequestURI(), duration, res.getStatus());
}
@Override
public void destroy() {
// 清理逻辑
}
}
拦截器实现
Java
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("拦截器 - preHandle: {} {}", request.getMethod(), request.getRequestURI());
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
log.info("拦截器 - postHandle: {}", request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
long duration = System.currentTimeMillis()
- (Long) request.getAttribute("startTime");
log.info("拦截器 - afterCompletion: {} {}, 耗时: {}ms",
request.getMethod(), request.getRequestURI(), duration);
}
}
过滤器注册方式
方式一:@WebFilter注解
Java
@WebFilter(urlPatterns = "/*", filterName = "loggingFilter")
@Component
public class LoggingFilter implements Filter {
// ...
}
方式二:FilterRegistrationBean
Java
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() {
FilterRegistrationBean<LoggingFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new LoggingFilter());
registration.addUrlPatterns("/*");
registration.setName("loggingFilter");
registration.setOrder(1); // 顺序控制
return registration;
}
}
使用场景选择
| 场景 | 推荐组件 | 原因 |
|---|---|---|
| 登录验证 | 拦截器 | 只需拦截Controller,可获取Handler信息 |
| 权限控制 | 拦截器 | 需要Spring Bean,获取Controller信息 |
| 日志记录 | 拦截器或过滤器 | 根据是否需要Handler信息决定 |
| 跨域处理 | 过滤器 | 需处理所有请求(含静态资源) |
| 编码设置 | 过滤器 | 需处理所有请求 |
| XSS防护 | 过滤器 | 需处理所有请求参数 |
| 静态资源处理 | 过滤器 | 拦截器不拦截静态资源 |
| 性能监控 | 拦截器 | 只关注Controller响应时间 |
典型应用示例
过滤器:跨域处理
Java
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equalsIgnoreCase(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, response);
}
}
拦截器:权限控制
text
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
private PermissionService permissionService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取方法上的权限注解
RequirePermission annotation =
handlerMethod.getMethodAnnotation(RequirePermission.class);
if (annotation != null) {
User user = UserContext.getUser();
if (!permissionService.hasPermission(user, annotation.value())) {
response.setStatus(403);
response.getWriter().write("{\"code\":403,\"message\":\"无权限\"}");
return false;
}
}
}
return true;
}
}
拦截器优势
- 可获取Handler信息:能获取Controller类、方法、参数等
- 直接访问Spring Bean:可注入Service等组件
- 更精确的拦截范围:只拦截Controller,不拦截静态资源
- postHandle能力:可在Controller执行后修改响应
过滤器优势
- 不依赖Spring:可在Spring容器初始化前执行
- 拦截范围广:可拦截所有请求(含静态资源)
- 容器级控制:适合底层通用处理
- 执行时机早:在DispatcherServlet之前执行
要点总结
- 过滤器属于Servlet容器,拦截器属于Spring MVC
- 过滤器拦截所有请求,拦截器只拦截Controller
- 过滤器不能获取Handler信息,拦截器可以
- 登录验证、权限控制推荐用拦截器
- 跨域、编码、安全防护推荐用过滤器
- 可同时使用两者处理不同层次的逻辑
📝 发现内容有误?点击此处直接编辑