ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

springMVC04-Filter过滤器与拦截器

springMVC04-Filter过滤器与拦截器

一、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、两者对比总结:

对比项FilterInterceptor
所属规范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. 响应返回给浏览器
阶段处理组件方法说明
1FilterdoFilter(request, response)最先执行的组件(如编码设置、日志)
2DispatcherServletdoDispatch()SpringMVC 核心分发器
3InterceptorpreHandle()在 Controller 前执行,可中断流程
4Controller处理请求的方法(比如 @GetMapping)执行业务逻辑
5InterceptorpostHandle()Controller 执行后,视图渲染前
6视图解析渲染返回的页面或 JSON渲染 View、封装 Model
7InterceptorafterCompletion()整个请求执行完,做资源清理、异常处理等
8FilterdoFilter 后段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) 调用。

返回列表