当前位置: 首页 > news >正文

Spring Mvc中拦截器Interceptor详解

一、概述

拦截器常用于在请求处理的不同阶段插入自定义逻辑。Spring MVC的拦截器作用是在请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理。如:

  • 登录验证:对于需要登录才能访问的网址,使用拦截器可以判断用户是否已登录,如果未登录则跳转到登录页面。
  • 权限校验:根据用户权限对部分网址进行访问控制,拒绝未经授权的用户访问。
  • 请求日志:记录请求信息,例如请求地址、请求参数、请求时间等,用于排查问题和性能优化。
  • 更改响应:可以对响应的内容进行修改,例如添加头信息、调整响应内容格式等。

二、拦截器和过滤器之间的区别

关于过滤器可以看我之前的文章过滤器Filter的介绍和使用。

我们很容易发现拦截器和过滤器十分相似,他们都是对某一阶段的前后进行拦截,进行一些处理。那么他们之间有什么不同呢?

  • 过滤器(Filter)是servlet中定义的,而拦截器(HandlerInterceptor)则是由Spring MVC框架提供

  • 二者所作用的范围不同

    • 过滤器更注重在**请求和响应(即在Servlet之前)**的流程中进行处理,可以修改请求和响应的内容,例如设置编码和字符集、请求头、状态码等。
    • 拦截器则更加侧重于对控制器进行前置或后置处理,在请求到达控制器之前或之后进行特定的操作,例如打印日志、权限验证等。

三、自定义实现拦截器

Spring MVC 提供了 HandlerInterceptor 接口,开发者可以通过实现这个接口来创建自定义的拦截器。其中定义了三个默认方法,用于对不同阶段进行拦截:

  1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    • 在控制器方法执行前调用
    • 返回 true 表示继续执行后续的拦截器和控制器方法;返回 false 表示中断执行,不再调用后续的拦截器和控制器方法。
    • 可以用于权限验证、日志记录等。
  2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
    • 在控制器方法执行后,但在视图渲染前调用
    • 可以用于修改 ModelAndView 对象,添加额外的数据等。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    • 在整个请求处理完成后调用,无论是否发生异常
    • 可以用于资源清理、日志记录等。

创建自定义拦截器:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在控制器方法执行前调用System.out.println("preHandle..." );//这里我们直接返回truereturn true;}@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");}
}

此时要想要该拦截器生效,我们还需在spring mvc配置文件中进行配置(默认对所有控制器进行拦截)

<mvc:interceptors><mvc:interceptor><!--设置要拦截的路径--><mvc:mapping path="/**"/><!--指定不进行拦截的路径--><mvc:exclude-mapping path="/test"/><!--配置自定义拦截器的类路径--><bean class="com.example.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>

也可以通过在自定义 拦截器的类上加上@component注解,此时的配置文件为

<mvc:interceptors><mvc:interceptor><!--设置要拦截的路径--><mvc:mapping path="/**"/><!--指定不进行拦截的路径--><mvc:exclude-mapping path="/test"/><!--默认名字为类名首字母小写--><ref bean="myInterceptor"></ref></mvc:interceptor>
</mvc:interceptors>

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

在 Spring MVC 中,多个拦截器可以组成一个拦截器链,按照注册(配置)顺序依次执行。假设现在按顺序注册三个拦截器Interceptor1,Interceptor2,Interceptor3。

  • 当所有的拦截器的preHandle方法都返回true时:
    • preHandle执行顺序:Interceptor1->Interceptor2->Interceptor3 (顺序执行)
    • postHandle执行顺序:Interceptor3->Interceptor2->Interceptor1 (逆序执行)
    • afterCompletion执行顺序:Interceptor3->Interceptor2->Interceptor1 (逆序执行)
  • 当某一个拦截器的preHandle方法返回false时,这里假设为Interceptor3
    • preHandle执行顺序:Interceptor1->Interceptor2->Interceptor3 (顺序执行直到某一个拦截器返回false)
    • postHandle不执行,控制器方法也不执行
    • afterCompletion执行顺序:Interceptor2->Interceptor1 (返回false的拦截器之前的拦截器逆序执行)

为什么是这样的顺序呢?我们观察源码可以发现:

preHandle源码分析

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {//interceptorList是一个ArrayList集合,按顺序存放了所有的拦截器	//下标从0开始,从这里我们可以知道为什么是顺序执行的。//this.interceptorIndex = i++,注意这个代码,如果返回false,则它的值则表示当前返回false的拦截器的下标for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);//如果返回falseif (!interceptor.preHandle(request, response, this.handler)) {//执行AfterCompletion,这里我们就知道为什么不执行postHandle,而执行AfterCompletion了this.triggerAfterCompletion(request, response, (Exception)null);return false;}}return true;}

postHandle源码分析

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {//可以看到这里是从最后一个拦截器开始逆序遍历for(int i = this.interceptorList.size() - 1; i >= 0; --i) {HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}

afterCompletion源码分析

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {//this.interceptorList.size() - 1表示当前返回false的拦截器的上一个的下标//注意这里是--i//这也就解释了为什么是返回false的拦截器之前的拦截器逆序执行for(int i = this.interceptorList.size() - 1; i >= 0; --i) {HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}

相关文章:

Spring Mvc中拦截器Interceptor详解

一、概述 拦截器常用于在请求处理的不同阶段插入自定义逻辑。Spring MVC的拦截器作用是在请求到达控制器之前或之后进行拦截&#xff0c;可以对请求和响应进行一些特定的处理。如&#xff1a; 登录验证&#xff1a;对于需要登录才能访问的网址&#xff0c;使用拦截器可以判断…...

【go从零单排】Strings and Runes 字符串和字符

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 概念 在Go语言中&#xff0c;rune 是一个内置的数据类型&#xff0c;用于表示一个Unicode字符。它实际上是一个别名…...

django Forbidden (403)错误解决方法

存在问题&#xff1a; django提交请求时&#xff0c;报403错误&#xff1b; 解决方案&#xff1a; 在form表单中加{% csrf_token %} <h1>用户登录</h1><form me method"post" ac action"/login/">{% csrf_token %}<input type"t…...

pdmaner连接sqlexpress

别以为sqlserver默认的端口总是1433 案例 有台sqlserver2008 express服务器&#xff0c;刚安装&#xff0c;支持混合模式登录&#xff0c;其它什么配置也没改。 先看用ADO连接 这说明&#xff1a; 案例中sqlserver端口不是1433 &#xff01;&#xff01;&#xff01;ADO连接…...

如果编译不通过,且感觉代码没有问题,大概率就是中文引起的问题

一、如果中文乱码&#xff1a;彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)_qt 中文乱码-CSDN博客 二、如果中文正常&#xff0c;编译还是有莫名其妙的问题 1、设置编码为 UTF-8(带BOM)。&#xff08;如果下方没有出现“高级保存选项”&#xff0c;只需要修改一下代码&…...

java反序列化学习之CommonCollections3利用链的学习

一、前言 在前文中&#xff0c;我们学习了Java的类加载过程&#xff0c;类加载器以及Java中加载字节码的一些方法&#xff0c;其中介绍了TemplatesImpl&#xff0c;TemplatesImpl是一个可以加载字节码的类&#xff0c;通过调用其newTransformer()方法&#xff0c;即可执行这段字…...

超详细:Vue入门

Vue(发音为 /vjuː/&#xff0c;类似 view)是近些年比较流行的前端框架之一&#xff0c;和 React、Angular 并称为前端三大框架。其中 Vue 简单易学的特点成为国内主流&#xff0c;很多公司已经把它列为一 个前端开发人员必须要掌握的技术点了。 Vue 简介 Vue2.x官网 Vue3.x …...

基础网络安全知识

1.ctfhub技能树 1.1 Web-SQL注入 Web-SQL注入-整数型 && 字符型 && MySQL结构 参考&#xff1a;5.9.6MySql注入 Web-SQL注入-报错注入 step1: 查库名 ?id1 and extractvalue(1,concat(0x7e,database(),0x7e))-- step2: 查看表名 ?id1 and extractvalue(1…...

大语言模型工作原理笔记

大语言模型工作原理笔记 一、词向量&#xff1a;表示语言的方式 大语言模型使用词向量来表示单词&#xff0c;每个词向量是由一串数字组成的列表&#xff0c;代表词空间中的一个点。词空间中&#xff0c;含义相近的词位置更接近&#xff0c;例如"猫"的词向量会靠近…...

安全工程师入侵加密货币交易所获罪

一名高级安全工程师被判犯有对去中心化加密货币交易所的多次攻击罪&#xff0c;在此过程中窃取了超过 1200 万美元的加密货币。 沙克布艾哈迈德&#xff08;Shakeeb Ahmed&#xff09;被判刑&#xff0c;美国检察官达米安威廉姆斯&#xff08;Damian Williams&#xff09;称其…...

使用Docker-Compose安装redis,rabbitmq,nacos,mysql,nginx,tomcat,portainer组件教程

因为开发经常会用到一些组件&#xff0c;又不想在本地启动&#xff0c;所以买了个服务器&#xff0c;然后将这些组件都安装到服务器上以便开发使用。下面就记录下使用docker-compose安装组件的教程以及一些需要注意的地方。 关于docker和docker-compose的安装在另一篇博客中有…...

lora训练模型 打造个人IP

准备工作 下载秋叶炼丹器整理自己的照片下载底膜 https://rentry.org/lycoris-experiments 实操步骤 解压整合包 lora-scripts,先点击“更新” 训练图片收集 比如要训练一个自己头像的模型&#xff0c;就可以拍一些自己的照片&#xff08;20-50张&#xff0c;最少15张&…...

mybatis+postgresql,无感读写json字段

1.实体类中字段类型 import com.alibaba.fastjson.JSONObject;Data public class TestDto {private String name;//对应数据库的JSON字段private JSONObject page_detail;} 2.自定义实现typeHandler package base.utils;import com.alibaba.fastjson.JSONObject; import org…...

苍穹外卖学习记录

苍穹外卖学习 文章目录 苍穹外卖学习知识前提&#xff1a;**<font color"red">Nginx****<font color"red">Swagger** 1.管理员登录思路&#xff1a;详细步骤&#xff1a; 1.1新增员工问题1&#xff1a;在新增员工时&#xff0c;需要将当前登录…...

大数据成功应用商业解决方案的例子

大数据技术在商业领域的广泛应用已经成为现代商业决策和运营优化的关键驱动力。企业利用大数据分析获取洞察&#xff0c;从而提高运营效率、改善客户体验并实现更高的盈利。以下是几个典型的成功案例&#xff0c;这些企业通过大数据技术在各自领域中取得了显著的成果。 亚马逊…...

《Python使用sqlite3数据库》

《Python使用sqlite3数据库》 1、连接数据库2、创建游标3、执行SQL语句4、提交更改5、查询数据6、关闭连接 Python可以使用多种数据库&#xff0c;以下是一般步骤和示例&#xff1a; 1、连接数据库 首先要安装对应的数据库驱动。如使用MySQL数据库&#xff0c;要安装pymysql库…...

XHCI 1.2b 规范摘要(14)

系列文章目录 XHCI 1.2b 规范摘要&#xff08;一&#xff09; XHCI 1.2b 规范摘要&#xff08;二&#xff09; XHCI 1.2b 规范摘要&#xff08;三&#xff09; XHCI 1.2b 规范摘要&#xff08;四&#xff09; XHCI 1.2b 规范摘要&#xff08;五&#xff09; XHCI 1.2b 规范摘要…...

(蓝桥杯C/C++)——基础算法(下)

目录 一、时空复杂度 1.时间复杂度 2.空间复杂度 3.分析技巧 4.代码示例 二、递归 1.递归的介绍 2.递归如何实现 3.递归和循环的比较 4.代码示例 三、差分 1.差分的原理和特点 2.差分的实现 3.例题讲解 四、枚举 1.枚举算法介绍 2.解空间的类型 3. 循环枚举解…...

详解Rust标准库:VecDeque 队列

theme: github highlight: an-old-hope 查看本地官方文档 安装rust后运行 rustup doc查看The Standard Library即可获取标准库内容 std::connections::VecDeque定义 队列是遵循先入先出规则的线性数据结构&#xff0c;在内存中不一定连续 VecDeque定义&#xff1a;可增长…...

网络协议都有哪些?

网络协议是为计算机网络中进行数据交换而建立的规则、标准或约定的集合。以下是一些常见的网络协议&#xff1a; TCP/IP协议&#xff1a;传输控制协议/因特网互联协议&#xff0c;又名网络通讯协议&#xff0c;是Internet最基本的协议、Internet国际互联网络的基础。由网络层的…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

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…...