过滤器,监听器与拦截器的区别
过滤器,监听器与拦截器的区别
过滤器和监听器不是Spring MVC中的组件,而是Servlet的组件,由Servlet容器来管理。拦截器是Spring MVC中的组件,由Spring容器来管理
Servlet过滤器与Spring MVC 拦截器在Web应用中所处的层次如下图所示:

过滤器Filter
过滤器是Servlet的高级特性之一,是实现Filter接口的Java类。其基本功能就是对Servlet的调用进行干预,在Servlet请求和响应的过程中增加一些特定的功能。
应用场景
在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数,如:过滤低俗文字、危险字符、敏感词过滤、响应信息压缩、控制权限、控制转向、做一些业务逻辑判断等
工作原理
使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
-
当服务器启动,会创建Filter对象,并调用init方法,只调用一次。
-
当访问资源,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,
-
当服务器关闭时,会调用Filter的destroy方法来进行销毁操作。
Filter接口
通过看Filter接口代码,其有三个方法:
public interface Filter {default void init(FilterConfig filterConfig) throws ServletException {}void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;default void destroy() {}
}
-
init(FilterConfig conf)方法:用于执行过滤器的初始化工作,web容器会在web项目启动时自动调用该方法。
-
doFilter(ServletRequest request,SerlvetResponse response,FilterChain chain)方法:当请求和响应被过滤器拦截后,都会交给doFilter来处理:其中两个参数分别是被拦截request和response对象,可以使用chain的doFliter方法来放行。
-
destroy()方法:用于释放关闭Filter对象打开的资源,在web项目关闭时,由web容器自动调用该方法。
开发一个Filter
开发一个过滤器比较简单,第一步实现Filter接口,第二步配置过滤器
实现Filter接口:
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;@Component
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {//获取filter名字String filterName = filterConfig.getFilterName();//获取filter里配置的init-param配置指定参数的值,如果参数不存在,则返回 nullString email = filterConfig.getInitParameter("email");//获取filter里配置的init-param配置所有参数值,如果过滤器没有初始化参数,则返回一个空的 EnumerationEnumeration<String> initParameterNames = filterConfig.getInitParameterNames();//返回对调用者在其中执行操作的 ServletContext 的引用。ServletContext servletContext = filterConfig.getServletContext();}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;//统一编码处理httpRequest.setCharacterEncoding("UTF-8");httpResponse.setContentType("text/html;charset=UTF-8");//添加name属性httpRequest.setAttribute("name", "tom");//获取请求中的所有cookieCookie[] cookies = httpRequest.getCookies();if (cookies != null) {StringBuilder sb = new StringBuilder();for (Cookie cookie : cookies) {String cookieName = cookie.getName();String cookieValue = cookie.getValue();//设置cookie的相关属性ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();httpResponse.addHeader(HttpHeaders.SET_COOKIE, lastCookie.toString());}filterChain.doFilter(httpRequest, httpResponse);}}@Overridepublic void destroy() {}
}
配置Filter:
(1)在web.xml中配置
<filter><filter-name>myFilter</filter-name><filter-class>com.lsl.mylsl.filter.MyFilter</filter-class><init-param><param-name>email</param-name><param-value>15***011@qq.com</param-value></init-param>
</filter>
<filter-mapping><filter-name>myFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
<filter>配置
fliter-name:指为过滤器的名字
filter-class:过滤器的完整类名
init-param:用于为过滤器指定初始化参数,它的子元素指定参数的名字
<filter-mapping>配置
filter-name:你在<fliter>中声明的filter-name
url-patten:设置 filter 所拦截的请求路径(过滤器关联的URL样式)
(2)注解配置
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
(3)配置类配置
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyFilterConfig {@Beanpublic FilterRegistrationBean myFilter(){FilterRegistrationBean fb = new FilterRegistrationBean();//设置filter启动顺序fb.setOrder(1);fb.setFilter(new MyFilter());fb.addInitParameter("email","15***11@qq.com");//设置拦截请求规则,这里拦截所有请求fb.addUrlPatterns("/*");return fb;}
}
三种Filter配置的优缺点:
第一种xml的配置需要在xml中写配置,但是现在大部分是springboot项目开发,都是重注解轻配置,现在不怎么使用了。如果xml中配置了多个filter,那么按上下先后顺序依次起作用。第二种注解配置,写法比较简单,但是有一个缺点,多个filter没法控制先后顺序。如果想用这个注解,但是还想控制filter的先后顺序,网上有个说法,就是按filter的名字首字母顺序来确定先后顺序,比如有多个filter的名字是AdminFilter和UserFilter,那么就是前者先生效后者后生效。第三种配置类配置,我个人比较倾向于这个(当然如果就是一个简单filter,用注解最简单方便),有xml配置的所有功能。可以定义启动顺序,初始化参数等。
拦截器Interceptor
Spring MVC中的拦截器( Interceptor)类似于Servlet中的过滤器( Filter ),它主要用于拦截用户请求并作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
工作原理
一个拦截器,只有 preHandle 方法返回 true , postHandle 、 afterCompletion 才有可能被执行;如果 preHandle 方法返回 false ,则该拦截器的 postHandle 、 afterCompletion 必然不会被执行。拦截器不是Filter,却实现了Filter的功能,其原理在于:
所有的拦截器 (Interceptor) 和处理器 (Handler) 都注册在 HandlerMapping 中。Spring MVC 中所有的请求都是由 DispatcherServlet 分发的。当请求进入 DispatcherServlet.doDispatch() 时候,首先会得到处理该请求的 Handler (即 Controller 中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
应用场景
拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
- 登录验证,判断用户是否登录。
- 权限验证,判断用户是否有权限访问资源,如校验token
- 日志记录,记录请求操作日志(用户Ip,访问时间等),以便统计请求访问量。
- 处理Cookie、本地化、国际化、主题等。
- 性能监控,监控请求处理时长等。
拦截器执行顺序


拦截器接口HandlerInterceptor
package org.springframework.web.servlet;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}
从代码可以看出,拦截器接口有三个方法,分别的作用是:
preHandle方法叫做预处理方法,本方法在控制器方法(MyController的方法)之前执 行,用户的请求最先到达此方法,在这个方法中可以获取请求的信息,验证请求是否符合要求。以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)。如果返回true则放行,返回false则拦截。
postHandle方法叫做后处理方法。在controller中的方法之后执行的。能够获取到处理器方法的返回值 mv,可以修改mv中的数据和视图。可以影响到最后的执行结果。主要是对原来的执行结果做二次修正
afterCompletion方法最后执行的方法,在页面渲染之后执行。在请求处理完成后执行的,框架中规定是当你的视图处理完成后,对视图进行了forword。就任务请求处理完成。一般做资源回收工作的,程序请求过程中创建了一些对象。在这里可以删除,吧占用的内存回收
开发一个拦截器Interceptor
开发一个拦截器需要2步,第一步实现HandlerInterceptor接口来定义一个拦截器,第二步就是配置拦截器了
(1)定义一个拦截器:
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {//在拦截的请求了添加属性,在对应请求的controller中的request中就可以获取该参数了//比如String userName = (String)request.getAttribute("userName");request.setAttribute("userName","lsl");//获取cookieCookie[] cookies = request.getCookies();//设置header属性response.addHeader("SameSite","Lax");//添加cookieCookie cookie = new Cookie("name","lsl");response.addCookie(cookie);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
(2)配置拦截器:
package com.lsl.mylsl.interceptor;import org.springframework.context.annotation.Bean;
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 MyInterceptorConfig implements WebMvcConfigurer {/*** 配置拦截器* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(myInterceptor()).addPathPatterns("/api/lsl/**")//需要拦截的请求.addPathPatterns("/api/mjx/**")//需要拦截的请求.excludePathPatterns("/api/debug/**")//不拦截的请求.excludePathPatterns("api/lsl/getName");//不拦截的请求}/*** 注入拦截器到spring容器* @return*/@Beanpublic MyInterceptor myInterceptor(){return new MyInterceptor();}
}
过滤器与拦截器工作流程

过滤器和拦截器区别
运行的顺序不同:
过滤器是Servlet容器接收到请求后,在Servlet被调用之前运行的,而拦截器则是在Servlet被调用之后,但是在响应发送到客户端之前来运行的

配置方式不同:
过滤器是在web.xml里面进行配置的,拦截器是在Spring的配置文件中去进行配置
依赖的对象不同:
过滤器依赖于Servlet容器,而拦截器不依赖与Servlet容器
操作的对象不同:
过滤器中只能对request和response进行操作,拦截器可以对request,response,handler,modelAndView,execption进行操作,相当于拦截器多了对于Spring MVC生态下组件的一个操作能力

通俗理解:
(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)
**(2)拦截器(Interceptor)**在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西
转发和重定向区别

相关文章:
过滤器,监听器与拦截器的区别
过滤器,监听器与拦截器的区别 过滤器和监听器不是Spring MVC中的组件,而是Servlet的组件,由Servlet容器来管理。拦截器是Spring MVC中的组件,由Spring容器来管理 Servlet过滤器与Spring MVC 拦截器在Web应用中所处的层次如…...
clickhouse ssb-dbgen数据构造 及 clickhouse-benchmark简单压测
一、 测试数据构造 1. 数据样例 官方文档有给出一批数据样例。优点是比较真实,缺点是太大了,动辄上百G不适合简单小测试 Anonymized Yandex.Metrica DatasetStar Schema BenchmarkWikiStatTerabyte of Click Logs from CriteoAMPLab Big Data Benchma…...
【数据分析】统计量
1. 均值、众数描述数据的集中趋势度量,四分位差、极差描述数据的离散程度。 2. 标准差、四分位差、异众比率度量离散程度,协方差是度量相关性。 期望值分别为E[X]与E[Y]的两个实随机变量X与Y之间的协方差Cov(X,Y)定义为: 从直观上来看&…...
【通用消息通知服务】0x4 - 目前进展 阶段复盘
【通用消息通知服务】0x4 - 阶段复盘 达成 基本的API已经写完✍️了(消息查看发送, 模板crud,终端crud,发送渠道crud,计划crud,计划执行查看)拆分server, executor, planner三个入口, 方便针对性水平扩展整体架构初步形成,通过队列实现了事件驱动模型和消息订阅发…...
vue若依导出word文件,简单的实现
首先前端导包,注意exportDocx的导包位置要修改成你自己的 import {exportDocx} from /utils/docUtil/docutil.js; import {addDays} from date-fns; import {listGongyi} from "/api/system/detail";然后新建一个测试按钮 <el-col :span"1.5"><…...
【LeetCode75】第四十题 最大层内元素和
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 这道题和LeetCode75的上一题大同小异,都是要我们对二叉树进行层序遍历。 那具体如何层序遍历我再上一题也详细介绍过了&#…...
脱离束缚:数字化工厂中ARM控制器的革命性应用!
近年来,中国数字经济体系已进入高速增长阶段。制造业作为中国经济高质量发展的重要支撑力量,在面临生产成本不断上涨、关键装备和核心零部件“受制于人”等挑战时,建设数字化工厂已成必然。 数字化工厂数据采集出现的问题 在数字工厂的建设…...
queue ide is not exists in YARN
报错内容: 2023-08-17 17:30:31.342 [ERROR] [BaseTaskScheduler-Thread-7 ] o.a.l.o.s.a.AsyncExecTaskRunnerImpl (79) [run] - Failed to execute task astJob_1_codeExec_1 org.apache.linkis.orchestrator.ecm.exception.ECMPluginErrorException: errCode:…...
【C++】UDP通信:客户端向服务端发送消息并接收服务端回应的消息
目录 1 UDP简介 2 通信 3 实践 4 运行结果 1 UDP简介 (1)UDP通信是无连接的,因此不需要connect操作。 (2)UDP通信过程需要指定数据接收端的IP和端口。 (3)UDP不对收到的数据进行排序。 (4)UDP对接收到的数据报不回复确认信息。 (5)如果发生了数据丢失,不会丢一…...
RabbitMq深度学习
什么是RabbitMq? RabbitMQ是一个开源的消息队列中间件,它实现了高级消息队列协议(AMQP)。它被广泛用于分布式系统中的消息传递和异步通信。RabbitMQ提供了一种可靠的、可扩展的机制来传递消息,使不同的应用程序能够相互之间进行…...
EasyExcel自定义字段对象转换器支持转换实体和集合实体
文章目录 1. 实现ObjectConverter2. 使用3. 测试3.1 导出excel3.2 导入excel 1. 实现ObjectConverter package com.tophant.cloud.common.excel.converters;import cn.hutool.json.JSONUtil; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.…...
Linux重置ROOT密码(CentOS)
解释说明 在CentOS中重置root密码通常需要进入单用户模式,这是一个没有密码限制的特殊模式,允许您以root权限登录系统并更改密码。 重启系统 如果您无法登录到系统,可以通过重启系统来开始这个过程。您可以使用虚拟机控制台、物理服务器控制台…...
【Spring】一文带你彻底搞懂IOC、AOP
目录 首先简单了解一下什么是spring框架 什么是IOC? 什么是依赖注入(DI)? 控制反转和依赖注入又有什么关系? AOP是什么? SpringAOP的实现 说了这么多抽象概念,举个实例方便理解 首先简单…...
国际旅游网络的大数据分析(数学建模练习题)
题目:国际旅游网络的大数据分析 伴随着大数据时代的到来,数据分析已经深入到现代社会生活中的各个方面。 无论是国家政府部门、企事业单位还是个人,数据分析工作都是进行决策之前的 重要环节。 山东省应用统计学会是在省民政厅注册的学术类社会组织&…...
音视频技术开发周刊 | 308
每周一期,纵览音视频技术领域的干货。 新闻投稿:contributelivevideostack.com。 OpenAI首席科学家最新访谈:对模型创业两点建议、安全与对齐、Transformer够好吗? OpenAI首席科学家Ilya Sutskever最近和他的朋友Sven Strohband进…...
多旋翼飞控底层算法开发系列实验 | 多旋翼动力系统设计实验3
多旋翼动力系统设计实验3 01/多旋翼动力系统简介 多旋翼无人机的动力系统通常包括螺旋桨、电机、电调以及电池。动力系统是多旋翼最重要的组成部分,它决定了多旋翼的主要性能,如悬停时间、载重能力、飞行速度和飞行距离等。动力系统的部件…...
Redis之Sentinel(哨兵)机制
一、Sentinel是什么? Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)…...
加密的PDF文件,如何解密?
PDF文件带有打开密码、限制编辑,这两种密码设置了之后如何解密? 不管是打开密码或者是限制编辑,在知道密码的情况下,解密PDF密码,我们只需要在PDF编辑器中打开文件 – 属性 – 安全,将权限状态修改为无保护…...
【java】获取当前年份
目录 一、代码示例二、截图示例 一、代码示例 package com.learning;import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.Year; import java.util.Calendar; import java.util.Date;/*** 获取当前年份*/ public class GetCurrentYear {public …...
前端面试话术集锦第一篇
🚗前端面试集锦目录 💖前端面试话术集锦第一篇💖 💖前端面试话术集锦第二篇💖 文章目录 1. 前端需要注意哪些SEO2. \<img>的title和alt有什么区别3. HTTP的⼏种请求⽅法⽤途4. 从浏览器地址栏输⼊url到显示⻚⾯的步骤5. 如何进⾏⽹站性能优化6. HTTP状态码及其…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
【QT控件】显示类控件
目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏:QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...
6.9本日总结
一、英语 复习默写list11list18,订正07年第3篇阅读 二、数学 学习线代第一讲,写15讲课后题 三、408 学习计组第二章,写计组习题 四、总结 明天结束线代第一章和计组第二章 五、明日计划 英语:复习l默写sit12list17&#…...
构建Docker镜像的Dockerfile文件详解
文章目录 前言Dockerfile 案例docker build1. 基本构建2. 指定 Dockerfile 路径3. 设置构建时变量4. 不使用缓存5. 删除中间容器6. 拉取最新基础镜像7. 静默输出完整示例 docker runDockerFile 入门syntax指定构造器FROM基础镜像RUN命令注释COPY复制ENV设置环境变量EXPOSE暴露端…...
