SpringBoot统一功能处理(AOP思想实现)(统一用户登录权限验证 / 异常处理 / 数据格式返回)
主要是三个处理:
1、统一用户登录权限验证;
2、统一异常处理;
3、统一数据格式返回。
目录
一、用户登录权限校验
🍅 1、使用拦截器
🎈 1.1自定义拦截器
🎈 1.2 设置自定义拦截器
🎈创建controller类,并且运行项目
🍅 2、拦截器原理
二、统一异常处理
三、统一数据返回
🍅 为什么需要统一数据返回格式
🍅 统一数据返回格式
🎈定义同已返回类型
🎈 同以数据处理
🎈业务类
一、用户登录权限校验
🍅 1、使用拦截器
可以对一部分方法进行拦截,而另一部分不拦截。
🎈 1.1自定义拦截器
/*
* 全局变量
* */
public class AppVar {
// Session keypublic static final String SESSION_KEY = "SESSION KEY";
}/*
* 自定义拦截器
* 返回true -> 表示拦截器验证成功,继续指定后续方法
* 返回false -> 表示验证失败,不会执行后续的方法了
* */
@Component
public class UserInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {
// 业务方法HttpSession session = request.getSession(false);if (session!=null &&session.getAttribute(AppVar.SESSION_KEY)!=null){
// 用户已经登录return true;}return false;}
}
🎈 1.2 设置自定义拦截器
将自定义拦截器设置当前项目的配置文件中,并且设置拦截规则。
拦截器要注入到Spring中才能运行,他是伴随着Spring的启动而启动的
@Configuration
public class AppConfig implements WebMvcConfigurer {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new UserInterceptor());registry.addInterceptor(userInterceptor).addPathPatterns("/**") //("/**")表示拦截所有的请求.excludePathPatterns("/user/reg")//表示过滤拦截,不拦截(/user/reg).excludePathPatterns("/user/login");//表示过滤拦截,不拦截("/user/login")}
}
🎈创建controller类,并且运行项目
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getuser")public String getUser(){System.out.println("do getUser()");return "user";}@RequestMapping("/reg")public String reg(){System.out.println("do reg()");return "reg";}@RequestMapping("/login")public String login(){System.out.println("do login()");return "login";}
}
其中:
- addPathPatterns:表示要拦截的url,“/**”表示拦截任意方法
- elcludePathPatterns:表示需要排除的URL
- 以上得拦截规则可以拦截URL,包括静态文件(图片文件、JS、CSS等),一般拦截静态文件的时候,我们可以把这些静态文件分类放在static文件中
🍅 2、拦截器原理
在使用拦截器之前:
使用拦截器之后:会在调用Controller之前进行相应的业务处理
实现原理源码分析:
所有的controller指定都会通过一个调度器DispatcherServlet来实现,

所有的请求都会执行DispatcherServlet中的doDispatcher方法,在doDispatcher会执行一系列的事件,该事件是在执行拦截器之前的,如果该事件返回false,后续就不会执行Controller。
以下是doDispatcher中的一部分代码,发现在执行controller之前都会追先执行预处理
// 调⽤预处理【重点】if (!mappedHandler.applyPreHandle(processedRequest, respon
se)) {return;}// 执⾏ Controller 中的业务mv = ha.handle(processedRequest, response, mappedHandler.g
etHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;
}
那么,关于预处理⽅法 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是异常处理,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。
首先认为构造一个空指针异常:
@RequestMapping("/reg")public String reg(){System.out.println("do reg()");Object obj = null;System.out.println(obj.hashCode());System.out.println();System.out.println("do reg()");return "reg";}
报错了: 这种直接给你报错的方式并不直观,所以我们可以进行统一的异常处理,返回直观的数据。

然后我们进行统一异常处理:
首先定义一个统一的返回对象:
@Data
public class ResultAjax {private int code; //状态码private String msg; //状态码的描述信息private Object data;//返回数据
}
然后定义异常管理器:
@RestControllerAdvice
public class ExceptionAdvice {@ExceptionHandler(NullPointerException.class)public ResultAjax doNullPointerException(NullPointerException e){ResultAjax resultAjax = new ResultAjax();//错误的信息使用-1描述状态码resultAjax.setCode(-1);resultAjax.setMsg("空指针异常:"+ e.getMessage());resultAjax.setData(null);return resultAjax;}
}
这时候就会返回状态的描述信息:

也可以直接使用NullPointerException的父类
@ExceptionHandler(Exception.class)public ResultAjax doException(Exception e){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(-1);resultAjax.setMsg("空指针异常:"+ e.getMessage());resultAjax.setData(null);return resultAjax;}
三、统一数据返回
🍅 为什么需要统一数据返回格式
统一数据返回格式的优点(为什么要统一):
- 方便程序员更好的接收和解析后端数据接口返回的数据
- 降低前端程序源和后端程序员的沟通成本,按照找某个格式实现,所有接口都这样返回
- 有利于项目统一数据的维护和修改
- 有利于后端技术部分的统一规范的标准制定,不会出现稀奇古怪的返回内容
🍅 统一数据返回格式
🎈定义同已返回类型
@Data
public class ResultAjax {private int code; //状态码private String msg; //状态码的描述信息private Object data;//返回数据/** 返回成功* */public static ResultAjax success(Object data){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(200);resultAjax.setMsg("");resultAjax.setData(data);return resultAjax;}/** 返回失败* */public static ResultAjax fail(int code,String msg){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(code);resultAjax.setMsg(msg);resultAjax.setData(null);return resultAjax;}public static ResultAjax fail(int code,String msg,Object data){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(code);resultAjax.setMsg(msg);resultAjax.setData(null);return resultAjax;}
}
🎈 同以数据处理
统一数据处理(强制执行):
- @ControllerAdvice
- 实现ResponseBodyAdvice接口,并且重写它其中的两个方法,supports必须返回true,beforeBodyWrite方法进行重新判断和重写操作
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/** 默认翻会true的时候* 才会执行beforeBodyWrite方法* */@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {//已经包装好的对象if (body instanceof ResultAjax){return body;}
// 没有包装return ResultAjax.success(body);}
}
🎈业务类
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")public ResultAjax login(){System.out.println("do login()");return ResultAjax.success("login");}@RequestMapping("/getnum")public int getNum(){return 1;}
}
其中login没有定义返回类型,getNum定义了返回类型,返回结果分别如下:

注意:
如果定义的返回值类型是String,那么会报错
@RequestMapping("/getstring")public String getString(){return "qqq";}
那么可以对String类型作出单独处理:
@Autowiredprivate ObjectMapper objectMapper;@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {//已经包装好的对象if (body instanceof ResultAjax){return body;} // 对字符串进行单独处理if (body instanceof String){ResultAjax resultAjax = ResultAjax.success(body);try {return objectMapper.writeValueAsString(resultAjax);} catch (JsonProcessingException e) {e.printStackTrace();}} // 没有包装return ResultAjax.success(body);}返回结果:
相关文章:
SpringBoot统一功能处理(AOP思想实现)(统一用户登录权限验证 / 异常处理 / 数据格式返回)
主要是三个处理: 1、统一用户登录权限验证; 2、统一异常处理; 3、统一数据格式返回。 目录 一、用户登录权限校验 🍅 1、使用拦截器 🎈 1.1自定义拦截器 🎈 1.2 设置自定义拦截器 🎈创建cont…...
git stash 用法
起始 今天在看一个bug,之前一个分支的版本是正常的,在新的分支上上加了很多日志没找到原因,希望回溯到之前的版本,确定下从哪个提交引入的问题,但是还不想把现在的修改提交,也不希望在Git上看到当前修改的…...
生鲜蔬果小程序的完整教程
随着互联网的发展,线上商城成为了人们购物的重要渠道。其中,小程序商城在近年来的发展中,备受关注和青睐。本文将介绍如何使用乔拓云网后台搭建生鲜果蔬配送小程序,并快速上线。 首先,登录乔拓云网后台,进入…...
De Bruijin序列与魔术(二)——魔术《De Bruijin序列》
早点关注我,精彩不错过! 上一篇我们介绍了De Bruijin序列的基本数学内容以及其如何应用在魔术上的一些基本内容,今天我们就来学习一下这个经典的《De Bruijin序列》魔术。 De bruijin序列魔术 先看视频。 视频1 De Bruijin序列的魔术 魔术来源…...
ARCGIS地理配准出现的问题
第一种。已有省级行政区矢量数据,在网上随便找一个相同省级行政区图片,利用地理配准工具给图片添加坐标信息。 依次添加省级行政区选择矢量数据、浙江省图片。 此时,图层默认的坐标系与第一个加载进来的省级行政区选择矢量数据的坐标系一致…...
redis原理 6:小道消息 —— PubSub
前面我们讲了 Redis 消息队列的使用方法,但是没有提到 Redis 消息队列的不足之处,那就是它不支持消息的多播机制。 img 消息多播 消息多播允许生产者生产一次消息,中间件负责将消息复制到多个消息队列,每个消息队列由相应的消费组…...
Android Studio 的Gradle版本修改
使用Android Studio构建项目时,需要配置Gradle,与Gradle插件。 Gradle是一个构建工具,用于管理和自动化Android项目的构建过程。它使用Groovy或Kotlin作为脚本语言,并提供了强大的配置能力来定义项目的依赖关系、编译选项、打包方…...
Redis的部分面试题
1.Redis是什么?简述它的优缺点? Redis的字符串类型是通过简单动态字符串SDS来实现的。简单动态字符串是Redis自己实现的一种字符串表示方式,相比于C语言中的传统字符串,它具有以下几个特点: 1. 动态调整大小:简单动态字符串可…...
单通道 6GSPS 16位采样DAC子卡模块--【资料下载】
FMC147是一款单通道6.4GSPS(或者配置成2通道3.2GSPS)采样率的12位AD采集、单通道6GSPS(或配置成2通道3GSPS)采样率16位DA输出子卡模块,该板卡为FMC标准,符合VITA57.4规范,该模块可以作为一个理想…...
Python 文件操作详解
概要 Python进行文件操作,在日常编程中是很常用的。为了方便大家,这里对各种文件操作的知识进行汇总。一文在手,无须它求!来一起学习吧。 一、文件的打开和关闭 open()函数 f1 open(rd:\测试文件.txt, moder, encodingutf-8) c…...
【Rust 基础篇】Rust Never类型:表示不会返回的类型
导言 Rust是一种以安全性和高效性著称的系统级编程语言,其设计哲学是在不损失性能的前提下,保障代码的内存安全和线程安全。在Rust中,Never类型是一种特殊的类型,它表示一个函数永远不会返回。Never类型在Rust中有着重要的应用场…...
error “Component name “*****“ should always be multi-word”解决方案
问题 在 vue-cli 创建的项目中,创建文件并命名后,会报 “Component name "*****" should always be multi-word” 报错; Component name "index" should always be multi-word.eslintvue/multi-word-component-names原…...
前后端开发的区别是什么?
VUE的开发方式为什么和后端的MVC开发方式不一样呢? 实际上,Vue 和后端开发的 MVC(Model-View-Controller)方式是不同的,因为它们面对的问题和场景也不同。 前端与后端的职责不同: 前端和后端的职责和任务不…...
小白电脑装机(自用)
几个月前买了配件想自己装电脑,结果最后无法成功点亮,出现的问题是主板上的DebugLED黄灯常亮,即DRAM灯亮。对于微星主板的Debug灯,其含义这篇博文中有说明。 根据另一篇博文,有两种可能。 我这边曾将内存条和主板一块…...
Quic协议 0-RTT
目录 1、Quic协议 2、Quic直接通过TLS握手进行建立链接,TLS是1.3版本 3.1、通过缓存服务器公钥实现0-RTT,服务器 通过kdf密钥派生机制,来产生会话加密key,保证数据向前安全性 3.2、通过PKN来实现数据重传保证数据完整性&…...
在排序数组中查找元素的第一个和最后一个位置——力扣34
文章目录 题目描述法一 二分查找题目描述 法一 二分查找 int bsearch_1(int l, int r) {while (l < r)<...
python列表处理方法
原始文件: id start end a1 10 19 a1 25 34 a2 89 124 a2 149 167 a2 188 221目的文件: a1 1 10 a1 16 25 a2 1 36 a2 61 79 a2 100 133解释说明: 原始文件是gff3文件的一部分,第一列id是基因的名字,第二列和第三列分…...
【Java】快速入门JVM
文章目录 1. JVM简介2. 类加载简介3. 类加载的过程4. 双亲委派5. GC垃圾回收6. JVM的回收方式7. 分代回收 1. JVM简介 JVM(Java虚拟机)是一个名字为Java的进程,是用于执行Java程序的虚拟机。 JVM会从操作系统中申请一大块内存空间,又把这个内存空间划分…...
C#之Winfrom自定义输入框对话框。
如果你需要一个带有输入框的对话框,并在输入完成后接收输入的值,你可以使用自定义窗体来实现。以下是一个示例代码:创建一个继承自 Form 的自定义窗体类,命名为 InputDialogForm,并将窗体上放置一个文本框(…...
docker制作镜像
docker制作镜像 docker制作镜像有两种: 1.docker build dockerfile 2.基于容器制作镜像 基于容器制作镜像 语法:docker commit options 容器名称 参数: -a:作者 -c:修改dockfile创建的镜像 -m:提交…...
Node.js环境下的实时口罩检测API开发与部署教程
Node.js环境下的实时口罩检测API开发与部署教程 1. 引言 在当今的智能化场景中,实时口罩检测技术已经成为许多公共场所和企业的必备功能。无论是商场入口、办公大楼还是公共交通场所,快速准确地检测人员是否佩戴口罩都显得尤为重要。 本教程将手把手教…...
图解numpy轴运算:用动画演示argmin/argmax在不同维度下的工作原理(附可运行代码)
用空间思维理解NumPy轴运算:argmin/argmax的维度穿越指南 当你第一次在NumPy中遇到axis参数时,是否感觉像在解一道空间几何题?本文将通过视觉化的思维模型,带你穿透维度的迷雾,掌握argmin和argmax在不同维度数组中的行…...
Qwen-Image-Edit-2509入门到精通:掌握核心指令,成为高效修图达人
Qwen-Image-Edit-2509入门到精通:掌握核心指令,成为高效修图达人 1. 为什么你需要Qwen-Image-Edit-2509 想象一下这个场景:你刚收到客户发来的50张产品照片,需要统一更换背景、添加促销标签、调整产品颜色。传统方法可能需要花费…...
OpenClaw故障排查:千问3.5-9B接口连接问题解决大全
OpenClaw故障排查:千问3.5-9B接口连接问题解决大全 1. 问题背景与排查思路 上周我在本地部署OpenClaw时,遇到了对接千问3.5-9B模型的连接问题。作为一个开源AI智能体框架,OpenClaw需要稳定接入大模型才能发挥自动化能力。但在实际配置过程中…...
如何用XUnity.AutoTranslator实现Unity游戏实时翻译:新手完全指南
如何用XUnity.AutoTranslator实现Unity游戏实时翻译:新手完全指南 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 你是否曾经因为语言障碍而错过精彩的Unity游戏?XUnity.AutoTrans…...
GLM-4v-9B功能体验:上传图片问问题,AI助手秒级回答
GLM-4v-9B功能体验:上传图片问问题,AI助手秒级回答 1. 模型概述 GLM-4v-9B是智谱AI于2024年开源的90亿参数视觉-语言多模态模型,具有以下核心特性: 多模态架构:基于GLM-4-9B语言模型底座,加入视觉编码器…...
如何评估一个SEO策略的效果_如何利用local SEO来提高网站曝光度
如何评估一个SEO策略的效果 在当今数字化时代,搜索引擎优化(SEO)已经成为了网站提升曝光度和吸引流量的关键手段。一个好的SEO策略可以帮助网站在搜索结果中获得更高的排名,从而吸引更多的潜在客户。如何评估一个SEO策略的效果呢…...
vLLM部署Qwen模型报错‘找不到libcuda.so’?别慌,一个环境变量就搞定
vLLM部署Qwen模型报错"找不到libcuda.so"的深度解决方案 当你在私有化部署vLLM框架运行Qwen大语言模型时,遇到/usr/bin/ld: cannot find -lcuda这类链接错误,这实际上是Linux系统中动态链接器无法定位CUDA驱动库的典型表现。本文将带你深入理…...
Ostrakon-VL 代码辅助新体验:像使用 Codex 一样生成图像处理代码
Ostrakon-VL 代码辅助新体验:像使用 Codex 一样生成图像处理代码 1. 视觉编程的新可能 想象一下这样的场景:你看到一张经过"老照片修复"处理的图片效果,想在自己的项目中实现类似风格,却不知道从何下手编写代码。传统…...
利用卷积神经网络原理优化万象熔炉·丹青幻境的图像生成效果
利用卷积神经网络原理优化万象熔炉丹青幻境的图像生成效果 最近在玩一个叫“万象熔炉丹青幻境”的AI图像生成工具,效果挺惊艳的,但有时候总觉得生成的图片差点意思——要么细节不够清晰,要么风格不是我想要的。这让我想起了以前做计算机视觉…...



