【SpringBoot】使用 HandlerInterceptor 拦截器进行用户登录验证? 为什么不使用 SpingAOP ?

news2025/1/20 21:53:27

文章目录

  • 前言
  • 一、为什么不使用 SpringAOP ?
    • 1, 需求分析
    • 2, SpringAOP 能实现吗?
  • 二、使用 HandlerInterceptor
    • 1, 实现 HandlerInterceptor 接口
    • 2, 将自定义拦截器加入到系统配置
  • 三、HandlerInterceptor 实现原理
    • 源码分析
  • 总结


前言

各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你:
📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
📗 Java数据结构: 顺序表, 链表, 堆, 二叉树, 二叉搜索树, 哈希表等
📘 JavaEE初阶: 多线程, 网络编程, TCP/IP协议, HTTP协议, Tomcat, Servlet, Linux, JVM等(正在持续更新)

在这里插入图片描述


提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!


一、为什么不使用 SpringAOP ?

1, 需求分析

上篇文章 介绍了 AOP 和 SpringAOP , 接下来分析一个需求 : UserController 类里面定义了许多和用户相关的控制层代码, 在一层, 很多业务逻辑都是需要用户登录之后才能执行的

@RestController
@RequestMapping("/user")
public class UserController {
 	// 某⽅法 1
	@RequestMapping("/m1")
 	public Object method(HttpServletRequest request) {
 		// 有 session 就获取,没有不会创建
	 	HttpSession session = request.getSession(false);
	 	if (session != null && session.getAttribute("userinfo") != null) {
 		// 说明已经登录,进行业务处理
 			return true;
	 	} else {
		 	// 未登录
		 	return false;
	 	}
	 }
	 
 	// 某⽅法 2
	@RequestMapping("/m2")
 	public Object method2(HttpServletRequest request) {
 		// 有 session 就获取,没有不会创建
 		HttpSession session = request.getSession(false);
 		if (session != null && session.getAttribute("userinfo") != null) {
 			// 说明已经登录,业务处理
 			return true;
 		} else {
 			// 未登录
 			return false;
 		}
 	}
}

从上述代码可以看出, 每个方法中都有相同的用户登录验证权限, 它的缺点是:

    1. 每个方法中都要单独写⽤户登录验证的方法, 即使封装成公共方法, 也⼀样要传参调⽤和在方法中
      进⾏判断
    1. 添加控制器越多, 调用用户登录验证的方法也越多, 这样就增加了后期的修改成本和维护成本
    1. 这些⽤户登录验证的方法和接下来要实现的业务几乎没有任何关联, 但每个方法中都要写⼀遍

为了解决这一问题, 首先想到的就是 AOP 面向切面编程


2, SpringAOP 能实现吗?

上篇文章 介绍了 SpringAOP 的各种通知的使用方式, 在当前需求场景下, 使用前置通知或环绕通知 “应该” 是可以首先的, 但仔细一想就会有问题 :

  1. 要验证用户的登陆状态, 就要先获取到内存中的 session 对象, 但是通过前置或者环绕通知的方式时很难拿到请求对象的, 也就很难拿到 session 对象进行判断
  2. 与我们用户相关的控制器中并非所有方法都要进行拦截判断(像登录、注册方法, 通过原生 SpringAOP 的切点表达式配置拦截规则几乎是做不到的, 说白了就是无法定义哪些方法需要被拦截, 哪些方法不能被拦截

更好的方式是使用 HandlerInterceptor (拦截器)


二、使用 HandlerInterceptor

HandlerInterceptor 拦截器是将传统 AOP 进行了封装, 内置了 reuqest, response 对象, 提供了更加方便的功能

拦截器的实现分为以下两个步骤:

  1. 创建自定义拦截器,实现 HandlerInterceptor 接口的 preHandle(执行具体方法之前的预处理)方法
  2. 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法

1, 实现 HandlerInterceptor 接口

定义一个 LoginInterceptor 类表示登录拦截器, 实现 HandlerInterceptor 接口, 重写 preHandle()

@Component // 表示这是一个组件
public class LoginInterceptor implements HandlerInterceptor {

    private final String  SEEION_KEY = "SEEION";

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("SEEION") != null) {
            return true;
        }
        return false;
    }
}

preHandle() 是调用目标方法(要被拦截的方法)执行之前的方法, 此方法返回的是 boolean 类型的值

  • 如果返回的 true 表示可以放行, 允许继续走后续的流程, 执行目标方法
  • 如果返回 false, 表示不能放行, 不允许执行后续的流程和目标方法

2, 将自定义拦截器加入到系统配置

定义一个 APPConfig 类, 实现 WebMvcConfigurer 接口, 重写 addInterceptors()

addInterceptors() 这个方法需要将我们上面写好的自定义拦截器( LoginInterceptor 的 Bean 对象)加入到系统配置, 所以可以使用 @Autowired 进行注入

@Configuration // 表示这是一个配置
public class APPConfig implements WebMvcConfigurer {

    // 把拦截器那个 Bean 注入进来
    @Autowired
    private LoginInterceptor loginInterceptor;

    // 添加拦截器规则
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor) // 添加我们的自定义拦截器
                .addPathPatterns("/**") // 拦截所有url
                .excludePathPatterns("/user/login")// 放行这个url
                .excludePathPatterns("/login.html")// 放行这个url
                .excludePathPatterns("/reg.html")// 放行这个url
                .excludePathPatterns("/css/**")// 放行这个url
                .excludePathPatterns("/editor.md/**")// 放行这个url
                .excludePathPatterns("/editor.md/**")// 放行这个url
                .excludePathPatterns("/img/**")// 放行这个url
                .excludePathPatterns("/js/**");// 放行这个url
    }
}

1, addPathPatterns() 表示需要拦截的 url , **表示拦截任意 url
2, excludePathPatterns():表示需要排除(不拦截)的 url

说明:以上拦截规则可以拦截此项目中使用的 url, 包括静态文件件(图片, html, css, js 等)


三、HandlerInterceptor 实现原理

在使用拦截器之前, 用户访问 web 网站的前后端交互流程大致如下 :

在这里插入图片描述
前端的所有请求都会先来到 Controller 层, 但加入了拦截器, 会在 Controller 层之前工作
在这里插入图片描述


源码分析

  1. 所有的 Controller 层的执行都会通过一个 调度器 DispatcherServlet 来实现,这⼀点可以从 Spring Boot 控制台打印的日志信息看出,如下图所示
    在这里插入图片描述

  2. 而所有方法都会执行 DispatcherServlet 中的 doDispatch() 调度方法, doDispatch() 部分源码如下(只看重点)

// 预处理【重点】
if (!mappedHandler.applyPreHandle(processedRequest, respon se)) {
	return;
}
// 往后执⾏ Controller 中的业务
mv = ha.handle(processedRequest, response, mappedHandler.g
etHandler());
if (asyncManager.isConcurrentHandlingStarted()){
    return;
}

上述代码表示 : 开始执行 Controller 之前,会先调用 预处理方法 applyPreHandle()

applyPreHandle() 方法是Boolean 类型, 如果 applyPreHandle() 返回值为 true, 才能执行Controller 层的方法

  1. applyPreHandle() 的源码如下 :
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
 	for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
 		// 获取项⽬中使⽤的拦截器 HandlerInterceptor
 		HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
 		if (!interceptor.preHandle(request, response, this.handler)) {
 			this.triggerAfterCompletion(request, response, (Exception)null);
 			return false;
 		}
 	}
 	return true;
}

上述代码表示, 遍历 interceptorList (我们自定义拦截器的集合), 执行我们重写的 preHandle()
如果我们自定义的拦截器都返回 true 了, applyPreHandle() 才会返回 true , 才能执行 Controller 层的方法


总结

拦截器 HandlerInterceptor 相比于 SpringAOP 有两大优点 :

  1. preHandle() 可以轻松的获取并使用 request 和 response 对象
  2. addInterceptors() 中将自定义的拦截器加入到系统配置, addPathPatterns() 和 excludePathPatterns() 配合可以很自由的定义拦截规则

拦截器会在Controller 层之前执行, 执行我们定义的预处理逻辑

以上就是本篇的所有内容了, 如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦😋😋😋~


上山总比下山辛苦
下篇文章见

在这里插入图片描述

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

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

相关文章

crawlab通过docker单节点部署简单爬虫

crawlab 单节点docker安装 此处介绍的是单节点的方式&#xff0c;多节点的情况可以把爬虫上传到一个节点中&#xff0c;之后会同步到其它节点上 version: 3.3 services:master:image: crawlabteam/crawlabcontainer_name: crawlab_masterrestart: alwaysenvironment:CRAWLAB…

GaussDB技术解读系列:高级压缩之OLTP表压缩

8月16日&#xff0c;第14届中国数据库技术大会&#xff08;DTCC2023&#xff09;在北京国际会议中心顺利举行。在GaussDB“五高两易”核心技术&#xff0c;给世界一个更优选择的专场&#xff0c;华为云数据库GaussDB首席架构师冯柯对华为云GaussDB数据库的高级压缩技术进行了详…

〔018〕Stable Diffusion 之 批量替换人脸 篇

✨ 目录 &#x1f388; 下载插件&#x1f388; 插件基础使用&#x1f388; 基础使用效果&#x1f388; 批量处理图片&#x1f388; 多人脸部替换 &#x1f388; 下载插件 如果重绘图片的时候&#xff0c;你只想更换人物面部的话&#xff0c;可以参考这篇文章扩展地址&#xff…

【GAMES202】Real-Time Environment Mapping2—实时环境光照2

一、Shadow from Environment Lighting 上篇我们说了给定Environment&#xff0c;如何计算一个着色点的Shading&#xff0c;但没说Shadow。而事实上&#xff0c;实时渲染中很难做到环境光的Shadow。 原因也很容易想到&#xff0c;一种观点我们把环境光当成多光源问题&#xff…

软件测试实训系统建设方案

一 、系统概述 软件测试实训系统是软件开发过程中的一项重要测试活动&#xff0c;旨在验证不同软件模块或组件之间的集成与交互是否正常。综合测试确保各个模块按照设计要求正确地协同工作&#xff0c;以实现整个软件系统的功能和性能。以下是软件测试实训系统的一般流程和步骤…

2023腾讯云服务器多少钱一年?CPU内存带宽配置报价

腾讯云服务器租用价格表&#xff1a;轻量应用服务器2核2G4M带宽112元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;2核4G5M带宽756元三年、云服务器CVM S5实例2核2G配置280.8元一年、GPU服务器GN10Xp实例145元7天&#xff0c;腾讯云服务器网长期更新腾讯云轻量…

格式化u盘怎么做?分享几个简单方法!

“u盘用了好久&#xff0c;存储了很多不太重要的文件&#xff0c;想将它格式化之后继续使用。但是不知道怎样才能格式化u盘&#xff0c;大家有什么好的建议吗&#xff1f;” U盘是常见的移动存储设备&#xff0c;然而&#xff0c;在日常生活中使用u盘时&#xff0c;我们可能因为…

锁策略、原子编程CAS 和 synchronized 优化过程

前言 锁冲突&#xff1a;两个线程获取一把锁&#xff0c;一个线程阻塞等待&#xff0c;一个线程加锁成功。 目录 前言 一、锁策略 &#xff08;一&#xff09;乐观锁和悲观锁 &#xff08;二&#xff09;重量级锁和轻量级锁 &#xff08;三&#xff09;自旋锁和挂起等待…

HTML基础1

一、创建项目和标签基础 1.1 什么是HTML 英文全称Hyper Text Markup Language&#xff0c; 中文全称为超文本标记语言。 超文本标记语言是标准通用标记语言下的一个应用&#xff0c;也是一种规范&#xff0c;一种标准&#xff0c;它通过标记符号来标记要显示的网页中的各个部…

进程与线程(概念、并行、并发)

进程与线程 一、定位二、什么是进程&#xff1f;三、进程管理1、PCB相关属性&#xff08;了解&#xff09;2、多任务的处理方式 四、什么是线程&#xff1f;总结 一、定位 在计算机系统中&#xff0c;操作系统是其中的重要一环。对上&#xff0c;给软件提供稳定的运行环境&…

ssm+vue线上体验馆管理系统源码和论文

ssmvue线上体验馆管理系统源码和论文085 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0…

el-collapse折叠面板默认全部展开/关闭

所要展开项的name标识符与v-model绑定值匹配即可默认展开。 1. 案例 <el-collapse v-model"activeNames"><el-collapse-item name"0" title段落1>那一年&#xff0c;花开得不是最好&#xff0c;可是还好&#xff0c;我遇到你&#xff1b;&l…

高忆管理:A股已具备年度配置价值

周末利好四箭齐发&#xff0c;财政部、证监会、三大买卖所均宣布严重方针调整&#xff0c;首要包含印花税调降、IPO节奏阶段性收紧、融资保证金比例降至80%、限制大股东和实控人减持等。二级商场上&#xff0c;大盘大幅高开后一路震动走低&#xff0c;终究收盘涨幅显着收窄。业…

ROS通信机制之服务(Service)的应用

1、服务的概述 在上节我们讲过一个重要通信机制话题&#xff1a;ROS通信机制之话题(Topics)的发布与订阅以及自定义消息的实现&#xff0c;这里介绍另外一种节点之间传递数据的方法&#xff1a;服务(Service)服务的本质是同步的跨进程函数调用&#xff0c;也就是说节点可以调用…

骨传导耳机哪款比较好,市面上最好的骨传导耳机分享

随着科技的日新月异&#xff0c;骨传导耳机也在不断更新换代。市场上涌现出许多品牌&#xff0c;这使得消费者在购买时感到困惑。别担心&#xff01;我们为你整理了一些市场上最好的骨传导耳机品牌&#xff0c;希望能帮到你。现在&#xff0c;就让我们一起探索这些骨传导耳机的…

人工智能会成为人类的威胁吗?马斯克、扎克伯格、比尔·盖茨出席

根据消息人士透露&#xff0c;此次人工智能洞察论坛将是一次历史性的聚会&#xff0c;吸引了来自科技界的许多重量级人物。与会者们将共同探讨人工智能在科技行业和社会发展中的巨大潜力以及可能带来的挑战。 埃隆马斯克&#xff0c;特斯拉和SpaceX的首席执行官&#xff0c;一直…

ssm+vue理发店会员管理系统源码和论文

ssmvue理发店会员管理系统源码和论文089 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&a…

《高性能Linux网络编程核心技术揭秘》已出版

#好书推荐##好书奇遇季#《高性能Linux网络编程核心技术揭秘》&#xff0c;京东当当天猫都有发售。定价109元&#xff0c;网店打折销售更便宜。本书配套示例项目源码、作者QQ答疑。 本书详解高性能Linux网络编程的核心技术及DPDK框架&#xff0c;剖析Nginx高性能服务器架构&…

《PyTorch 2.0深度学习从零开始学》已出版

#好书推荐##好书奇遇季#《PyTorch 2.0深度学习从零开始学》&#xff0c;京东当当天猫都有发售。定价69元&#xff0c;网店打折销售更便宜。本书配套示例项目源码、PPT课件。 本书以通俗易懂的方式介绍PyTorch深度学习基础理论&#xff0c;并以项目实战的形式详细介绍PyTorch框…

无涯教程-Android - 应用组件

应用程序组件是Android应用程序的基本组成部分&#xff0c;这些组件需要在应用程序清单文件 AndroidManifest.xml 注册&#xff0c;该文件描述了应用程序的每个组件以及它们如何交互。 Android应用程序可以使用以下四个主要组件- Sr.NoComponents & 描述1 Activities 它们…