过滤器Filter和拦截器Interceptor心得

news2024/12/22 22:53:05

上一篇文章讲了监听器Listener,下面我们来讲一下过滤器和拦截器。

一、过滤器Filter。

首先,servlet容器(比如tomcat)肯定的要有servlet才能发挥它的光彩。在上古jsp时代,我们会写各种servlet通过不同的请求来实现我们相关的业务,就如同我们现在要写各种controller一样来接收用户请求一样。现在我们不需要写servlet了,因为伟大的spring拯救了我们这些copy工程师,也因为spring的易用的良好生态导致我们很多人现在找不到活。spring给我们弄了个很牛X的servlet,那就是DispatcherServlet。 我们老程序员肯定看过如下配置:

<!-- web.xml -->
<web-app>
  <!-- ... -->
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 可选配置:设置Spring MVC配置文件的位置 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
    </init-param>
    <!-- 可选配置:设置DispatcherServlet的加载顺序 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 配置DispatcherServlet处理哪些请求 -->
    <url-pattern>/</url-pattern> <!-- 通常配置为'/'来处理所有请求 -->
  </servlet-mapping>
  <!-- ... -->
</web-app>

 我们Java程序员老是自豪的喊我们写的web是MVC的,大部分依赖于DispatcherServlet它这个家伙。

DispatcherServlet 是 Spring Web MVC 框架的核心组件,它充当了前端控制器的角色,实现了前端控制器设计模式。在基于 Spring MVC 构建的 Java Web 应用程序中,DispatcherServlet 主要承担以下作用:

  1. 统一入口:作为所有HTTP请求的集中处理者,应用程序的所有请求首先都会被路由到DispatcherServlet。

  2. 请求分发:根据用户请求的URL,DispatcherServlet会查找合适的处理器(Controller),这一过程通过HandlerMapping实现,它可以将请求映射到具体的处理器方法。

  3. 处理器适配:找到处理器后,DispatcherServlet使用HandlerAdapter来调用处理器的方法执行业务逻辑,即使处理器有不同的实现方式(如注解控制器、XML配置的控制器等)。

  4. 数据绑定和验证:在调用处理器方法前,DispatcherServlet会自动将请求参数绑定到处理器方法的参数上,并执行任何相关的数据验证。

  5. 视图解析:处理器方法执行完毕后,通常会返回一个逻辑视图名,DispatcherServlet通过ViewResolver接口将逻辑视图名解析成实际的视图对象,进而渲染模型数据并生成最终的响应内容。

  6. 拦截器处理:支持HandlerInterceptor(拦截器)的配置,可以在请求处理前后执行额外的逻辑,例如权限检查、日志记录等。

  7. 异常处理:处理控制器抛出的异常,并根据配置将其映射到特定的错误页面或返回适当的HTTP错误状态码。

  8. 文件上传支持:通过配置MultipartResolver,DispatcherServlet能处理多部分表单提交,如文件上传请求。

  9. 国际化支持:支持对请求进行本地化解析,确保返回的内容符合用户的语言环境。

DispatcherServlet在整个Spring MVC架构中扮演着核心调度和管理角色,它负责协调各个组件以完成HTTP请求的处理并返回响应。通过这种方式,它简化了Web应用程序的设计,促进了模块化和可扩展性。

回归正题,在请求没有到servlet之前或者请求离开了servlet之后,想要干点什么该怎么做呢?其实这个想法在没有spring之前就有古老程序员想到了,比如他们遇到了比如说刚写好了一个销售新研发的薄荷味儿的六味地黄丸的servlet,但是太医院御医突发奇想拍脑门说我要跟踪所有访问过这个servlet的贝勒爷有哪些,但工部侍郎不太想改刚写好的servlet,万一增加了这个功能,明天八旗子弟不愿意了又让去掉。。。

这时候过滤器Filter就登场了,它与servlet非常类似,过滤器就是Java组件,请求发送到servlet之前,可以用过滤器截获和处理请求,另外servlet结束工作之后,但在响应发回给客户之前,可以用过滤器处理响应。过滤器可以链到一起,一个接一个地运行。过滤器设计为完全自包含的。过滤器并不关心在它前面运行了哪些过滤器(如果有的话),也不关心后面还会运行哪个过滤器。

过滤器与servlet很像,过滤器有自己的API。如果一个Java类实现了Filter接口对容器来说就有很大不同,这个类会从原先一个普通的Java类摇身一变而成为一个正式的J2EE过滤器。过滤器API的其他成员允许过滤器访问ServletContext,而且可以与其他过滤器链接。就像servlet一样,过滤器也有一个生命周期。类似于servlet,过滤器有init()和destroy()方法。对应于servlet的doGet()/doPost()方法,过滤器则有一个doFilter()方法。Web应用可以有很多的过滤器,一个给定请求可能导致执行多个过滤器。针对请求要运行哪些过滤器,以及运行的顺序如何,这些都要在DD中声明。

 真正的工作在doFilter()中完成,每次容器认为应该对当前请求应用过滤器时,就会调用doFilter()方法。

doFilterO方法有3个参数:一个ServletRequest(而不是HttpServletRequest),一个ServletResponse(而不是HttpServletResponse),一个FilterChain。

它在古老的定义里是这样的。

那么他就能在servlet执行前后干一些别的事情了。比如:

  1. 自定义Filter: 开发者可以编写自己的Filter实现,例如认证过滤器(Authentication Filter)、授权过滤器(Authorization Filter)、字符编码过滤器(Character Encoding Filter)、日志记录过滤器(Logging Filter)等,用于实现特定的请求预处理和后处理功能。

  2. Spring Security Filter Chain: Spring Security框架提供了一整套安全过滤器链,其中包括多个内置的Filter,如ChannelProcessingFilter(通道处理过滤器)、SecurityContextPersistenceFilter(安全上下文持久化过滤器)、LogoutFilter(注销过滤器)、UsernamePasswordAuthenticationFilter(用户名密码认证过滤器)等,这些过滤器一起协作保障了应用的安全性。

  3. Cross-Origin Resource Sharing (CORS) Filter: 为了支持跨域资源共享,开发者经常编写CORS Filter来处理浏览器的预检请求OPTIONS方法以及设置响应头以允许跨域访问。

  4. GZIP Compression Filter: 用于压缩HTTP响应内容,提升网络传输效率。

  5. Content-Type and Character Encoding Filter: 设置响应的Content-Type和字符编码。

  6. Static Resources Filter: 对静态资源(如CSS、JavaScript、图片等)的访问进行优化处理,如缓存控制。

  7. Locale Change Filter: 用于处理用户地域变更请求,切换应用的语言环境。

在Spring Boot项目中,可以通过实现javax.servlet.Filter接口并配置到Spring的WebApplicationInitializer或通过@WebFilter注解在类上声明的方式创建自定义Filter,并在Spring的配置文件或Java配置类中注册到Servlet容器的过滤器链中。特别是你在学Spring Security的时候会发现有很多filter。

二、拦截器Interceptor。

拦截器(Interceptor)和过滤器(Filter)是Java Web框架中两种不同的设计模式,它们各自独立,并非基于彼此设计,但常常在功能上有协同作用,共同完成对HTTP请求和响应的预处理和后处理工作。

过滤器上面说了,是Servlet规范的一部分,它基于责任链模式,能够对Web容器接收到的所有请求及其对应的响应进行统一处理,例如权限验证、编码转换、压缩等。过滤器按照定义的顺序链式执行,且必须依赖于Servlet容器。

拦截器则是更偏向于具体框架的概念,比如Spring MVC框架中的拦截器,它是基于面向切面编程(AOP)思想设计的,通常利用Java反射机制实现,主要用于处理控制器层(如Action、Controller)的请求和响应。拦截器可以介入到业务逻辑执行前后,进行诸如身份验证、日志记录、性能监控等操作。

虽然拦截器和过滤器都可以实现类似的功能,比如对请求进行预处理和后处理,但它们的设计原理、使用场景以及所在的层次有所不同,在实际项目中,可以根据需求选择使用过滤器、拦截器或同时使用两者来优化应用的功能结构。

在Spring框架中,特别是在Spring MVC环境下,Interceptor(拦截器)主要用于增强或修改请求处理的行为,提供一种灵活的方式来添加通用的横切关注点。比如权限验证、日志记录、性能监控、事务管理等。Spring MVC中主要的Interceptor类型如下:

  1. HandlerInterceptor: 这是最常见的Spring MVC拦截器类型,通过实现org.springframework.web.servlet.HandlerInterceptor接口来创建自定义的拦截器。HandlerInterceptor有三个方法可以覆盖:

    • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在处理器执行之前调用,可以决定是否继续执行后续的处理流程。
    • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在处理器执行完并且视图渲染之前调用,可以修改ModelAndView对象。
    • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在整个请求处理完成后(包括视图渲染)调用,主要用于清理资源等工作。
  2. WebRequestInterceptor: 实现org.springframework.web.context.request.WebRequestInterceptor接口,这种拦截器针对的是所有的Web请求,不仅仅是HTTP请求,它的方法包括:

    • preHandle(WebRequest request):在请求处理之前调用。
    • postHandle(WebRequest request, ModelMap model):在请求处理完成但视图尚未渲染之前调用。
    • afterCompletion(WebRequest request, Exception ex):在请求处理完全结束后调用,无论是否有异常。
  3. AsyncHandlerInterceptor: 用于异步请求处理的拦截器,继承自HandlerInterceptor接口,增加了对异步请求生命周期的支持。

除了上述标准拦截器,Spring还提供了许多与特定功能相结合的拦截器,例如:

  • HandlerExceptionResolver接口及其实现类,用于异常处理的拦截,虽然不是严格意义上的Interceptor,但在请求处理流程中起到类似的作用。

此外,Spring AOP也可以看作是一种广义的拦截器,它可以应用于整个Spring容器中所有bean的方法调用,实现更为广泛的切面编程,但与Spring MVC中的HandlerInterceptor不同,它更多的是面向服务和业务层的增强。

那么拦截器和过滤器怎么选择呢?老祖宗在我们面向对象的同时又给我们搞出来一个面向切面的利器,那就是AOP,比如我们可以实现Spring MVC中的org.springframework.web.servlet.HandlerInterceptor拦截器接口。

该接口定义了三个方法,分别对应请求处理的不同阶段,能让我们直接一砍刀切到我们喜欢的Bean中去 :

  1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在处理器执行前调用,如果该方法返回false,则后续的处理器不会被执行,通常用于权限验证、登录状态检查等预处理操作。

  2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在处理器执行完业务逻辑后,视图渲染前调用,可以修改ModelAndView对象,影响视图呈现的数据。

  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在整个请求处理完成后(包括视图渲染)调用,用于释放资源、记录日志等收尾工作。

Spring通过HandlerMapping和HandlerExecutionChain维护一系列的拦截器,形成拦截器链(Interceptor Chain),当请求到达DispatcherServlet时,会沿着这个链依次调用每个拦截器的相应方法。

你是不是感觉拦截器和过滤器功能感很像呢,又是pre又是post,对象的前后都能搞而且都带责任链?是不是又觉得拦截器更牛B想搞哪个对象搞哪个对象呢?那我们该怎么选择呢?因为拦截器需要切到Bean中去,如果你明确知道要搞的那些Bean去增强它,那么你可以用拦截器Interceptor。如果你想再请求前后对某些请求统一做操作并不关心后面某某某实现的某些bean,那么你就用Filter。使用范围和应用场景上的不同点:

  1. 实现原理与依赖

    • Filter: 是Java Servlet规范的一部分,基于Servlet容器提供的过滤器接口javax.servlet.Filter实现。Filter的执行由Servlet容器负责调用,对所有进入Servlet容器的HTTP请求均能进行拦截。
    • Interceptor: 是Spring MVC框架提供的功能,基于Spring的org.springframework.web.servlet.HandlerInterceptor接口实现。Interceptor的执行由Spring DispatcherServlet控制,仅对经过Spring MVC框架处理的请求起作用。
  2. 使用范围

    • Filter: 可以应用于任何基于Servlet的Web应用程序,不限于Spring MVC。它可以捕获所有的HTTP请求和响应,包括静态资源请求和其他框架处理的请求。
    • Interceptor: 特别针对Spring MVC框架中的Controller请求处理,无法直接拦截静态资源请求或非Spring MVC处理的请求。
  3. 执行顺序

    • Filter: 执行顺序较早,处于请求到达Spring DispatcherServlet之前,可以对请求进行初步处理,如编码转换、安全检查等。
    • Interceptor: 执行顺序在Filter之后,仅针对Spring MVC Controller的请求处理,发生在Controller方法调用前后以及视图渲染前后。
  4. 功能定位

    • Filter: 一般用于处理跨越多个应用或框架的通用问题,如登录验证、日志记录、编码转换、请求压缩等,这些处理往往不需要知道具体的业务逻辑。
    • Interceptor: 更加贴近业务逻辑,通常用于处理与Controller方法执行紧密相关的任务,如权限验证、性能监控、统一异常处理、事务管理、注入额外数据到ModelAndView等。
  5. 调用时机

    • Filter: 可以在请求之前(doFilter()方法中)、请求之后或整个请求生命周期的任意时刻进行处理。
    • Interceptor: 有明确的三个调用点:preHandle()(前置处理,可决定是否继续执行请求)、postHandle()(后置处理,可以修改模型和视图数据)和afterCompletion()(完全完成,通常用于清理资源)。

总结起来Filter在Web请求处理的早期阶段发挥作用,拥有更广泛的适用范围,而Interceptor则更聚焦于Spring MVC框架内部的请求处理环节,能够深度参与到业务逻辑的执行过程中。两者结合使用,可以为Web应用提供全面且细致的请求处理和响应控制。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

E-MapReduce极客挑战赛季军方案

前一段时间我参加了E-MapReduce极客挑战赛&#xff0c;很幸运的获得了季军。在这把我的比赛攻略给大家分享一下&#xff0c;希望可以抛砖引玉。 赛题分析与理解 赛题背景&#xff1a; 大数据时代&#xff0c;上云已成为越来越多终端客户大数据方案的落地选择&#xff0c;阿里…

解锁EDM设计秘籍:关键要素一览,邮件如何设计?

一个成功的EDM邮件需要包含多个关键元素&#xff0c;从内容、设计到呼唤行动&#xff0c;每个环节都至关重要。今天&#xff0c;我们就来探讨EDM邮件中应包含的关键元素&#xff1f;以及如何设计邮件&#xff1f; 一、EDM必备关键要素 1、吸引眼球的主题行 主题行应该简短明了…

2-Embedding例子:简单NN网络、迁移学习例子(glove语料预训练)

一、简单例子&#xff1a;构造简单NN网络生成Embedding 1、pytorch例子 2、tensorflow例子 # 1导入模块 import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding import numpy as np# 2构建语料库 corpus[[…

【更新】cyのMemo(20240422~)

序言 胡哥首马在淮安325完赛&#xff0c;他的本硕都在淮安度过&#xff0c;七年的跑步生涯画上句号&#xff0c;真的是很圆满。七年&#xff0c;从180斤瘦到120斤&#xff0c;历经种种&#xff0c;胡哥理解的跑步&#xff0c;不是快&#xff0c;而是稳&#xff0c;他在比赛中从…

线性表的顺序存储如何设计实现?

如何存储 顺序及链式实现 计算机中的状态

【Java】变量零基础教程

目录 一、引言 二、基本组成单位 三、变量的基本原理 四、变量的基本使用步骤 五、变量快速入门 六、变量使用的注意事项 一、引言 为什么需要变量&#xff1f; ​​​​​​一个程序就是一个世界。 大家看下图&#xff0c;是我们现实中的一张生活照&#xff0c;图里有树…

汕头联想 ibm x3500 M5服务器上门维修记录

汕头联想服务器现场检修&#xff1b;汕尾IBM服务器故障维修&#xff1b;揭阳戴尔服务器维修&#xff1b;汕头ERP服务器维修&#xff1b;潮阳地区各种服务器故障维修&#xff1b;各类服务器主板齐全&#xff1b; 分享一例从东莞到汕头某染料厂维修ibm system x3500 M5服务器的真…

47.基于SpringBoot + Vue实现的前后端分离-校园外卖服务系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的校园外卖服务系统设计与实现管理工作…

分布式技术在文本摘要生成中的应用

摘要 自然语言处理首先要应对的是如何表示文本以供机器处理&#xff0c;随着网络技术的发展和信息的公开&#xff0c;因特网上可供访问的数字文档成爆炸式的增长&#xff0c;文本摘要生成逐渐成为了自然语言处理领域的重要研究课题。本文主要介绍了分布式技术在文本摘要生成中…

Oracle21C 引入HR实例(linux)

1、下载资源 https://github.com/oracle-samples/db-sample-schemas点击code&#xff08;代码&#xff09;下载 2、上传Sql文件 解压之后将human_resources里的文件复制到demo\schema\目录&#xff08;具体目录前面的路径是你安装的路径&#xff09;下&#xff0c;如下图 3、…

argparse模块(详解)

文章目录 一、argparse模块&#xff08;1&#xff09;创建命令行解析对象&#xff1a;parser argparse.ArgumentParser()&#xff08;2&#xff09;添加命令行参数和选项&#xff1a;parser.add_argument()&#xff08;3&#xff09;解析命令行参数&#xff1a;args parser.p…

就业班 第三阶段(nginx) 2401--4.22 day1 nginx1 http+nginx初识+配置+虚拟主机

一、HTTP 介绍 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写,是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP是一个基于TCP/IP通信协议来传递数据&#xff08;HTML 文件…

Web3钱包开发获取测试币-Polygon Mumbai(一)

Web3钱包开发获取测试币-Polygon Mumbai(一) 由于主网区块链上的智能合约需要真正的代币&#xff0c;而部署和使用需要花费真金白银&#xff0c;因此测试网络为 Web3 开发人员提供了一个测试环境&#xff0c;用于部署和测试他们的智能合约&#xff0c;以识别和修复在将智能合约…

❤️新版Linux零基础快速入门到精通——第三部分❤️

❤️新版Linux零基础快速入门到精通——第三部分❤️ 非科班的我&#xff01;Ta&#xff01;还是来了~~~3. Linux权限管控3.1 认知root用户3.1.1 Switch User——su3.1.2 sudo命令3.1.3 为普通用户配置sudo认证 3.2 用户和用户组3.2.1 用户、用户组3.2.2 用户组管理3.2.3 用户管…

辽宁梵宁教育设计培训:赋能大学生,新技能学习再升级

辽宁梵宁教育设计培训&#xff1a;赋能大学生&#xff0c;新技能学习再升级 在当今这个日新月异、信息爆炸的时代&#xff0c;大学生们面临着前所未有的挑战与机遇。为了帮助他们更好地适应社会的快速变化&#xff0c;提升个人的综合素质和竞争力&#xff0c;辽宁梵宁教育设计…

基于python实现的医疗领域用户问答的意图识别算法研究(django)

基于python实现的医疗领域用户问答的意图识别算法研究(django) 开发语言&#xff1a;Python语言 数据库&#xff1a;MySQL&#xff0c;Neo4j知识&#xff1a;深度学习&#xff0c;知识图谱工具&#xff1a;pycharm、Navicat、Maven 系统的实现 系统登录界面 医疗领域用户问答…

华媒舍:百度竞价排名如何提升点击率

在网络推广中&#xff0c;提升点击率是十分重要的。运用百度搜索引擎广告是一种常用的提升点击率的形式。而百度竞价推广是搜索引擎所提供的一种付费流量方法&#xff0c;根据提高网站在搜索结果中的排名&#xff0c;可以有效提升点击率。下面我们就详细介绍如何运用百度竞价推…

钢管钢材地板踢脚线定购规格采购批发商城h5公众号开发

钢管钢材地板踢脚线定购规格采购批发商城h5公众号开发 商品管理&#xff0c;订单管理&#xff0c;用户管理&#xff0c;售后管理&#xff0c;商品评价&#xff0c;虚拟商品自动发货&#xff0c;优惠劵&#xff0c;购物送劵。 您可以在这个H5公众号商城上找到以下功能列表&…

flink Unsupported operand types: IF(boolean, NULL, String)

问题&#xff1a;业务方存储了NULL 字符串&#xff0c;需要处理为 null select if(anull&#xff0c;null&#xff0c;a); 结果遇到了 Unsupported operand types: IF(boolean, NULL, String)&#xff0c;根据报错反馈&#xff0c;很明显应该是没有对 null 自动转换&#xff…

Day39 网络编程(一):计算机网络,网络编程,网络模型,网络编程三要素

Day39 网络编程&#xff08;一&#xff09;&#xff1a;计算机网络&#xff0c;网络编程&#xff0c;网络模型&#xff0c;网络编程三要素 文章目录 Day39 网络编程&#xff08;一&#xff09;&#xff1a;计算机网络&#xff0c;网络编程&#xff0c;网络模型&#xff0c;网络…