spring揭秘25-springmvc05-过滤器与拦截器区别(补充)

文章目录

  • 【README】
  • 【1】springmvc拦截器回顾
    • 【1.1】定义与应用
    • 【1.2】拦截器作用范围
  • 【2】servlet过滤器回顾
    • 【2.1】过滤器定义与应用
    • 【2.2】过滤器作用范围
  • 【3】springmvc拦截器与servlet过滤器区别(重要*)
    • 【3.1】拦截方法调用代码实现

【README】

代码详情参见: springmvcDiscoverFirstDemo【github】

1)本文根据spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理) 中的拦截器与过滤器进行总结;

  • 确切的说本文讨论的拦截器指的是springmvc拦截器,过滤器是servlet过滤器;springmvc是基于servlet构建的web框架,但两者有区别;(当然了,servlet有拦截器,也有过滤器)

2)拦截器与过滤器都可以对业务逻辑做拦截,即在上下文织入逻辑,所以把两者放在一起比较;

  • 拦截器与过滤器最重要的应用场景:本文认为是偷梁换柱, 在拦截方法中,用新对象替换已有对象 ; (当然也有其他场景,如日志收集, 参数校验)


【1】springmvc拦截器回顾

【1.1】定义与应用

1)springmvc拦截器定义:基于servlet拦截器思想,springmvc提供的对servlet内部处理逻辑进行拦截的抽象接口;

2)应用场景:日志收集, 参数校验等; 其实最重要的应用,应该是偷梁换柱;就是在拦截方法中,可以用新对象替换已有对象

【HandlerInterceptor】

package org.springframework.web.servlet;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;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 {}
}

【TimeCostHandlerInterceptor】自定义拦截器

public class TimeCostHandlerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setAttribute("startTime" , System.currentTimeMillis());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 {Long startTime = (Long) request.getAttribute("startTime");System.out.println(request.getServletPath() + " 执行耗时统计(单位毫秒)=" + (System.currentTimeMillis() - startTime));}
}

【dispatcher-servlet.xml】装配拦截器到HandlerMapping

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 注册自定义处理器拦截器 --><bean id="timeCostHandlerInterceptor"  class="com.tom.springmvc.handlerinterceptor.TimeCostHandlerInterceptor"/><!-- 注册HandllerMapping bean到springweb容器, BeanNameUrlHandlerMapping使用URL与Controller的bean名称进行匹配 --><bean id="beanNameUrlHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="interceptors"><list><ref bean="timeCostHandlerInterceptor" /> <!-- 装配拦截器 --> </list></property></bean><!-- SimpleUrlHandlerMapping: 可以配置web请求到具体二级控制器的映射, 可以把一组或多组拥有相似特征的web请求映射给二级控制器--><bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><!-- 设置SimpleUrlHandlerMapping优先级为1,优先匹配,若有多个HandlerMapping时 --><property name="order" value="1" /><property name="mappings"><value>/userController.do=userController/bankCard*.do=bankCardController/bankCard/*.do=bankCardController/pdfUrlView*.do=pdfUrlViewController</value></property></bean></beans>


【1.2】拦截器作用范围

1) 由配置可知,拦截器的作用范围是HandlerMapping ; 如本文配置了2个HandlerMapping,包括 BeanNameUrlHandlerMapping, SimpleUrlHandlerMapping ;而只有BeanNameUrlHandlerMapping装配了timeCostHandlerInterceptor拦截器,而SimpleUrlHandlerMapping 没有;

  • 所以:通过BeanNameUrlHandlerMapping找到的二级处理器,并调用该处理器时,才会有timeCostHandlerInterceptor拦截功能;而SimpleUrlHandlerMapping 没有;
  • 而二级处理器是由一级处理器DispatcherServlet调用HandlerMapping查找到的,所以总结起来,springmvc拦截器是在Servlet内部做拦截;(补充:servlet拦击器是对servlet外部做拦截,即对servlet上下文做拦截) ;


【2】servlet过滤器回顾

【2.1】过滤器定义与应用

1)servlet过滤器:servlet框架提供的对servlet逻辑做前置过滤的抽象接口;

2)应用场景:如参数校验; 与拦截器类似, 其实最重要的应用,应该是偷梁换柱;就是在拦截方法(doFilter)中,可以用新对象替换已有对象

package jakarta.servlet;import java.io.IOException;public interface Filter {default public void init(FilterConfig filterConfig) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException;default public void destroy() {}
}

【CustomFilter】自定义过滤器

public class CustomFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println(request.getServletContext().getContextPath() + " CustomFilter 过滤器执行");chain.doFilter(request, response);System.out.println(request.getServletContext().getContextPath() + " CustomFilter 过滤器执行完成后");}
}

【web.xml】注册过滤器代理到servlet容器

<!-- 注册过滤器代理 -->
<filter><filter-name>customFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping><filter-name>customFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

【applicationContext.xml】自定义过滤器注册到spring容器

<!-- 注册自定义过滤器 -->
<bean id="customFilter"  class="com.tom.springmvc.filter.CustomFilter"/>


【2.2】过滤器作用范围

1)过滤器: 对servlet进行拦截,且仅可以做前置拦截(在servlet入口方法执行前拦截); 若满足条件,则调用FilterChain.doFilter()放行;否则封装响应报文,直接返回;



【3】springmvc拦截器与servlet过滤器区别(重要*)

1)拦截位置不同:

  • 拦截器有3个拦截方法,包括preHandle, postHandle, afterCompletion 方法;可以在上文与下文以及结束时拦截;
  • 过滤器只有1个拦截方法, 包括doFilter方法; 也可以在上下文拦截(FilterChain.doFilter()的上文和下文织入业务逻辑);

2)放行请求的方式不同:

  • 拦截器的preHandle方法通过返回true/false放行请求;
  • 过滤器的doFilter()) 通过调用 FilterChain.doFilter() 放行请求; (责任链模式)

3)作用范围不同:

  • 拦截器是装配给HandlerMapping,是对servlet内部逻辑进行拦截;(本文特指springmvc拦截器)
  • 过滤器是对servlet上文进行拦截,是对servlet外部逻辑进行拦截;(本文特指servlet过滤器)

4)底层拦截机制不同:

  • 拦截器:若有多个拦截器,只要拦截器的preHandle执行通过(返回true,这个非常重要),则其afterCompletion 一定执行(无论是否抛出异常);类似于双向链表;
    • 参考【3.1】HandlerExecutionChain#applyPreHandle()代码, 只有preHandle返回true的拦截器,才会执行其afterCompletion 方法
  • 过滤器:若有多个过滤器,是通过 FilterChain.doFilter() 把请求透传下去,类似于单向链表;


【3.1】拦截方法调用代码实现

【HandlerExecutionChain】 拦截方法调用

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptorList.size(); i++) {HandlerInterceptor interceptor = this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {// 若有一个拦击器前置拦截返回false,则已执行preHandle方法的所有拦截器的afterCompletion方法被执行 【因为暂存了已执行preHandle方法的拦截器索引或下标】 triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i; // 暂存已执行preHandle方法的拦截器索引 (下标递增)}return true;
}/*** Apply postHandle methods of registered interceptors.*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {for (int i = this.interceptorList.size() - 1; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}
}/*** Trigger afterCompletion callbacks on the mapped HandlerInterceptors.* Will just invoke afterCompletion for all interceptors whose preHandle invocation* has successfully completed and returned true.*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {// 把已执行preHandle方法的拦截器索引取出,执行其afterCompletion方法(下标递减)for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i);try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}
}

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

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

相关文章

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…

elasticsearch单个node节点写入数据

不设置用户名及密码的情况下,直接写入 我以为没有明确的设置就没有账号密码了,发现还是不行,竟然是非root的用户名,当初./bin/elasticsearch时创建的非sudo用户,elasticsearch 用户名(不是python虚拟环境的用户名),密码另外设置了,此时也是elasticsearch的密码,现在…

如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue

TOC ssm779基于SSM的宠物服务平台的设计与实现vue 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#x…

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo 安全帽头盔检测数据集介绍 数据集名称 安全帽头盔检测数据集 (Safety Helmet and Person Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7…

【C++ STL】手撕vector,深入理解vector的底层

vector的模拟实现 前言一.默认成员函数1.1常用的构造函数1.1.1默认构造函数1.1.2 n个 val值的构造函数1.1.3 迭代器区间构造1.1.4 initializer_list 的构造 1.2析构函数1.3拷贝构造函数1.4赋值运算符重载 二.元素的插入,删除,查找操作2.1 operator[]重载函数2.2 push_back函数:…

OpenCV视频I/O(11)视频采集类VideoCapture之设置视频捕获设备的属性函数 set()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 VideoCapture 中设置一个属性。 在OpenCV中&#xff0c;cv::VideoCapture::set() 函数用于设置视频捕获设备的属性。这些属性可以包括分辨率、…

Redis篇(面试题 - 连环16炮)(持续更新迭代)

目录 目录 目录 &#xff08;第一炮&#xff09;一、Redis&#xff1f;常用数据结构&#xff1f; 1. 项目里面到了Redis&#xff0c;为什么选用Redis&#xff1f; 2. Redis 是什么&#xff1f; 3. Redis和关系型数据库的本质区别有哪些&#xff1f; 4. Redis 的线程模型…

4 思科模拟器的介绍和使用

4 思科模拟器的介绍和使用 思科的IOS给我们提供了三大模式 设备开机后&#xff0c;进入的模式是【用户模式】 Router表示设备的名称 “>”表示用户模式 在用户模式输入"?" 可列出在用户模式可以使用的命令 第二种模式是特权模式,输入enable进入特权模式&…

【C++】入门基础介绍(上)C++的发展历史与命名空间

文章目录 1. 前言2. C发展历史2. 1 C版本更新特性一览2. 2 关于C23的一个小故事: 3. C的重要性3. 1 编程语言排行榜3. 2 C在工作领域中的应用 4. C学习建议和书籍推荐4. 1 C学习难度4. 2 学习书籍推荐 5. C的第一个程序6. 命名空间6. 1 namespace的价值6. 2 namespace的定义6. …

如何解决 MySQL ERROR 1040 (08004): Too many connections ?

MySQL 是最流行的开源关系数据库管理系统之一&#xff0c;它也是开发人员中非常常用的数据库。即便它高度健壮和可伸缩性极强&#xff0c;像任何软件一样&#xff0c;它也可能出现错误。我们会经常遇到一个错误&#xff0c;特别是在高流量系统中&#xff0c;error 1040 (08004)…

DenseNet算法:口腔癌识别

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 DenseNet算法结构 其基本思路与ResNet一致&#xff0c;但是它建立的是前面所有层和后面层的密集连接&#xff0c;它的另一大特色是通过特征在channel上的连接来实现特征重用。 二 设计理念 三…

XSP16受电端取电快充协议芯片的应用及工作原理

受电端取电快充协议芯片XSP16是一款集成PD2.0/3.0、PD3.1、QC2.0/3.0、华为FCP/SCP、三星AFC等全协议芯片&#xff0c;这使得它能够适应不同品牌和设备的需求。支持大电流、大功率140W28V/5A给设备快速供电&#xff0c;该芯片采用小 QFN16_3*3mm封装&#xff0c;芯片支持电压向…

【网络篇】计算机网络——应用层详述(笔记)

目录 一、应用层协议原理 1. 进入应用层 2. 网络应用程序体系结构 &#xff08;1&#xff09;客户-服务器体系结构&#xff08;client-server architecture&#xff09; &#xff08;2&#xff09; P2P 体系结构&#xff08;P2P architecture&#xff09; 3. 进程间通讯 …

dll动态库加载失败导致程序启动报错以及dll库加载失败的常见原因分析与总结

目录 1、问题说明 2、dll库的隐式加载与动态加载 2.1、dll库的隐式加载 2.2、dll库的显式加载 3、使用Process Explorer查看进程加载的dll库信息以及动态加载的dll库有没有加载成功 3.1、使用Process Explorer查看进程加载的dll库信息 3.2、使用Process Explorer查看动态…

Json-Rpc框架(JsonCpp库使用介绍)

阅读导航 引言一、Json数据格式二、JsonCpp介绍三、JsonCpp使用示例四、封装Json工具类 引言 JsonCpp&#xff0c;作为一个广受欢迎的C JSON库&#xff0c;以其易用性、高性能和丰富的功能集赢得了众多开发者的青睐。它不仅提供了简洁直观的API用于JSON数据的解析和生成&#…

C语言语句、语句分类及注释

文章目录 一、语句和语句分类二、注释&#x1f355;注释是什么&#xff1f;为什么写注释&#xff1f;1. /**/的形式2. //的形式3. 注释会被替换 三、随机数的生成1.rand函数2.srand函数3.time函数4.设置随机数的范围 四、C99中的变长数组五、问题表达式解析表达式1表达式2表达式…

redis中的数据类型(Set与ZSet)

&#xff08;一&#xff09;set set在我们目前有两个意思&#xff0c;首先就是这里使用的集合&#xff0c;第二个是我们的set和get方法 因为set是一个集合&#xff0c;所以他具有集合的一些特点&#xff1a; 1.集合中的元素无序 2.集合中的元素是不可重复的 3.集合间是可…

2.点位管理开发(续)及设计思路——帝可得后台管理系统

目录 前言一、页面原型二、修改1、页面展示2、新增 3 、总结思路 前言 提示&#xff1a;本篇继续点位管理的改造 一、页面原型 页面展示新增 二、修改 1、页面展示 页面修改&#xff1a;修改标签换行、顺序顺序、地址过长时换行问题&#xff1b; <el-table v-loading…

大厂笔试现已经禁用本地IDE怎么看

如果我说本来面试做题这种事情就是反人类你相信吗&#xff1f; 这个罪恶的源头就是 Google&#xff0c;说是为了选择高素质的计算机编程水平的人才&#xff0c;然后把面试就变成了考试&#xff0c;最大的受益者当然是印度人了。 当把一个考察过程变成标准化的考试过程&#x…

前后端传输文件(图片)

前端&#xff1a;Vue | 后端&#xff1a;.NET&#xff08;ASP.NET Core&#xff09; 情况1&#xff1a;前端>后端 前端&#xff1a; 1.设置 header 为 multipart/form-data 2.将数据封装为 FormData 类型 const formData new FormData() ......获取数据并通过append函数…