一、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 之后
配置方式@WebFilterweb.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) 调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88296.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88296.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/88296.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32第十九天 ESP8266-01S和电脑实现串口通信(2)

1&#xff1a;UDP 传输UDP 传输不不区分 server 或者 client &#xff0c;由指令 ATCIPSTART 建⽴立传输。 1. 配置 WiFi 模式 ATCWMODE3 // softAPstation mode 响应 : OK 2. 连接路路由器器 ATCWJAP"SSID","password" // SSID and password of router 响…

大健康IP如何用合规运营打破“信任危机”|创客匠人

一、行业乱象下的信任裂痕当前大健康领域私域直播乱象频发&#xff0c;部分机构利用“假专家义诊”“限量抢购”等话术&#xff0c;将低成本保健品高价卖给老人&#xff0c;甚至有技术公司提供“全链路坑老方案”&#xff0c;加剧行业信任危机。这种短视行为不仅损害消费者权益…

MySQL(122)如何解决慢查询问题?

解决慢查询问题通常涉及到多种技术和方法&#xff0c;以确保数据库查询的高效性和响应速度。以下是详细步骤和示例代码&#xff0c;阐述如何解决慢查询问题。 一. 慢查询的常见原因 缺少索引&#xff1a;查询未使用索引或索引未优化。查询不当&#xff1a;查询语句本身书写不合…

esp32在vscode中仿真调试

此方法可以用在具有usb serial jtag功能的esp32芯片用&#xff0c;支持型号&#xff1a; ESP32-C3 ESP32-S3 ESP32-C6 ESP32-H2 ESP32-C5 USB Serial JTAG功能介绍&#xff1a; 从硬件角度&#xff1a; 它是ESP32芯片内置的硬件功能 不是一个独立的物理接口 是通过USB接口实…

蓝桥云课 矩形切割-Java

目录 题目链接 题目 解题思路 代码 题目链接 竞赛中心 - 蓝桥云课 题目 解题思路 找最大的正方形就是大边-n个小边&#xff0c;直至相等或者小于1 代码 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static voi…

PostgreSQL 锁等待监控,查找等待中的锁

直接贴SQLWITH RECURSIVE l AS (SELECT pid, locktype, mode, granted, ROW(locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid) objFROM pg_locks ), pairs AS (SELECT w.pid waiter, l.pid locker, l.obj, l.modeFROM l wJOIN l ON l.…

Elasticsearch 字符串包含子字符串:高级查询技巧

作者&#xff1a;来自 Elastic Justin Castilla 想要获得 Elastic 认证&#xff1f;看看下一次 Elasticsearch Engineer 培训什么时候开始吧&#xff01; Elasticsearch 拥有大量新功能&#xff0c;可以帮助你为你的使用场景构建最佳的搜索解决方案。深入了解我们的示例 noteb…

Vue、Laravel 项目初始化命令对比 / curl 命令/ CORS 机制总结与案例

前言一个疑问衍生出另一个疑问再衍生出又一个疑问&#xff0c;于是有了这篇文章。一、Vue 项目初始化命令 基于 Vite 创建 Vue 项目 命令&#xff1a;npm create vitelatest my-project -- --template vue适用场景&#xff1a;需轻量级、高速开发环境关键点&#xff1a;使用 Vi…

Jenkins 流水线配置

Jenkinsfile dsl文件:pipeline {// 指定任务在哪个集群节点执行agent any// 声明全局变量environment {keyvalueAPPLICATION_NAMEspringboot-demo // 项目名称HOST_PORT7777 // 宿主机暴露服务端口CONTAINER_PORT8080 // 容器内部服务端口…

服务器重装后如何“复活”旧硬盘上的 Anaconda 环境?—— 一次完整的排错与恢复记录

目录 摘要 一、 背景&#xff1a;熟悉的陌生人 二、 问题浮现&#xff1a;一次次失败的尝试 问题一&#xff1a;source activate 失效&#xff0c;被写死的旧路径 问题二&#xff1a;官方安装器修复失败&#xff0c;神秘的“进程池损坏” 问题三&#xff1a;核心脚本也“背…

Redis的多并发实际业务场景下的使用分析:布隆过滤器

文章目录前言什么是布隆过滤器项目中引入布隆过滤器与缓存结合的最佳实践场景&#xff1a;高并发用户访问商品详情页&#xff08;防止缓存穿透&#xff09;总结&#xff1a;前言 okok 我们已经学完了 所有的redis中的常用的数据结构 下面就是进阶 我会用一系列的例子 去讲解 如…

【AI】人工智能领域关键术语全解析

一、前言 人工智能&#xff08;AI&#xff09;作为当今最热门的技术领域之一&#xff0c;正在深刻改变着我们的生活和工作方式。然而&#xff0c;对于初学者或非技术背景的人士来说&#xff0c;理解AI领域的专业术语可能是一项挑战。本文旨在全面解析人工智能领域的关键术语&a…

【Linux基础知识系列】第四十三篇 - 基础正则表达式与 grep/sed

在Linux系统中&#xff0c;正则表达式是一种强大的文本处理工具&#xff0c;广泛用于文本搜索、替换和批量处理。通过掌握基础正则表达式的语法&#xff0c;结合grep和sed命令&#xff0c;用户可以高效地完成复杂的文本处理任务。无论是数据分析师、软件开发者还是系统管理员&a…

SIMATIC S7-1200的以太网通信能力:协议与资源详细解析

SIMATIC S7-1200的以太网通信能力&#xff1a;协议与资源解析 在工业自动化领域&#xff0c;PLC的通信能力往往直接影响着整个控制系统的灵活性与高效性。西门子SIMATIC S7-1200系列PLC作为一款广泛应用的中小型控制器&#xff0c;其强大的以太网通信功能是其核心优势之一。本文…

什么是高防 IP?从技术原理到实战部署的深度解析

目录 前言 一、高防 IP 的定义与核心价值 二、高防 IP 的技术原理与架构 2.1 流量牵引技术 2.2 流量清洗引擎 2.3 回源机制 三、高防 IP 的核心防护技术详解 3.1 DDoS 攻击防御技术 3.2 高防 IP 的弹性带宽设计 四、实战&#xff1a;基于 Linux 的高防 IP 环境配置 …

NW710NW713美光固态闪存NW719NW720

美光NW系列固态闪存深度解析&#xff1a;技术、性能与市场洞察一、技术架构与核心创新美光NW系列固态闪存&#xff08;包括NW710、NW713、NW719、NW720&#xff09;的技术根基源于其先进的G9 NAND架构。该架构通过5纳米制程工艺和多层3D堆叠技术&#xff0c;在单位面积内实现了…

JVM汇总

1.什么是JVM&#xff1f;Java虚拟机&#xff0c;Java具有自动内存管理等一系列特性&#xff0c;为实现Java跨平台&#xff0c;一次编译处处执行。2.JVM结构图3.类加载器-入口加载class文件&#xff0c;将类信息存放到运行时数据区的方法区内存空间中通过魔数和文件格式来判断是…

2024.09.20 leetcode刷题记录

# 前言 昨天发布了第一遍博客&#xff0c;感觉很好&#xff0c;趁着我现在还是很感兴趣就多发几遍&#xff0c;希望能坚持下去&#xff0c;在这里记录下自己学习成长的经历。 今天是周五&#xff0c;下周一就又要去实习啦&#xff0c;距离上一段实习刚结束一个月&#xff0c;之…

SQLite3 中列(变量)的特殊属性

在 SQLite3 中&#xff0c;列的特殊属性通常通过约束&#xff08;Constraints&#xff09;和数据类型修饰符来定义。这些属性可以在创建表时指定&#xff0c;用于限制数据的完整性或定义特殊行为。以下是 SQLite3 支持的主要特殊属性及其说明&#xff1a; 1. 主键约束&#xff…

Datawhale AI 夏令营:用户洞察挑战赛 Notebook(2)

针对文本聚类优化 优化TF-IDF特征工程# 调整ngram_range&#xff1a;设置为(1, 2)&#xff0c;捕捉单字和双字词&#xff08;如“不错”“不满意”&#xff09;。 # 限制特征数量&#xff1a;通过max_features5000保留高信息密度特征&#xff0c;降低维度。 # 过滤低频/高频词&…