【拦截器Interceptor】springboot拦截器的使用和原理

news2024/12/23 23:25:43

【拦截器Interceptor】springboot拦截器的使用和原理

  • 【一】拦截器简介
    • (1)简介
    • 【2】作用
  • 【二】实现步骤
    • 【1】自定义拦截器,实现拦截器接口HandlerInterceptor
    • 【2】将拦截器添加到容器当中
    • 【3】配置拦截器的拦截规则
    • 【4】拦截器的执行顺序
  • 【三】拦截器参数
    • 【1】获取请求头 request.getHeader
    • 【2】Object handler 是什么参数
    • 【3】ModelAndView modelAndView
    • 【4】Exception ex
    • 【5】HttpServletRequest request
    • 【6】HttpServletResponse response
  • 【四】多拦截器执行顺序
  • 【五】拦截器和过滤器的区别
  • 【六】拦截器的实际案例
    • 【1】拦截器实现权限控制
    • 【2】拦截器实现日志记录
    • 【3】拦截器实现接口幂等性校验
  • 【七】拦截器的性能优化和常见问题
    • 【1】拦截器性能优化策略
    • 【2】拦截器的常见问题和解决方案
  • 【八】拦截器的原理和源码分析

【一】拦截器简介

(1)简介

拦截器就是用来拦截指定的请求,在请求前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。

拦截器最常用的使用场景就是认证,在请求开始之前,对当前请求进行权限校验,如果当前请求用户具备操作当前请求的权限,就对当前请求放行,允许执行业务逻辑;否则拦截当前请求,直接返回。

拦截器的功能通过网关也都是可以实现的,但是一些单体架构还是需要使用拦截器。

【2】作用

拦截器可以用于实现以下功能:
(1)权限控制:拦截器可以在请求到达处理器之前进行权限验证,从而实现对不同用户的访问控制。
(2)日志记录:拦截器可以在请求处理过程中记录请求和响应的详细信息,便于后期分析和调试。
(3)接口幂等性校验:拦截器可以在请求到达处理器之前进行幂等性校验,防止重复提交。
(4)数据校验:拦截器可以在请求到达处理器之前对请求数据进行校验,确保数据的合法性。
(5)缓存处理:拦截器可以在请求处理之后对响应数据进行缓存,提高系统性能。

【二】实现步骤

【1】自定义拦截器,实现拦截器接口HandlerInterceptor

要在SpringBoot中实现拦截器,首先需要创建一个类并实现HandlerInterceptor接口。HandlerInterceptor接口包含以下三个方法:
(1)preHandle:在请求到达处理器之前执行,可以用于权限验证、数据校验等操作。如果返回true,则继续执行后续操作;如果返回false,则中断请求处理。
(2)postHandle:在处理器处理请求之后执行,可以用于日志记录、缓存处理等操作。
(3)afterCompletion:在视图渲染之后执行,可以用于资源清理等操作。

/**
 * 登录检查
 * 1.配置到拦截器要拦截哪些请求
 * 2.把这些配置放在容器中
 *
 * 实现HandlerInterceptor接口
 */
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目标方法执行之前
     * 登录检查写在这里,如果没有登录,就不执行目标方法
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取进过拦截器的路径
        String requestURI = request.getRequestURI();
 
        // 登录检查逻辑
        HttpSession session = request.getSession();
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser !=null){
            // 放行
            return true;
        }
        // 拦截   就是未登录,自动跳转到登录页面,然后写拦截住的逻辑
        return false;
    }
 
    /**
     * 目标方法执行完成以后
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
 
    /**
     * 页面渲染以后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

【2】将拦截器添加到容器当中

要让拦截器生效,需要将其注册到InterceptorRegistry中。这可以通过实现WebMvcConfigurer接口并重写addInterceptors方法来实现。以下是一个简单的注册示例:

@Configuration
//定制SpringMVC的一些功能都使用WebMvcConfigurer
public class AdminWebConfig implements WebMvcConfigurer {
 
    /**
     * 配置拦截器
     * @param registry 相当于拦截器的注册中心
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
				//下面这句代码相当于添加一个拦截器   添加的拦截器就是我们刚刚创建的
         registry.addInterceptor(new LoginInterceptor())
								//addPathPatterns()配置我们要拦截哪些路径 addPathPatterns("/**")表示拦截所有请求,包括我们的静态资源
                 .addPathPatterns()
								//excludePathPatterns()表示我们要放行哪些(表示不用经过拦截器)
								//excludePathPatterns("/","/login")表示放行“/”与“/login”请求
								//如果有静态资源的时候可以在这个地方放行
                 .excludePathPatterns("/","/login");
    }
}

【3】配置拦截器的拦截规则

在注册拦截器时,可以通过addPathPatterns和excludePathPatterns方法来配置拦截器的拦截规则。addPathPatterns方法用于指定需要拦截的请求路径,excludePathPatterns方法用于指定不需要拦截的请求路径。以下是一个配置示例:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/register");
    }
}

在上述示例中,我们配置了拦截器拦截所有请求,但排除了登录和注册请求。

【4】拦截器的执行顺序

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

【三】拦截器参数

【1】获取请求头 request.getHeader

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

在这里插入图片描述
在这里插入图片描述

【2】Object handler 是什么参数

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

使用PostMan发送请求后,控制台出现下面这个样子
在这里插入图片描述
这个参数有什么用?被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String contenType = request.getHeader("Content-Type");
//        System.out.println(handler);
        HandlerMethod hm = (HandlerMethod)handler;
//        通过hm.getMethod()就可以拿到原始执行的对象,拿到这个对象就可以进行反射
         hm.getMethod();
        System.out.println("preHandle..."+contenType);
//      放行
        return true;
    }

在这里插入图片描述

【3】ModelAndView modelAndView

封装了SpringMVC进行页面跳转的相关数据,但是我们现在都是返回JSON

【4】Exception ex

通过这个ex可以拿到原始的程序执行过程中出现的异常的

假设controller层抛了异常,在这里是可以拿到异常对象的,但是我们有异常处理机制,所以这里就没有那么大的需求了

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

【5】HttpServletRequest request

request:请求对象

【6】HttpServletResponse response

response:响应对象

【四】多拦截器执行顺序

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

准备第二个拦截器
在这里插入图片描述
注册

 
@Configuration
//定制SpringMVC的一些功能都使用WebMvcConfigurer
public class AdminWebConfig implements WebMvcConfigurer {
 
    /**
     * 配置拦截器
     * @param registry 相当于拦截器的注册中心
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//       下面这句代码相当于添加一个拦截器   添加的拦截器就是我们刚刚创建的
         registry.addInterceptor(new LoginInterceptor())
//       addPathPatterns()配置我们要拦截哪些路径 addPathPatterns("/**")表示拦截所有请求,包括我们的静态资源
                 .addPathPatterns()
//       excludePathPatterns()表示我们要放行哪些(表示不用经过拦截器)
//       excludePathPatterns("/","/login")表示放行“/”与“/login”请求
//       如果有静态资源的时候可以在这个地方放行
                 .excludePathPatterns("/","/login");
 
//       第二个拦截器
        registry.addInterceptor(new LoginInterceptor2()).addPathPatterns("/books");
    }
}

那当我们配置了两个拦截器以后,会有一个执行顺序

拦截器链的运行顺序参照拦截器添加顺序为准,下面就是三个拦截器时的执行顺序

拦截器链的运行顺序参照拦截器添加顺序为准,下面就是三个拦截器时的执行顺序

在这里插入图片描述

【五】拦截器和过滤器的区别

拦截器和过滤器都可以实现对请求和响应的拦截和处理,但它们之间存在以下区别:
(1)执行顺序:过滤器在拦截器之前执行,拦截器在处理器之前执行。
(2)功能范围:过滤器可以对所有请求进行拦截,而拦截器只能对特定的请求进行拦截。
(3)生命周期:过滤器由Servlet容器管理,拦截器由Spring容器管理。
(4)使用场景:过滤器适用于对请求和响应的全局处理,拦截器适用于对特定请求的处理。

【六】拦截器的实际案例

【1】拦截器实现权限控制

拦截器可以在请求到达处理器之前进行权限验证,从而实现对不同用户的访问控制。以下是一个简单的权限控制示例:

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
}

在上述示例中,我们在preHandle方法中检查用户是否已登录,如果未登录,则重定向到登录页面并中断请求处理。

【2】拦截器实现日志记录

拦截器可以在请求处理过程中记录请求和响应的详细信息,便于后期分析和调试。以下是一个简单的日志记录示例:

public class LogInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        logger.info("Request URI: {}", request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        logger.info("Response status: {}", response.getStatus());
    }
}

在上述示例中,我们在preHandle方法中记录请求URI,在postHandle方法中记录响应状态。

【3】拦截器实现接口幂等性校验

拦截器可以在请求到达处理器之前进行幂等性校验,防止重复提交。以下是一个简单的幂等性校验示例:

public class IdempotentInterceptor implements HandlerInterceptor {

    private static final String IDEMPOTENT_TOKEN = "idempotentToken";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader(IDEMPOTENT_TOKEN);
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("Idempotent token is missing");
        }
        if (!checkIdempotentToken(token)) {
            throw new RuntimeException("Duplicate request");
        }
        return true;
    }

    private boolean checkIdempotentToken(String token) {
        // Check the token in the cache or database
        // Return true if the token is valid, false otherwise
    }
}

在上述示例中,我们在preHandle方法中检查请求头中的幂等性令牌,如果令牌无效,则抛出异常并中断请求处理。

【七】拦截器的性能优化和常见问题

【1】拦截器性能优化策略

拦截器在请求处理过程中可能会影响系统性能,以下是一些性能优化策略:
(1)减少拦截器数量:尽量将相关功能集中到一个拦截器中,避免创建过多的拦截器。
(2)精确配置拦截规则:通过addPathPatterns和excludePathPatterns方法精确配置拦截规则,避免不必要的拦截。
(3)使用异步处理:在拦截器中使用异步处理,避免阻塞请求处理过程。
(4)使用缓存:在拦截器中使用缓存,减少对数据库或其他资源的访问。

【2】拦截器的常见问题和解决方案

拦截器是一种用于处理请求和响应的中间件,它可以在请求到达目标处理器之前或响应返回客户端之前执行一些操作。然而,在实际使用过程中,我们可能会遇到一些问题,如拦截器不生效、执行顺序错误或影响性能等。接下来,我们将逐一分析这些问题的原因及解决方法。

(1)拦截器不生效:拦截器不生效的可能原因有很多,其中最常见的包括拦截器未注册到InterceptorRegistry、拦截规则配置错误等。为了解决这个问题,我们需要首先检查拦截器是否已经正确注册到InterceptorRegistry中,然后再检查拦截规则是否配置正确。如果发现问题,需要及时进行调整和修复。

(2)拦截器执行顺序错误:拦截器执行顺序错误的主要原因是拦截器的注册顺序错误。在实际应用中,拦截器的执行顺序是根据它们在InterceptorRegistry中的注册顺序来决定的。因此,为了解决这个问题,我们需要调整拦截器在InterceptorRegistry中的注册顺序,确保它们按照预期的顺序执行。

(3)拦截器影响性能:拦截器影响性能的主要原因是拦截器中的处理逻辑过于复杂或资源消耗过大。为了解决这个问题,我们需要对拦截器的处理逻辑进行优化,尽量减少不必要的计算和资源消耗。同时,我们还可以考虑使用一些性能监控工具,如JProfiler等,来对拦截器的性能进行实时监控和分析,从而找到性能瓶颈并进行优化。

【八】拦截器的原理和源码分析

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

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

相关文章

HCIP-Datacom(H12-821)111-120题

111、地址转换技术的优点不包括()? A.地址转换可以使内部网络用户(私有IP地址)方便地访问Internet B.地址转换可以屏蔽内部网络的用户提高内部网络的安全性 C.地址转换可以使内部局城网的许多主机共享一个IP地址上网D.地址转换能够处理IP报头加密的情况 解析:地址转换只处理…

Python远程创建docker容器

1.安装docker yum install dockerdocker -v 2.拉取一个测试镜像,比如tomcat,默认是最新版本的 docker pull tomcat 使用 docker images可以看到该镜像 3.使用Python创建容器 import docker# 连接到远程Docker守护进程 client docker.DockerClient(…

今年消费新潮流:零元购商业模式

今天给大家推荐一种极具创新的电子商务模式:零元购商业模式 这个模式支持消费者以零成本或极低成本购买商品。这种模式主要通过返现、积分、优惠券等方式来减少支付金额,使消费者实现“零成本”购物的目标。 人民网在去年发表了一篇文章。 总结了一下&a…

麒麟服务器操作系统安装HTTP服务

往期好文:麒麟服务器操作系统安装TFTP服务 Hello,大家好啊!今天我们将探讨如何在麒麟服务器操作系统上安装和配置HTTP服务,这是任何网络服务或应用的基础。无论你是想建立一个简单的网站,还是需要一个全功能的Web服务器…

基于微信小程序【原生】+ssm+mysql+jsp消防知识学习平台(含论文)

博主介绍: 大家好,本人精通Java、Python、C#、C、C编程语言,同时也熟练掌握微信小程序、Php和Android等技术,能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验,能够为学生提供各类…

酸雨降水问题——多元回归分析

目录 题目如下 数据集如下 解题方法 regress 函数 代码实现 得出结果 题目如下 酸雨是降水中各种离子综合作用的结果。实际检测表明:城市降水pH值主要 受酸性离子[SO]、[NO]、[Ca]、[NH]影响。下表列出了我国部分城市降水 中[SO]、[NO]、[Ca⁺]、[NH]的浓度和pH值数据。以…

Linux程序调试优化(1)——内存占用详解及优化思路

文章目录 1.free查看总体的内存占用2./proc/$PID/status 查看某进程状态 linux开发最重要的两个参数,分别是内存以及CPU使用率,若内存出现严重不足,则在需要使用内存时,可能出现申请不到的情况,导致 OOM,L…

如何实现对空调状态监测的监控

随着科技的飞速发展和人们生活水平的持续提高,空调已经成为现代家庭和办公环境中不可或缺的一部分。然而,传统的空调使用方式往往存在能效低下、操作不便等问题。为了解决这些问题,智能空调控制器应运而生,它不仅能实现对空调状态…

Java使用OpenOffice将office文件转换为PDF

Java使用OpenOffice将office文件转换为PDF 1. 先行工作1.1 OpenOffice官网下载1.2 JODConverter官网下载1.3 下载内容 2.介绍3. 安装OpenOffice服务3.1.Windows环境3.2 Linux环境 4. maven依赖5. 转换代码 1. 先行工作 请注意,无论是windows还是liunx环境都需要安装…

zookeeper分布式应用程序协调服务+消息中间件kafka分布式数据处理平台

一、zookeeper基本介绍 1.1 zookeeper的概念 Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。 是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、…

半导体材料(一)

本篇为西安交通大学本科课程《电气材料基础》的笔记。 本篇为这一单元的第一篇笔记,下一篇传送门。 半导体是导电能力介于均属导体和绝缘体之间的固体材料。 半导体基本特征 室温下其电阻数量级约为 1 0 − 6 ∼ 1 0 8 Ω ⋅ m 10^{-6}\sim10^{8}\mathrm{\Omega…

供应IMX415-AAQR-C索尼芯片

长期供应各进口品牌芯片现货: IMX415-AAQR-C IMX492LLJ-C IMX492LQJ-C IMX455ALK-K IMMX455AQK-K IMX461ALR-C IMX461AQR-C IMX661-AAMR-C IMX661-AAQR-C IMX411ALR-C IMX411AQR-C IMX290LQR-C FS32K118LFT0MLHT FS32K146UAT0VLLT FS32K146UAT0VLQT …

什么数据集成(Data Integration):如何将业务数据集成到云平台?

说到数据集成(Data Integration),简单地将所有数据倒入数据湖并不是解决办法。 在这篇文章中,我们将介绍如何轻松集成数据、链接不同来源的数据、将其置于合适的环境中,使其具有相关性并易于使用。 数据集成&#xff1…

机器学习实训 Day1(线性回归练习)

线性回归练习 Day1 手搓线性回归 随机初始数据 import numpy as np x np.array([56, 72, 69, 88, 102, 86, 76, 79, 94, 74]) y np.array([92, 102, 86, 110, 130, 99, 96, 102, 105, 92])from matplotlib import pyplot as plt # 内嵌显示 %matplotlib inlineplt.scatter…

针对MaxCompute优化案例分享

声明 原文来源:微信公众号:阿里云开发者 前言 MaxCompute 是阿里巴巴集团推出的一种大数据计算平台,用于处理海量数据和进行数据分析。它提供了高可靠性、高扩展性和高性能的数据处理能力,支持 SQL 查询、MapReduce 计算和机器…

【快捷部署】017_MongoDB(6.0.14)

📣【快捷部署系列】017期信息 编号选型版本操作系统部署形式部署模式复检时间017MongoDB6.0.14Ubuntu 20.04apt单机2024-04-11 一、快捷部署 #!/bin/bash ################################################################################# # 作者:…

链表基础3——单链表的逆置

链表的定义 #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node* next; } Node; Node* createNode(int data) { Node* newNode (Node*)malloc(sizeof(Node)); if (!newNode) { return NULL; } newNode->data …

ceph集群管理节点高可用

一、前言 ceph集群想要高可用也必须要有多个管理节点&#xff0c;不然只有单管理节点&#xff0c;在一个管理节点挂了的情况下就没法进行集群的管理&#xff0c;可以分为web管理和客户端管理&#xff0c;web管理和mgr服务相关&#xff0c;客户端管理和mon服务相关 二、部署 mg…

品深茶都有什么功效,为什么那么贵?

品深国茶是一款高端商务用茶品牌。以中国传统中医理论为指导&#xff0c;精选天然有机茶叶为原料&#xff0c;经过严格配方科学制茶&#xff0c;再经现代生物技术加工制成的高端茶&#xff0c;有排毒养颜、补充营养、调节免疫、调节血脂和血压、调节血糖、促消化、解酒护肝、软…

【深度学习实战(6)】搭建通用的语义分割推理流程

一、代码 #---------------------------------------------------# # 检测图片 #---------------------------------------------------# def detect_image(self, image, countFalse, name_classesNone):#---------------------------------------------------------## 在…