SpringMVC-拦截器

news2024/12/23 6:47:01

1,pringMVC-拦截器

对于拦截器这节的知识,我们需要学习如下内容:

  • 拦截器概念
  • 入门案例
  • 拦截器参数
  • 拦截器工作流程分析

1.1 拦截器概念

讲解拦截器的概念之前,我们先看一张图:

1630676280170

(1)浏览器发送一个请求会先到Tomcat的web服务器

(2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源

(3)如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问

(4)如果是动态资源,就需要交给项目的后台代码进行处理

(5)在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行

(6)然后进入到到中央处理器(SpringMVC中的内容),SpringMVC会根据配置的规则进行拦截

(7)如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果

(8)如果不满足规则,则不进行处理

(9)这个时候,如果我们需要在每个Controller方法执行的前后添加业务,具体该如何来实现?

这个就是拦截器要做的事。

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用:
    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行
    • 总结:拦截器就是用来做增强

看完以后,大家会发现

  • 拦截器和过滤器在作用和执行顺序上也很相似

所以这个时候,就有一个问题需要思考:拦截器和过滤器之间的区别是什么?

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

1630676903190

1.2 拦截器入门案例

1.2.1 环境准备

  • 创建一个Web的Maven项目

  • pom.xml添加SSM整合所需jar包

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.itheima</groupId>
      <artifactId>springmvc_12_interceptor</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <dependencies>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.0</version>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <configuration>
              <port>80</port>
              <path>/</path>
            </configuration>
          </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
      </build>
    </project>
    
    
  • 创建对应的配置类

    public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
        protected Class<?>[] getRootConfigClasses() {
            return new Class[0];
        }
    
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{SpringMvcConfig.class};
        }
    
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        //乱码处理
        @Override
        protected Filter[] getServletFilters() {
            CharacterEncodingFilter filter = new CharacterEncodingFilter();
            filter.setEncoding("UTF-8");
            return new Filter[]{filter};
        }
    }
    
    @Configuration
    @ComponentScan({"com.itheima.controller"})
    @EnableWebMvc
    public class SpringMvcConfig{
       
    }
    
  • 创建模型类Book

    public class Book {
        private String name;
        private double price;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Book{" +
                    "书名='" + name + '\'' +
                    ", 价格=" + price +
                    '}';
        }
    }
    
  • 编写Controller

    @RestController
    @RequestMapping("/books")
    public class BookController {
    
        @PostMapping
        public String save(@RequestBody Book book){
            System.out.println("book save..." + book);
            return "{'module':'book save'}";
        }
    
        @DeleteMapping("/{id}")
        public String delete(@PathVariable Integer id){
            System.out.println("book delete..." + id);
            return "{'module':'book delete'}";
        }
    
        @PutMapping
        public String update(@RequestBody Book book){
            System.out.println("book update..."+book);
            return "{'module':'book update'}";
        }
    
        @GetMapping("/{id}")
        public String getById(@PathVariable Integer id){
            System.out.println("book getById..."+id);
            return "{'module':'book getById'}";
        }
    
        @GetMapping
        public String getAll(){
            System.out.println("book getAll...");
            return "{'module':'book getAll'}";
        }
    }
    

最终创建好的项目结构如下:

1630677370998

1.2.2 拦截器开发

步骤1:创建拦截器类

让类实现HandlerInterceptor接口,重写接口中的三个方法。

@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    //原始方法调用前执行的内容
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
    }

    @Override
    //原始方法调用后执行的内容
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    @Override
    //原始方法调用完成后执行的内容
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

**注意:**拦截器类要被SpringMVC容器扫描到。

步骤2:配置拦截器类
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    }

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //配置拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );
    }
}
步骤3:SpringMVC添加SpringMvcSupport包扫描
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig{
   
}
步骤4:运行程序测试

使用PostMan发送http://localhost/books

1630678114224

如果发送http://localhost/books/100会发现拦截器没有被执行,原因是拦截器的addPathPatterns方法配置的拦截路径是/books,我们现在发送的是/books/100,所以没有匹配上,因此没有拦截,拦截器就不会执行。

步骤5:修改拦截器拦截规则
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    }

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //配置拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*" );
    }
}

这个时候,如果再次访问http://localhost/books/100,拦截器就会被执行。

最后说一件事,就是拦截器中的preHandler方法,如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。

步骤6:简化SpringMvcSupport的编写
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

此后咱们就不用再写SpringMvcSupport类了。

最后我们来看下拦截器的执行流程:

1630679464294

当有拦截器后,请求会先进入preHandle方法,

​ 如果方法返回true,则放行继续执行后面的handle[controller的方法]和后面的方法

​ 如果返回false,则直接跳过后面方法的执行。

1.3 拦截器参数

1.3.1 前置处理方法

原始方法之前运行preHandle

public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}
  • request:请求对象
  • response:响应对象
  • handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装

使用request对象可以获取请求数据中的内容,如获取请求头的Content-Type

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String contentType = request.getHeader("Content-Type");
    System.out.println("preHandle..."+contentType);
    return true;
}

使用handler参数,可以获取方法的相关信息

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HandlerMethod hm = (HandlerMethod)handler;
    String methodName = hm.getMethod().getName();//可以获取方法的名称
    System.out.println("preHandle..."+methodName);
    return true;
}

1.3.2 后置处理方法

原始方法运行后运行,如果原始方法被拦截,则不执行

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

前三个参数和上面的是一致的。

modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

因为咱们现在都是返回json数据,所以该参数的使用率不高。

1.3.3 完成处理方法

拦截器最后执行的方法,无论原始方法是否执行

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

前三个参数与上面的是一致的。

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。

这三个方法中,最常用的是preHandle,在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。

1.4 拦截器链配置

目前,我们在项目中只添加了一个拦截器,如果有多个,该如何配置?配置多个后,执行顺序是什么?

1.4.1 配置多个拦截器

步骤1:创建拦截器类

实现接口,并重写接口中的方法

@Component
public class ProjectInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...222");
        return false;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...222");
    }
}
步骤2:配置拦截器类
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Autowired
    private ProjectInterceptor2 projectInterceptor2;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
    }
}

步骤3:运行程序,观察顺序

1630680435269

拦截器执行的顺序是和配置顺序有关。就和前面所提到的运维人员进入机房的案例,先进后出。

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

1630680579735

preHandle:与配置顺序相同,必定运行

postHandle:与配置顺序相反,可能不运行

afterCompletion:与配置顺序相反,可能不运行。

这个顺序不太好记,最终只需要把握住一个原则即可:==以最终的运行结果为准

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

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

相关文章

字节青训前端笔记 | 响应式系统与 React

本节课为前端框架 React 的基础课程讲解 React的设计思路 UI编程的特点 状态更新的时候&#xff0c;UI不会自动更新&#xff0c;需要手动调用DOM接口进行更新欠缺基本的代码层面的封装和隔离&#xff0c;代码层面没有组件化UI之间的数据依赖关系&#xff0c;需要手动维护&am…

【程序人生 | 价值扳机】你的寒假自律第一步(建议收藏)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计专业大二本科在读&#xff0c;阿里云社区专家博主&#xff0c;华为云社区云享专家&#xff0c;CSDN SAP应用技术领域新兴创作者。   在学习工…

小技巧:Excel顽固的名称、引用冲突的解决

共享编辑、跨文档引用的不便 Excel 的共享文档多人编辑、跨文档引用等功能似乎很美好&#xff0c;实际用下来很成问题。 首先共享文档虽然用约定按标注责任人的方式由不同的人编辑不同的行避免的多人同时编辑一行的冲突&#xff0c;但是这通常是个大文件&#xff0c;经常(大概…

函数 C语言】

函数的声明和定义 函数间调用关系是&#xff0c;由于函数调用其他函数&#xff0c;替他函数也可以互相调用&#xff0c;同一个函数可以被一个或多个函数调用任意次。 先声明&#xff0c;后调用。 #include <stdio.h> //去标准库下找文件 #include "stdio.h"…

分件操作和IO

1.文件的路径如图:当我们打开此电脑后(windows系统),上面会显示我们当前的位置&#xff0c;点击之后会出现如图片中的一段字符&#xff0c;这段字符代表着当前你所处位置的路径。最开头的D&#xff1a;/d&#xff1a;是盘符&#xff0c;后面会用斜杠‘/’或者反斜杠‘\’分开,该…

MFC的使用

1.初使用的简单代码该程序包含两个代码 头文件mfc.h和mfc.cpp文件头文件mfc.h#pragma once #include<afxwin.h>class MyApp:public CWinApp//CWinApp应用程序类 { public://程序入口virtual BOOL InitInstance(); }; class MyFrame : public CFrameWnd//继承窗口框架类a …

Java_Git:2. 使用git管理文件版本

目录 1 创建版本库 1.1 使用GitBash 1.2 使用TortoiseGit 2 添加文件 2.1 添加文件过程 2.2 工作区和暂存区 3 修改文件 3.1 提交修改 3.2 查看修改历史 3.3 差异比较 3.4 还原修改 4 删除文件 5 案例&#xff1a;将java工程提交到版本库 5.1 复制文件到工作目录 …

论文阅读:Boosting 3D Object Detection by Simulating Multimodality on Point Clouds

Boosting 3D Object Detection by Simulating Multimodality on Point CloudsResponse DistillationSparse-Voxel DistillationVoxel-to-Point DistillationInstance DistillationlossExperiments稠密&#xff08;多模态、多帧&#xff09;信息->稀疏&#xff08;单模态点云…

【华为上机真题 2023】数组去重和排序 (华为机考真题)

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

2023/1/20 ES6基本语法学习

1 let 命令的解读 1 let 声明变量&#xff0c;没有变量提升 <script>// 不存在变量提升console.log(variable)let variable zhaoshuai-lc </script>2 作用域 全局作用域函数作用域&#xff1a;function() {}块级作用域&#xff1a;{} let 是一个块作用域 <…

Spring中涉及的设计模式总结

Spring中涉及的设计模式总结 1.简单工厂(非23种设计模式中的一种) 实例化阶段主要是通过反射或者CGLIB对bean进行实例化&#xff0c;在这个阶段Spring又给我们暴露了很多的扩展点&#xff1a; 实现方式&#xff1a;BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现…

【设计模式】结构型模式·装饰者模式

学习汇总入口【23种设计模式】学习汇总(数万字讲解体系思维导图) 写作不易&#xff0c;如果您觉得写的不错&#xff0c;欢迎给博主来一波点赞、收藏~让博主更有动力吧&#xff01; 一.概述 在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增…

2022年房地产投资退出方法和工具研究报告

第一章 房地产投资概况 房地产商品既是人们日常“衣食住行”中的一种必需品&#xff0c;又因保值增值的功能而具有很好的投资品属性。房地产投资是以房地产为对象&#xff0c;为获得预期效益而对土地和房地产开发、房地产经营&#xff0c;以及购置房地产等进行的投资。 房地产…

深度学习 GNN图神经网络(二)PyTorch Geometric(PyG)安装

一、前言 我们使用torch_geometric库来实现图神经网络的编码&#xff0c;因为它与PyTroch天然集成。本文介绍了PyTorch Geometric&#xff08;PyG&#xff09;的安装与测试。 二、安装 首先打开官方的安装说明文档&#xff1a;https://pytorch-geometric.readthedocs.io/en/…

蓝桥杯 stm32 LCD显示及 数据格式化

文章代码使用 HAL 库。 文章目录前言一、LCD 原理图&#xff1a;二、LCD 基本函数&#xff1a;1.LCD 清屏函数&#xff1a;LCD_Clear ( u16 Color )&#xff1b;2. 显示一行字符串&#xff1a;LCD_DisplayStringLine(u8 Line, u8 *ptr)&#xff1b;3.设置字符背景色&#xff1a…

switch自制软件开发环境搭建

参考: https://switch.homebrew.guide/ https://switchbrew.org/wiki/Main_Page https://www.bilibili.com/video/BV133411Q77X/?spm_id_from333.788&vd_sourcec5c272e9490d8bf475c8204462fc26e7 1.开发环境 开发机 -> 虚拟机 ubuntu22.04 设备 -> 破解switch 大…

Ubuntu20.04系统WineHQ7.0安装微信

提供3种Ubuntu系统安装微信的方法&#xff0c;在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信&#xff1a;ubuntu20.04安装最新版微信--可以支持微信最新版&#xff0c;但是适配的不是特别好&#xff1b;比如WeChartOCR.exe 报错。2. 原生微信安装&#xff1a;linux系统下的微信…

[电商实时数仓] 数据仓库建模过程分析

文章目录1.数据仓库概述1.1 数据仓库概念1.2 数据仓库核心架构2.数据仓库建模概述2.1 数据仓库建模的意义2.2 数据仓库建模方法论2.2.1 ER模型2.2.2 维度模型3.维度建模理论之事实表3.1 事实表概述3.2 事实表分类3.3 事务事实表4.维度建模理论之维度表5.数据仓库设计5.1 数据仓…

[前端笔记——HTML 表格] 8.HTML 表格

[前端笔记——HTML 表格] 8.HTML 表格1.HTML 表格基础1.1 什么是表格&#xff1f;1.2 创建表格&#xff1a;2.HTML 表格高级特性和无障碍2.1 使用<caption>为表格增加一个标题2.2 添加<thead>,<tfoot>和<tbody>结构2.3 嵌套表格2.4 对于视力受损的用户…

第五层:C++中的运算符重载

文章目录前情回顾运算符重载概念为什么会出现运算符重载运算符重载中函数名格式加减运算符重载作用实现左移运算符重载作用左移运算符是什么&#xff1f;实现递增递减运算符作用实现前置后置赋值运算符重载关系运算符重载作用实现函数调用运算符重载第二种重载掌握&#xff01;…