springboot的统一处理
在处理网络请求时,有一部分功能是需要抽出来统一处理的,与业务隔开。
登录校验
可以利用spring mvc的拦截器Interceptor,实现HandlerInterceptor接口即可。实现该接口后,会在把请求发给Controller之前进行拦截处理。
拦截器的实现分为以下两个步骤:
- 创建⾃定义拦截器,实现 HandlerInterceptor 接⼝的 preHandle(执⾏具体⽅法之前的预处理)⽅法。
- 将⾃定义拦截器加⼊ WebMvcConfigurer 的 addInterceptors ⽅法中。
我们使用session来作为登录校验的例子,实现如下:
package com.demo;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 登录拦截器*/
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {/*** 为 false 则不能继续往下执行;为 true 则可以。*/ @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 判断session的信息是否合法HttpSession session = request.getSession(false);if (session != null && session.getAttribute("userinfo") != null) {return true;}log.error("当前用户没有访问权限");response.setStatus(401);return false;}
}
将写好的⾃定义拦截器通过WebMvcConfigurer注册到容器中,使得拦截器生效,具体实现代码如下:
package com.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MyConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/login"); // 排除不拦截的 url}
}
如果不注入对象的话,addInterceptor() 的参数也可以直接 new 一个对象:
@Configuration // 一定不要忘记
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/login"); // 排除不拦截的 url}
}
原理
所有的 Controller 执⾏都会通过spring mvc的调度器 DispatcherServlet 来实现,所有⽅法都会执⾏ DispatcherServlet 中的 doDispatch 调度⽅法,doDispatch 源码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv = null;Object dispatchException = null;try {// ... 忽略不重要的代码// 调⽤预处理if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 执⾏ Controller 中的业务mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// ... 忽略不重要的代码} catch (Exception var20) {dispatchException = var20;} catch (Throwable var21) {dispatchException = new NestedServletException("Handler dispatch failed", var21);}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}
}
从上述源码可以看出在开始执⾏ Controller 之前,会先调⽤ 预处理⽅法 applyPreHandle,⽽ applyPreHandle ⽅法的实现源码如下:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex= i++) {// 获取项⽬中使⽤的拦截器 HandlerInterceptorHandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}return true;
}
异常处理
请求时的异常处理也是比较常见的统一处理的对象。
统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件,具体实现代码如下:
package com.demo;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;/*** 统一处理异常* 一般都需要自定义一个异常对象,这里为了简单说明只用一个map对象来说明*/
@ControllerAdvice
public class ErrorAdive {@ExceptionHandler(Exception.class)@ResponseBodypublic HashMap<String, Object> exceptionAdvie(Exception e) {HashMap<String, Object> result = new HashMap<>();result.put("code", "-1");result.put("msg", e.getMessage());return result;}@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic HashMap<String, Object> arithmeticAdvie(ArithmeticException e) {HashMap<String, Object> result = new HashMap<>();result.put("code", "-2");result.put("msg", e.getMessage());return result;}}
此时若出现异常就不会报错了,代码会继续执行,但是会把自定义的异常信息返回给前端!
原理
@ControllerAdvice是spring的aop对于Controller进行切面所有属性的,包括切入点和需要织入的切面逻辑,配合@ExceptionHandler来捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。
返回数据结构
统⼀的返回数据结构可以使用 @ControllerAdvice + ResponseBodyAdvice接口 的方式实现,具体实现代码如下:
package com.demo;import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyA
dvice;import java.util.HashMap;/*** 统一返回数据的处理*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/*** 内容是否需要重写(通过此⽅法可以选择性部分控制器和⽅法进⾏重写)* 返回 true 表示重写*/@Overridepublic boolean supports(MethodParameter returnType, Class converterTyp
e) {return true;}/*** ⽅法返回之前调⽤此⽅法*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType, ServerHttpRequest request,ServerHttpResponse response) {// 构造统⼀返回对象HashMap<String, Object> result = new HashMap<>();result.put("state", 1);result.put("msg", "");result.put("data", body);return result;}
}
相关文章:
springboot的统一处理
在处理网络请求时,有一部分功能是需要抽出来统一处理的,与业务隔开。 登录校验 可以利用spring mvc的拦截器Interceptor,实现HandlerInterceptor接口即可。实现该接口后,会在把请求发给Controller之前进行拦截处理。 拦截器的实…...

C/C++每日一练(20230319)
目录 1. 反转链表 II 🌟🌟 2. 解码方法 🌟🌟 3. 擅长编码的小k 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 …...

GitHub 上有些什么好玩的项目?
前言 各个领域模块的都整理了一下,包含游戏、一些沙雕的工具、实用正经的工具以及一些相关的电商项目,希望他们可以给你学习的路上增加几分的乐趣,我们直接进入正题~ 游戏 1.吃豆人 一款经典的游戏开发案例,包括地图绘制、玩家控…...
蓝桥杯刷题第十二天
问题描述给定一个正整数 n ,请问 n 的十进制表示中末尾总共有几个 0 ?输入格式输入一行包含一个正整数 n。输出格式输出一个整数,表示答案。评测用例规模与约定对于所有评测用例,1 < n < 1000000000。运行限制最大运行时间&…...

开发也可以很快乐,让VSCode和CodeGPT带给你幸福感
CodeGPT 是一款 Visual Studio Code 扩展,可以通过官方的 OpenAI API 使用 GPT-3 (预训练生成式转换器) 模型,在多种编程语言中生成、解释、重构和文档化代码片段。CodeGPT 可用于各种任务,例如代码自动完成、生成和格式化。它还可以集成到代…...

【Linux】基本指令介绍
前言从今天开始,我们一起来学习Linux的相关知识,今天先来介绍怎么登录Linux,并且介绍一些Linux的基本指令。使用 XShell 远程登录 Linux很多同学的 Linux 启动进入图形化的桌面. 这个东西大家以后就可以忘记了. 以后的工作中 没有机会 使用图…...
JQuery介绍
文章目录一. JQuery介绍二. JQuery使用三. JQuery选择器四. JQuery选择集过滤五.JQuery选择集转移六. JQuery获取和操作标签内容七. JQuery获取和设置元素属性八. JQuery事件九.JQuery事件代理- 事件冒泡- 事件绑定的问题- 事件代理一. JQuery介绍 定义: jquery是JS的一个函数…...

Selenium基础篇之八大元素定位方式
文章目录前言一、如何进行元素定位?1.右击元素-检查2.F12-选择工具点击元素3.借助selenium IDE二、八大元素定位方式1.ID1.1 方法1.2 举例1.3 代码1.4 截图2.NAME2.1 方法2.2 举例2.3 代码2.4 截图3.CLASS_NAME3.1 方法3.2 举例3.3 代码3.4 截图4.TAG_NAME4.1 方法4…...

C语言的灵魂---指针(基础)
C语言灵魂指针1.什么是指针?2.指针的大小3.指针的分类3.1比较常规的指针类型3.2指针的解引用操作3.3野指针野指针的成因:4.指针运算4.1指针加减整数4.2指针-指针1.什么是指针? 这个问题我们通常解释为两种情况: 1.指针本质&#…...
带你一文透彻学习【PyTorch深度学习实践】分篇——线性模型 梯度下降
分享给大家一段我国著名作家、散文家史铁生先生的一段话: 把路想象的越是坎坷就越是害怕,把山想象的越是险峻就越会胆怯,把别人想象的越是优秀就越是不敢去接近。惯于这样想象的人,是天生谦卑的人。 --------史铁生《关于恐惧》 🎯作者主页:追光者♂🔥 �…...
Javascript如何截取含有表情的字符串
Javascript如何截取含有表情的字符串 一、说说背景 社区社交应用中,难免会有输入用户昵称的操作,如果用户老老实实的输入中文汉字或者英文字母,那当然没啥问题,我们能够轻松的处理字符串的截取,产品说按多少字符截取…...

【云原生】prometheus结合jmx exporter 的java agent模式采集tomcat监控实战
前言 大家好,我是沐风晓月,今天我们又来探讨一款使用prometheus监控tomcat的另外一种形式:Java agent模式。 如果你想使用http server模式,请参考:【云原生】prometheus结合jmx exporter 的http server模式采集tomca…...

深度学习应用技巧总结与pytorch框架下训练过程的记忆技巧
大家好,我是微学AI,今天给大家总结一下深度学习模型训练过程中的一些技巧总结,以及pytorch框架下训练过程的记忆技巧,很有用的干货,理解模型训练过程的步骤,让流程难懂,难记忆的过程变得简单&am…...
数字图像处理 基于OpenCV的一种简单的阴影校正的方法
一、简述 在很多工业场景,都是基于工业相机、或者结合显微镜进行拍照采样,以进行进一步的分析,通常情况下分析结果和图像的质量息息相关,我们这里讨论的主要是因光照不均衡而在图像边缘产生阴影的图像的校正。 1、亮度阴影 亮度阴影(光学上称为渐晕,Vignetting)就是我们…...

OpenHarmony之cJSON库使用介绍
一、前言 我们前面OpenHarmony设备配网 文章中,给大家提供的示例有使用cJSON解析和cJSON创建json数据的用法 那么有同学会提出疑问,我难道只能用cJSON库? 当然不是啊,你也可以用 json-parser、parson、jansson 等等三方库 回到正题…...

门面设计模式
介绍 Java门面模式(Facade Pattern)是一种结构型设计模式,它提供了一个简单的接口,隐藏了复杂系统的实现细节,使得客户端可以更加容易地使用系统. 在Java门面模式中,一个门面对象(Facade)提供了一个简单的接口,该接口包装了一个或多个复杂的子系统,客户端可以直接使用门面对象…...

苹果手写笔好用吗?比较好用的ipad手写笔推荐
随着技术的进步,各种新型的电子产品和数码器件层出不穷。比如智能手机、IPAD、以及电容笔。而在实际生活中,为了更好的利用ipad,我们需要一支好用的电容笔。就好比如我们在ipad上做笔记,要用手来进行手写记录,会很不方…...

GPT-4来了!看看她究竟强在哪里!
GPT-4来了!OpenAI老板Sam Altman直接开门见山地介绍说:这是我们迄今为止功能最强大的模型!GPT-4是一个超大的多模态模型,也就是说,它的输入可以是文字(上限2.5万字),还可以是图像。我…...

GPT-4 API 接口调用及价格分析
GPT-4 API 接口调用及价格分析 15日凌晨,OpenAI发布了万众期待的GPT-4!新模型支持多模态,具备强大的识图能力,并且推理能力和回答准确性显著提高。在各种专业和学术基准测试上的表现都媲美甚至超过人类。难怪OpenAI CEO Sam Altm…...
MySQL高级功能:存储过程、触发器、事务、备份和恢复
MySQL高级功能MySQL是一款广泛使用的关系型数据库管理系统,它不仅具有基本的数据库功能,还支持一些高级功能,如存储过程、触发器、事务、备份和恢复等。这些高级功能可以帮助开发人员更高效地管理和维护数据库,本文将介绍MySQL的高…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...