13SpringMVC中拦截器的配置(拦截规则)和多个拦截器的preHandle,postHandle执行顺序原理详解

news2024/11/16 16:18:59

拦截器

Servlet中的过滤器的实现及其原理,参考文章

配置一个拦截器

SpringMVC中请求的处理流程: 用户请求—>listener—>filter—>DispatcherServlet—>filter—>preHandle—>controller—>postHandle

第一步: 编写一个Java类实现HandlerInterceptor(HandlerInterceptorAdapter已过时)接口,由于接口中的方法都有默认的方法体,我们可以根据需求实现方法

方法名功能
boolean preHandle(processedRequest, response)在控制器方法执行之前执行 , 返回true表示放行即调用控制器方法 , 返回false表示拦截即不调用控制器方法
postHandle(processedRequest, response, mv)在控制器方法执行之后执行
afterComplation()在控制器方法执行之后,且模型数据都被渲染到视图上后执行
// 将当前bean加入IoC容器,这样就可以在配置文件中引用当前的bean作为拦截器
@Component
public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor-->preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor-->postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor-->afterCompletion");
    }
}

第二步: 在SpringMVC的配置文件中将实现了HandlerInterceptor接口的类设置为拦截器并设置拦截的规则

  • 通过ref或bean标签可以设置拦截器但是不能设置拦截规则,此时默认拦截DispatcherServlet处理的所有的请求
  • 通过mvc:interceptor标签可以设置拦截器同时设置拦截的规则即拦截哪些请求或放行哪些请求
  • 使用view-controller标签配置的视图控制器对应的跳转页面的请求只要符合拦截器拦截的规则也会被拦截
标签名描述
bean标签的class属性根据全类名告诉SpringMVC哪个类是拦截器
ref标签的bean属性引用IoC容器中的某个bean的Id作为拦截器,所以需要保证容器中注册了对应的bean
mvc:mapping设置需要拦截的请求路径
/**表示拦截所有请求,/* 表示拦截上下文路径后的一层路径的请求
mvc:exclude-mapping设置排除即不需要拦截的请求路径
<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
     <!--扫描组件-->
    <context:component-scan base-package="com.atguigu.mvc"></context:component-scan>
    <!--使用view-controller标签配置的视图控制器对应的跳转页面的请求也会被拦截-->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <mvc:annotation-driven />
    <!--配置拦截器-->
    <mvc:interceptors>
        <!--根据全类名将某个类设置为拦截器-->
        <bean class="com.atguigu.mvc.interceptors.FirstInterceptor"></bean>
        <!--引用IoC容器中的某个bean的Id作为拦截器,需要保证容器中注册了对应的bean-->
        <ref bean="firstInterceptor"></ref>
        <!--设置拦截器及拦截的规则-->
        <mvc:interceptor>
            <!--配置需要拦截的请求路径-->
        	<mvc:mapping path="/**"/>
            <!--配置不需要拦截的请求路径-->
            <mvc:exclude-mapping path="/"/>
            <!--引用容器中的某个bean作为拦截器-->
            <ref bean="firstInterceptor"></ref>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

第三步: 编写处理请求的控制器方法,测试拦截器方法的执行顺序,只要请求符合拦截的规则,拦截器中重写的方法就一定会执行,无论有没有匹配请求的控制器方法

<a th:href="@{/testInterceptor}">测试拦截器</a>
@Controller
public class TestController {
    @RequestMapping("/testInterceptor")
    @ResponseBody
    public String testInterceptor(){
        return "success";
    }
}
FirstInterceptor-->preHandle
success
FirstInterceptor-->postHandle
FirstInterceptor-->afterCompletion

配置多个拦截器

多个拦截器的执行顺序和在SpringMVC的配置文件的中配置的拦截器顺序以及拦截器的preHandle()方法的返回值有关

在这里插入图片描述

第一步: 创建一个拦截器类并且preHandle方法的返回值是false

// 将当前bean加入IoC容器,这样就可以在配置文件中引用当前的bean作为拦截器
@Component
public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor-->preHandle");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondInterceptor-->postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondInterceptor-->afterCompletion");
    }
}

第二步: 在SpringMVC的配置文件中设置多个拦截器及其拦截规则

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--扫描组件-->
    <context:component-scan base-package="com.atguigu.mvc"></context:component-scan>
    <!--配置视图控制器-->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <mvc:annotation-driven />
    <!--配置拦截器-->
    <mvc:interceptors>
        <ref bean="firstInterceptor"></ref>
        <ref bean="secondInterceptor"></ref>
    </mvc:interceptors>
</beans>

第三步: 编写控制器方法测试多个拦截器中方法的执行顺序

Controller
public class TestController {
    @RequestMapping("/testInterceptor")
    @ResponseBody
    public String testInterceptor(){
        return "success";
    }
}
FirstInterceptor-->preHandle
SecondInterceptor-->preHandle
success
FirstInterceptor-->afterCompletion

拦截器执行顺序的原理

mappedHandler是控制器执行链,包含控制器方法,拦截器集合(自定义的和SpringMvc提供的),拦截器的索引

正序执行所有拦截器的prehandle方法

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    // 如果有一个拦截器的prehandle方法返回fasle,直接终止当前方法即剩下的拦截器和对应控制器的方法都不会执行
    return;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 遍历拦截器集合中的每一个拦截器
    for(int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
        // 判断当前拦截器的prehandle方法的返回值
        if (!interceptor.preHandle(request, response, this.handler)) {
            // 如果prehandle方法返回false,调用当前拦截器的afterComplation方法
            this.triggerAfterCompletion(request, response, (Exception)null);
      		// 返回false后剩下的拦截器和对应控制器的方法都不会执行
            return false;
        }
        // interceptorIndex的值是prehandle方法返回的是false的某个拦截器之前的拦截器的索引
        this.interceptorIndex = i;
    }
    // 返回true后才会执行下一个拦截器或对应控制器的方法
    return true;
}

反序执行所有拦截器的posthandle方法

mappedHandler.applyPostHandle(processedRequest, response, mv);

void applyPostHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // i的初始值是拦截器集合中的最后一个拦截器的索引
    for(int i = this.interceptorList.size(); i >= 0; i--) {
        HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
        interceptor.postHandle(request, response, this.handler,mv);    
    }
}

反序执行所有拦截器的aftercompletion方法

if(mappedHandler != null){
	mappedHandler.triggerAfterCompletion(request, response, (Exception)null);      
}

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // i的初始值是最后一个prehandle方法返回的是false的某个拦截器之前的拦截器的索引
    for(int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
        interceptor.afterCompletion(request, response, this.handler,ex);    
    }
}

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

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

相关文章

基于SpringBoot的在线教育系统

目录 前言 一、技术栈 二、系统功能介绍 普通管理员管理 课程管理员管理 课程信息管理 用户信息管理 讲师信息管理 课程信息查看 讲师信息查看 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c…

EDUSRC-记一个SHELL捡漏

目录 ​编辑 Jenkins - println绕过到shell命令执行 语法 Jenkins未授权访问(捡漏失败) Jenkins捡漏 弱口令 脚本执行(println失败) CHATGPT调教绕过 hack渗透视频教程&#xff0c;扫码免费领 Jenkins - println绕过到shell命令执行 语法 org"China Education and…

【excel技巧】如何在Excel表格中添加选项按钮?

不知道大家是否会9遇到需要勾中选项的情况&#xff0c;我们可以在电子表格中制作出可以勾选、选中的选项按钮&#xff0c;今天我们一起学习一下设置方法。 首先&#xff0c;我们需要先在excel工具栏中添加一个功能模块&#xff1a;开发工具 依次点击excel中的文件 – 选项 –…

【问题思考总结】二次型和二次曲面的关系【常数项的改变对曲面的影响】【图文】

问题 今天做到一个题的时候发现&#xff0c;之前记的结论记错了&#xff0c;一个方程本来应该是双叶双曲面我记得&#xff0c;结果答案竟然是圆锥面&#xff0c;后来发现原因是常数项等于0或者不等于0的差别。因此&#xff0c;就这个问题我们来通过图文的方式探讨一下两种情况…

【广州华锐互动】VR建筑施工事故体验:提高工人安全意识和责任感

VR建筑施工事故体验的意义在于通过模拟真实场景和情况&#xff0c;帮助人们更好地理解建筑施工中的安全问题&#xff0c;并提供一种安全、有效的方式来学习和掌握安全技能。 建筑施工是一项高风险的工作&#xff0c;涉及各种复杂的工作环境和操作过程。在现实中&#xff0c;建筑…

剧院建筑三维可视化综合管控平台提高安全管理效率

随着数字孪生技术的高速发展&#xff0c;智慧楼宇也被提上日程&#xff0c;以往楼宇管理存在着设备故障排查困难、能源浪费与管理不足、安全性和风险高等问题&#xff0c;而智慧楼宇数字孪生可视化中控平台&#xff0c;打造智慧楼宇管理一张图&#xff0c;实现了智慧建筑和楼宇…

资深8年测试整理,接口测试必备-加密与签名,让你不再走弯路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、接口加密解密 …

四.镜头知识之放大倍率

四.镜头知识之放大倍率 文章目录 四.镜头知识之放大倍率4.0 前言4.1 镜头的光学放大倍率的计算方法4.2 显示器的电子放大倍率4.2.1 智能硬件产品的显示放大倍率计算案例 4.3 系统放大倍率4.4 智能硬件产品的系统放大倍率计算案例4.4 智能硬件产品的系统放大倍率计算案例 4.0 前…

成绩分析数据的重要性,老师们一定要看过来!

成绩分析数据在教育领域中具有重要性&#xff0c;对于教师们来说是一项必不可少的工具。下面将详细介绍成绩分析数据的重要性&#xff0c;并强调为什么老师们一定要关注和利用这些数据。 **1. 了解学生的学习情况** 成绩分析数据可以帮助教师全面了解学生的学习情况。通过分析…

Jenkins发布失败记录

Exception when publishing, exception message [Exec exit status not zero. Status [127]] 见链接&#xff1a;Jenkins发布时常见异常&#xff08;持续更新...&#xff09;_exception when publishing, exception message [exec_码农StayUp的博客-CSDN博客 The remote end hu…

mysql sql语句遍历树结构

mysqlsql语句遍历树结构 MySQL SQL语句遍历树结构实现步骤 理解树结构和遍历算法 在开始之前&#xff0c;我们首先需要了解什么是树结构以及如何遍历树结构。树结构是一种常用的数据结构&#xff0c;由各个节点和节点之间的关系构成。树结构的一个重要应用是表示具有层级关系…

winscope使用方法

Ubuntu下Android T的winscope工具使用方法 1. 在Android的项目源码中&#xff0c;prebuilts/misc/common/winscope目录下 直接使用chrome浏览器打开文件winscope.html 2. 可能会提示adb问题 进入目录development/tools/winscope/adb_proxy&#xff0c;有文件winscope_proxy.…

地球系统模式的应用与进阶丨CESM丨Linux丨CLM丨代码修改等

目录 第一部分 运行前的准备 第二部分 Linux系统及编译 第三部分 CESM原理、结构 第四部分 CESM程序获取、结构及其功能 第五部分 CESM 移植、安装及快速运行 第六部分 CESM 配置选项及数据文件制备 第七部分 CESM单模块运行——以CLM为例 第八部分 CESM 的部分耦合运行…

TOGAF(企业架构)

TOGAF 核心概念&#xff08;官方原版&#xff09; 什么是TOGAF&#xff1f; TOGAF?是一种经验证的企业架构方法和框架&#xff0c;被世界领先的组织用于提高业务效率。它是一个企业架构标准&#xff0c;确保企业架构专业人员之间的标准、方法和通信一致&#xff0c;以便我们…

CentOS 7 服务器上创建新用户及设置用户密码有效期

一、创建用户 1、以 root 用户身份登录到 CentOS 服务器 2、运行以下命令以创建新用户&#xff1a; useradd -m -s /bin/bash username其中&#xff0c;username 是您要创建的新用户的用户名。该命令将创建一个新用户并为其分配一个主目录。3、运行以下命令以设置新用户的密码…

泛微低代码平台应用合集,开箱即用,助力组织快速数字化

随着数字化进程的不断深入&#xff0c;各行业对数字化转型的认知不断加深&#xff0c;组织数字化的步伐越来越快。 数字化对组织创新能力加强、生产效率提升、运营成本下降等方面有显著成效&#xff0c;但是组织数字化转型之路面临不少挑战&#xff1a; 数字化挑战 1、数字化…

Android终极大招之全面取代drawble文件实现View圆角背景样式的新方案

简介 最近一直忙于音视频SDK的开发&#xff0c;遇到很多问题&#xff0c;简单来说&#xff0c;就是怎么让别人接入SDK时越简单越好。相信大多数Android开发都会遇到一个场景&#xff0c;给TextView或Button添加背景颜色&#xff0c;修改圆角&#xff0c;描边等需求。一看到这样…

纯干货,怎样用手机提取歌曲伴奏?

提取歌曲伴奏这个需求还是很大的&#xff0c;要想去掉原声只留伴奏&#xff0c;只要使用音分轨人声分离软件中的【音频提取伴奏】功能就能解决这个问题了&#xff0c;下面就给大家具体演示一下操作步骤&#xff01; 第一步&#xff1a;打开【音分轨】APP&#xff0c;进入首页点…

电脑提示Explorer.exe系统错误该怎么办?

平时我们在使用电脑时&#xff0c;系统有时会提示Explorer.exe系统错误&#xff0c;很多用户在遇到这类问题时不知道该怎么办。遇到Explorer.exe系统错误&#xff0c;该怎么办呢&#xff1f;下面我们一起来了解一下。 怎么修复Explorer.exe系统错误&#xff1f; Explorer.exe是…

考研:数学二做题套路

文章中的□&#xff0c;代表广义化&#xff0c;就是什么都可以往里面填&#xff08;但是每个公式中&#xff0c;□的值必须相同&#xff0c;假设一个公式中有两个□&#xff0c;不可以第一个填x第二个填y&#xff09; 每个类型&#xff0c;都会先总结公式和套路&#xff0c;然…