springMVC04-Filter过滤器与拦截器

一、Filter(过滤器)和 Interceptor(拦截器)

在 SpringMVC 中,Filter(过滤器)和 Interceptor(拦截器)都是对请求和响应进行预处理和后处理的重要工具,但它们存在本质区别,属于不同层面的机制:


1-1、Filter(过滤器)

  • 属于 Servlet 规范的一部分

  • 和 Spring 无关,作用于整个 Web 应用(包括静态资源、Servlet、SpringMVC 控制器等)

  • 是在 SpringMVC 前进行处理的。

1、使用场景:

  • 编码处理(如统一设置 request 编码)

  • 权限校验、登录验证(不依赖 Spring Bean)

  • 请求日志记录

  • XSS 防护、跨域设置

2、编写方式:

java 复制代码
@WebFilter(urlPatterns = "/*")  // 或在 web.xml 中配置
public class MyFilter implements Filter {
    @Override
    public 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 接口:
java 复制代码
public class MyInterceptor implements HandlerInterceptor {
    // 请求前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("Interceptor: 控制器前");
        return true; // false 则中断执行
    }

    // 控制器执行后,视图渲染前
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor: 控制器后");
    }

    // 完全结束后(包括视图渲染)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("Interceptor: 完成后");
    }
}
(2). 注册拦截器(Java 配置方式):
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/static/**");
    }
}

3、特点总结:

  • 生命周期由 Spring 管理,可注入 Bean

  • 只拦截 Controller 请求,静态资源不会被拦截

  • 更适合业务层逻辑(如认证授权、日志记录等)


1-3、两者对比总结:

对比项 Filter Interceptor
所属规范 Servlet 规范 Spring 框架
拦截范围 所有请求(静态资源、Servlet) 只拦截 SpringMVC 控制器请求
执行时机 DispatcherServlet 之前 DispatcherServlet 之后
配置方式 @WebFilterweb.xml 实现 HandlerInterceptor 接口
注入 Spring Bean
控制执行流程 不能直接终止控制器方法执行 可以通过 preHandle 控制是否继续

1-4、实际建议:

  • Filter: 用于与 Spring 无关的通用功能(如编码、日志、跨域等)

  • Interceptor: 用于控制器相关的逻辑(如登录校验、权限控制)

如果你只是处理 SpringMVC 控制器请求,推荐使用 Interceptor,它更灵活、易于与 Spring 的其他功能结合使用。


二、拦截器的执行流程图

浏览器请求在 SpringMVC 中的执行顺序:

java 复制代码
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. 响应返回给浏览器
阶段 处理组件 方法 说明
1 Filter doFilter(request, response) 最先执行的组件(如编码设置、日志)
2 DispatcherServlet doDispatch() SpringMVC 核心分发器
3 Interceptor preHandle() 在 Controller 前执行,可中断流程
4 Controller 处理请求的方法(比如 @GetMapping 执行业务逻辑
5 Interceptor postHandle() Controller 执行后,视图渲染前
6 视图解析 渲染返回的页面或 JSON 渲染 View、封装 Model
7 Interceptor afterCompletion() 整个请求执行完,做资源清理、异常处理等
8 Filter doFilter 后段 Filter 的"响应后"逻辑
9 浏览器 展示响应结果 最终结果返回给用户

三、拦截器的配置

SpringMVC中的拦截器用于拦截控制器方法的执行

SpringMVC中的拦截器需要实现HandlerInterceptor接口;或者继承HandlerInterceptorAdapter类(已过时)

SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:

3-1、步骤一:编写一个类,实现handerInterceptor接口

java 复制代码
public class MyInterceptor implements HandlerInterceptor {
    // 前置处理(Controller方法调用前)
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("前置处理:preHandle");
        return true; // 返回true才会继续调用后面的拦截器或Controller
    }

    // 后置处理(Controller方法调用后,但视图未渲染前)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("后置处理:postHandle");
    }

    // 完成后处理(视图渲染后,一般用于资源清理)
    @Override
    public 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

XML 复制代码
    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <bean class="com.wsbazinga.controller.MyInterceptorController"></bean>
    </mvc:interceptors>

页面返回值:

2、配置方式二:ref

XML 复制代码
    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!--<bean class="com.wsbazinga.controller.MyInterceptor"></bean>-->
        <ref bean="myInterceptor"></ref>
    </mvc:interceptors>

【注意】:

此时,拦截器类:MyInterceptor,要加上@Component注解,才能被IOC容器注入,并配置在ref中!


【注意】:

方式一,方式二,所有的请求都会被拦截!

3、配置方式三:可以指定拦截

XML 复制代码
<!-- 配置拦截器 -->
<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 常用)

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 WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
            .addPathPatterns("/**")                // 拦截所有请求
            .excludePathPatterns("/login", "/css/**", "/js/**"); // 放行登录、静态资源
    }
}

四、多个拦截器的执行顺序

在 SpringMVC 中使用 多个拦截器 时,它们的执行顺序由你在配置时的注册顺序决定,就像"拦截器栈"。

4-1、多个拦截器的preHandle()都返回true

假设你注册了两个拦截器:

java 复制代码
@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(倒序)

示例:假设两个拦截器打印日志

java 复制代码
public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(...) {
        System.out.println("First - preHandle");
        return true;
    }

    @Override
    public void postHandle(...) {
        System.out.println("First - postHandle");
    }

    @Override
    public void afterCompletion(...) {
        System.out.println("First - afterCompletion");
    }
}

public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(...) {
        System.out.println("Second - preHandle");
        return true;
    }

    @Override
    public void postHandle(...) {
        System.out.println("Second - postHandle");
    }

    @Override
    public void afterCompletion(...) {
        System.out.println("Second - afterCompletion");
    }
}

输出结果将是:

java 复制代码
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 个拦截器,顺序如下:

java 复制代码
registry.addInterceptor(new Interceptor1());
registry.addInterceptor(new Interceptor2());
registry.addInterceptor(new Interceptor3());

拦截器2 的 preHandle() 返回 false

java 复制代码
public class Interceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(...) {
        System.out.println("Interceptor2 - preHandle");
        return false; // 拦截住!
    }

    @Override
    public void afterCompletion(...) {
        System.out.println("Interceptor2 - afterCompletion");
    }
}

打印结果将是:

java 复制代码
Interceptor1 - preHandle
Interceptor2 - preHandle  (返回 false,终止)
Interceptor1 - afterCompletion

注意:

  • Interceptor3 的任何方法都不会执行!

  • postHandle() 都不会执行!因为 Controller 都没进去!

  • afterCompletion() 只对 已成功通过的拦截器(即 preHandle() 返回 true) 调用。

相关推荐
ruleslol1 天前
springMVC06-注解+配置类实现springMVC
springmvc
ruleslol4 天前
springMVC01-特点、创建项目、@RequestMapping、获取参数请求,三种域对象
springmvc
ruleslol5 天前
springMVC02-视图解析器、RESTful设计风格,静态资源访问配置
springmvc
endswel7 天前
Spring MVC HandlerInterceptor 拦截请求及响应体
springmvc·springboot
sniper_fandc10 天前
SpringMVC详解
java·springmvc
保持学习ing21 天前
SpringBoot电脑商城项目--创建订单+统计业务方法耗时
java·spring boot·spring·springmvc·jquery
编程大全1 个月前
47道SpringMVC高频题整理(附答案背诵版)
springmvc·面试题
周星星日记1 个月前
1.springmvc基础入门(一)
spring·springmvc
abcnull2 个月前
springboot中过滤器配置使用
java·spring boot·后端·springmvc·过滤器