Java开发学习----拦截器(Interceptor)详细解析

article/2025/10/20 11:25:55

一、拦截器概念

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

(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的访问进行增强

二、拦截器入门案例

2.1 环境准备

  • 创建一个Web的Maven项

  • pom.xml添加所需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[]{"/"};}
    ​//乱码处理@Overrideprotected 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;}
    ​@Overridepublic String toString() {return "Book{" +"书名='" + name + '\'' +", 价格=" + price +'}';}
    }
  • 编写Controller

    @RestController
    @RequestMapping("/books")
    public class BookController {
    ​@PostMappingpublic 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'}";}
    ​@PutMappingpublic 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'}";}
    ​@GetMappingpublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
    }

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

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 {@Autowiredprivate ProjectInterceptor projectInterceptor;
​@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");}
​@Overrideprotected 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

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

步骤5:修改拦截器拦截规则

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Autowiredprivate ProjectInterceptor projectInterceptor;
​@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");}
​@Overrideprotected 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 {@Autowiredprivate ProjectInterceptor projectInterceptor;
​@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");}
}

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

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

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

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

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

三、拦截器参数

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;
}

3.2 后置处理方法

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

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

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

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

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

3.3 完成处理方法

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

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

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

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理,该参数的使用率也不高。

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

四、拦截器链配置

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

4.1 配置多个拦截器

步骤1:创建拦截器类

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

@Component
public class ProjectInterceptor2 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...222");return false;}
​@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...222");}
​@Overridepublic 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 {@Autowiredprivate ProjectInterceptor projectInterceptor;@Autowiredprivate ProjectInterceptor2 projectInterceptor2;
​@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");}
}

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

拦截器执行的顺序是和配置顺序有关。先进后出。

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

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

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

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

  • 当配置多个拦截器时,形成拦截器链

  • 拦截器链的运行顺序参照拦截器添加顺序为准

  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行

  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作


http://chatgpt.dhexx.cn/article/Vtj8oDjI.shtml

相关文章

JAVA三大器之拦截器

1&#xff0c;拦截器的概念 java里的拦截器是动态拦截Action调用的对象&#xff0c;它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码&#xff0c;也可以在一个Action 执行前阻止其执行&#xff0c;同时也提供了一种可以提取Action中可重用部分代码的方式。…

java之拦截器

java里的拦截器是动态 拦截action的web请求&#xff0c;而过滤器能够进行系统级别的过滤&#xff0c;即能够过滤所有的web请求。从这可以看出拦截器是有一定的局限性的。拦截器是基于jdk实现的动态代理&#xff0c;拦截器是动态拦截action调用的对象&#xff0c; 拦截器可以使得…

Java三大器之拦截器(Interceptor)的实现原理及代码示例

前言&#xff1a;前面2篇博客&#xff0c;我们分析了Java中过滤器和监听器的实现原理&#xff0c;今天我们来看看拦截器。 1&#xff0c;拦截器的概念 java里的拦截器是动态拦截Action调用的对象&#xff0c;它提供了一种机制可以使开发者在一个Action执行的前后执行一段代…

Java 拦截器

一、引言 既然要用拦截器&#xff0c;首先先得简单了解一下什么是拦截器&#xff1a; 概念&#xff1a;java里的拦截器是动态拦截Action调用的对象&#xff0c;它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码&#xff0c;也可以在一个Action执行前阻止其执行…

VirtualAPK:滴滴 Android 插件化的实践之路

作者简介&#xff1a; 任玉刚&#xff0c;滴滴出行 Android 技术专家&#xff0c;《Android 开发艺术探索》作者&#xff0c;插件化框架 dynamic-load-apk 的发起者&#xff0c;CSDN 移动开发博客专家&#xff0c;曾当选 CSDN 2014、2015年度十大博客之星。热爱技术&#xff0c…

Unity刚体

1、Dynamic&#xff1a;动态类型 受重力和力的影响移动和旋转 Material&#xff1a; 物理材质&#xff0c;在刚体上设置了物理材质&#xff0c;如果子物体有碰撞器但是没有设置材质则会通用刚体的物理材质 如果不设置&#xff0c;将使用在Physics 2D窗口中设置的默认材质(Physi…

android view 的测量过程

参考任玉刚主席的《android开发艺术探索》所写。

2017年终总结,开始写博客的第一年

结束校园生活&#xff0c;开始工作 今年是我开始工作的第一年&#xff0c;前半个学期实习阶段&#xff0c;开发了三个上线的应用&#xff0c;之前在学校的时候&#xff0c;做过不少练手的项目&#xff0c;有时心血来潮&#xff0c;还做了一些自己认为有趣的项目&#xff0c;但是…

阿里组织新调整:张勇兼任云业务总裁“敏捷组织”是内核

雷递网 雷建平 12月29日 岁末年初之际&#xff0c;在小米进行管理层调整后&#xff0c;阿里巴巴也进行了新一轮调整。 12月29日&#xff0c;阿里巴巴集团董事会主席兼CEO张勇发布内部邮件&#xff0c;宣布张建锋不再担任阿里云总裁&#xff0c;继续担任阿里达摩院院长&#xff…

鲲鹏院武志强课题组诚聘博士后

诚聘英才 Recruitment Season 佛山鲲鹏现代农业研究院 研究院简介 佛山鲲鹏现代农业研究院&#xff08;以下简称“鲲鹏院”&#xff09;成立于2021年&#xff0c;由中国农业科学院与佛山市人民政府、南海区人民政府依托中国农业科学院&#xff08;深圳&#xff09;农业基因组研…

刚体

概述 在整个 Unity 物理系统中&#xff0c;最重要概念就是刚体 Rigidbody。 刚体是物理学中的概念&#xff0c;它是指在运动中和受力后&#xff0c;形状和大小不变&#xff0c;并且内部各点相对位置不变的物体。刚体是一种为了方便物理计算而提出的理想化模型&#xff0c;在不…

技术人员如何从容转型项目经理?

科技在发展&#xff0c;时代在进步&#xff0c;项目越来越复杂&#xff0c;越来越多的技术人员面临技术转型&#xff0c;那么&#xff0c;如何成功转型成了众多技术人员面临的新挑战。 首先我们必须要搞清楚&#xff0c;为什么需要技术人员转型项目经理&#xff1f;项目经理不…

阿里云杨国彦:云上护航,陪伴成长

以下整理自杨国彦在云栖大会“云上成就创新梦想”论坛中发表的《云上护航&#xff0c;陪伴成长》的主题演讲&#xff09; 11月5日&#xff0c;以“云上成就创新梦想”为主题的中小企业云上创新论坛在浙江杭州云栖小镇举行&#xff0c;论坛聚集政府、资本、媒体、机构等相关领导…

滴滴技术专家任玉刚:让你的职业迷茫从哪来回哪去

今天给大家推荐的是《Android开发艺术探索》的作者&#xff08;滴滴技术专家&#xff09;任玉刚老师的直播课&#xff0c;感兴趣的同学可以通过文末的方式参与本次活动&#xff08;喜欢的同学欢迎转发&#xff09;。 我是任玉刚&#xff0c; 我来我想说。 01 收到过无数同学的…

从菜鸟到资深工程师的进阶之路

专访任玉刚&#xff1a;从菜鸟到资深工程师的进阶之路 发表于 2015-12-22 08:25| 11131次阅读| 来源 CSDN| 31 条评论| 作者 夏夏 专访 iOS Android 任玉刚 开发者 CSDN博客 allowtransparency"true" frameborder"0" scrolling"no" src"h…

kafka sasl_ssl配置

一、切换到存储证书的路径 我这里在家目录中的创建了ssl文件夹 mkdir ssl && cd ssl 二、生成服务端密钥库 keytool -keystore server.keystore.jks -alias localhost -validity 365 -genkey验证证书&#xff1a; keytool -list -v -keystore server.keystore.jks …

KAFKA SASL配置 记录

kafka配置SASL 第1步 将kafka_client_jaas.conf/kafka_server_jaas.conf/kafka_zoo_jaas.conf三个文件放入kafka的config文件夹中&#xff0c;文件中配置用户&#xff0c;superadmin用户必须配置。 kafka_client_jaas.conf内容如下 KafkaClient { …

WIN10 VS2019 编译Cyrus SASL

环境 下载安装Visual Studio 2019 安装时在【工作负载】必须勾选【使用C的桌面开发】下载cyrus-sasl源码 从Github上clone或者下载zip包&#xff0c;我本来是需要2.1.26&#xff0c;但是从从https://www.cyrusimap.org/releases/下载对应版本的源码包编译都有问题&#xff0c;…

Kafka3.0 SASL安全认证

下面主要介绍Kafka两种认证方式 kafka验证方式&#xff1a; SASL/PLAIN&#xff1a;不能动态添加用户配置文件写死账号密码 SASL/SCRAM&#xff1a; 可以动态的添加用户 SASL/PLAIN方式 cd /usr/local/kafka/kafka_2.12-3.0.1/bin/ ## 复制一份saslcp kafka-server-start.…

集成OpenLDAP与Kerberos实现统一认证(三):基于SASL/GSSAPI深度集成

文章目录 1. 写作背景2. 既定目标3. 重要概念3.1 SASL3.2 GSSAPI3.3 SASL与GSSAPI的关系3.4 saslauthd3.5 Kerberos化 4. 核心原理4.1 基于SASL/GSSAPI实现Kerberos账号登录OpenLDAP4.2 基于olcAuthzRegexp规则映射Kerberos与OpenLDAP账号4.3 基于saslauthd进行委托认证 5. 安装…