当前位置: 首页 > news >正文

聚合统一,SpringBoot实现全局响应和全局异常处理

目录

前言

全局响应

数据规范

状态码(错误码)

全局响应类

使用

优化

全局异常处理

为什么需要全局异常处理

业务异常类

全局捕获

使用

优化

总结


前言

        在悦享校园1.0版本中的数据返回采用了以Map对象返回的方式,虽然较为便捷但也带来一些问题。一是在Controller中所有方法均需要实例化一个Map对象。二是当返回数据较多时使用put方式添加信息会容易出现遗漏的问题。在异常处理方面,虽然该版本中对所有异常通过继承RuntimeException的方式来进行封装,但业务异常较多时这一操作就显得冗余,且需要使用上述提到的Map对象包装异常信息。对于以上问题在2.0版本中通过结合SpringBoot来进行优雅的解决。

全局响应

数据规范

一般来讲我们提供给前端接口调用的返回值为如下的JSON格式,其包含结果状态,状态码,响应信息和响应数据。通常会使用@ResponseBody注解配合一个响应类来实现这一功能。但需要注意的是,当方法返回值为String类型时,@ResponseBody注解并不会将其转为JSON格式,需要手动进行转换。

{"success": true,"code": 0,"message": "操作成功","data": "Hello"
}

状态码(错误码)

通过第一步数据规范可知,当接口被调用后会返回对应信息,若调用成功时返回固定的状态码即可,但调用失败时则需要不同的状态码来标识。为解决这个问题这里使用枚举的方式来定义出现异常时的错误信息。(此处的枚举对象名称可以自定义)

 块的错误。(此处的枚举对象名称可以自定义)

@AllArgsConstructor
@Getter
public enum ExceptionCodeEnum {// 操作成功EC0(0,"操作成功"),// 通用模块错误EC10000(10000,"系统内部错误"),EC10001(10001,"参数错误"),EC10002(10002,"资源不存在"),// 用户模块错误EC20000(20000,"用户名已被占用"),EC20001(20001,"用户不存在"),EC20002(20002,"用户名或密码错误"),// 其它模块..../*** 异常代码*/private Integer code;/*** 描述信息*/private String message;
}

全局响应类

此处创建一个泛型类来实现全局返回信息的格式统一,并且提供返回结果不同状态下的构造方法。

@Data
@Builder
@AllArgsConstructor
public class ResultDataVO<T> {/*** 调用结果状态*/private Boolean success;/*** 响应代码*/private Integer code;/*** 详细信息*/private String message;/*** 返回数据,数据为空则不返回*/@JsonInclude(JsonInclude.Include.NON_NULL)private T data;/*** 操作成功时返回的数据* @param result* @param <T>* @return*/public static <T> ResultDataVO<T> success(T result) {return ResultDataVO.<T>builder().success(true).code(ExceptionCodeEnum.EC0.getCode()).message(ExceptionCodeEnum.EC0.getMessage()).data(result).build();}/*** 操作失败* @param <T>* @param exceptionCodeEnum 错误类型枚举* @return*/public static <T> ResultDataVO<T> failure(ExceptionCodeEnum exceptionCodeEnum){return ResultDataVO.<T>builder().success(false).code(exceptionCodeEnum.getCode()).message(exceptionCodeEnum.getMessage()).data(null).build();}/*** 操作失败,返回信息* @param exceptionCodeEnum 错误信息列表* @param result 对应失败信息对象* @param <T>* @return*/public static <T> ResultDataVO<T> failure(ExceptionCodeEnum exceptionCodeEnum, T result){return ResultDataVO.<T>builder().success(false).code(exceptionCodeEnum.getCode()).message(exceptionCodeEnum.getMessage()).data(result).build();}
}

使用

通过以上操作已经实现了一个基础的全局数据响应处理,可以通过如下方式来使用。

@GetMapping("/{id}")public ResultDataVO getMsg(@RequestParam(required = false) String name,@Max(value = 10,message = "最大值不能超过10")@PathVariable(name = "id") int uid) {String result = "Hello,"+name+" id "+uid;return ResultDataVO.success(result);}

优化

虽然到这里我们已经基本实现了全局响应,但如果不想要在每个方法中调用ResultDataVO的success方法,可以通过如下方式解决。这里新建处理类实现了ResponseBodyAdvice接口,该接口包含三个方法,supports、beforeBodyWrite、handleEmptyBody。

supports用于指明方法是否需要对进入的方法进行后续包装处理,默认返回true,即对所有方法处理。

beforeBodyWrite用于在控制器方法返回结果后,但在响应体写入之前调用。可以在此方法中修改body对象,如包装、添加元数据等。在该方法中将使用ResultDataVO的success方法进行包装,由此将可以省去在Controller方法中重复调用success方法。

handleEmptyBody用于处理null值,由于ResultDataVO类中已经对null值进行了处理,因此无需重写该方法。

注意:即使在全异处理添加了@RestControllerAdvice注解后,仍需要在Controller类上添加@ResponseBody注解,或者直接使用@RestController注解。因为方法返回值经过invokeAndHandle处理后已经确定,若没有以上注解则默认会按照String类型进行路径映射查找视图,进而返回404错误,而@RestControllerAdvice的相关方法会在invokeAndHandle处理后再进行调用。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionAdvice implements ResponseBodyAdvice<Object> {/*** json格式化操作*/@Resourceprivate ObjectMapper objectMapper;/*** 是否开启对所有方法的处理,可以在此方法中添加条件使其支持对特定方法的处理。*/@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true;}/*** 用于在控制器方法返回结果后,但在响应体写入之前调用。可以此处对数据进行包装等操作*/@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {/*** 未被捕获的错误进行拦截*/if(body == null){log.error("未处理的异常信息,请检查错误日志");return ResultDataVO.failure(ExceptionCodeEnum.EC10000);}/*** 返回类型为String则需要手动序列化*/if (body instanceof String) {return objectMapper.writeValueAsString(ResultDataVO.success(body));}/*** 已被包装为全局VO对象直接返回*/if (body instanceof ResultDataVO) {return body;}/*** 判断是否为404,500等错误类型*/if (body instanceof LinkedHashMap) {LinkedHashMap<String, Object> httpErrorCode = (LinkedHashMap<String, Object>) body;Integer code = (Integer) httpErrorCode.get("status");String message = (String) httpErrorCode.get("error");return new ResultDataVO(false, code, message, null);}return ResultDataVO.success(body);}
}

全局异常处理

为什么需要全局异常处理

使用全局异常处理更加灵活和规范化, 所有错误信息会被封装后返回给前端,避免暴露业务细节。

业务异常类

由于代码在运行过程中会出现异常,通常我们会使用 try...catch 方式来捕获并处理,在此之后我们需要返回错误信息知调用者当前状况。由于我们处理的异常多为RuntimeException的子类,因此可以通过编写一个业务异常类来实现总的异常信息处理,与以往不同在这里并不会为所有的业务异常创建具体的异常类,将使用前文中的错误码来配合使用。

@Getter
public class BusinessException extends RuntimeException {/*** 错误对象枚举*/private ExceptionCodeEnum codeEnum;/*** 根据传入的异常枚举解析异常相关信息。* @param codeEnum*/public BusinessException(ExceptionCodeEnum codeEnum){this.codeEnum = codeEnum;}
}

全局捕获

由于已经定义了总的异常处理类,因此在使用时只需要通过抛出 BusinessException 对象即可。但我们需要在代码中写入大量的try-catch语句来捕获处理异常。并且对于错误信息的返回需要符合在全局响应中的数据规范,也就是说需要像全局响应一样统一调用ResultDataVO的failure方法。

在前文创建的GlobalExceptionAdvice类上有一个@RestControllerAdvice注解,该注解将使所有的异常都进入到此处被处理同时也可以用于全局的数据绑定、格式化等。

既然所有的异常都进入该类处理,那么如何处理呢?这里使用@ExceptionHandler注解,使用它可以指定当前方法处理哪种类型的异常,示例代码如下。通过在方法体内调ResultDataVO的failure方法来完成返回数据格式的规范,这里仅列举了三个异常处理,可自行添加更多的异常类。

    /*** 数据格式转换错误*/@ExceptionHandler(DataFormatException.class)@ResponseBodypublic ResultDataVO dataFormatExceptionHandler(DataFormatException e) {log.error("捕获数据格式转换错误异常", e);return ResultDataVO.failure(ExceptionCodeEnum.EC10001);}/*** 业务异常捕获** @param businessException* @return*/@ExceptionHandler(value = BusinessException.class)public ResultDataVO handleBusinessException(BusinessException businessException) {log.error("捕获业务异常", businessException);return ResultDataVO.failure(businessException.getCodeEnum());}/*** 系统级异常** @param throwable*/@ExceptionHandler(value = Throwable.class)public ResultDataVO handleThrowable(Throwable throwable) {log.error("捕获系统级异常", throwable);return ResultDataVO.failure(ExceptionCodeEnum.EC10000);}

使用

通过上述操作可以实现一定程度上对try-catch的消除,示例代码如下

    /*** 统一异常处理* @return*/@GetMapping("/error")public ResultDataVO getError(){// try...catchint res = 1 / 0;return ResultDataVO.success(res);}

优化

虽然采用上述方式已经实现了对异常的统一拦截处理并返回,但若异常产生的源头并非Crontroller中出现而是在系统内部时则有可能导致返回结果出现问题,该问题已经在GlobalExceptionAdvice类beforeBodyWrite方法中做了处理,当body对象为空时则仍然会调用ResultDataVO的failure方法。

        // 用于处理未被正常捕获的异常if(body == null){log.error("未处理的异常信息,请检查错误日志");return ResultDataVO.failure(ExceptionCodeEnum.EC10000);}// ......

总结

通过使用@RestControllerAdvice和@ExceptionHandler注解和错误码以及对应处理/响应类即可实现全局异常的统一处理,其中GlobalExceptionAdvice类对全局响应和异常处理做了合并,可按照业务需求自行拆分。

相关文章:

聚合统一,SpringBoot实现全局响应和全局异常处理

目录 前言 全局响应 数据规范 状态码(错误码) 全局响应类 使用 优化 全局异常处理 为什么需要全局异常处理 业务异常类 全局捕获 使用 优化 总结 前言 在悦享校园1.0版本中的数据返回采用了以Map对象返回的方式&#xff0c;虽然较为便捷但也带来一些问题。一是在…...

【C/C++笔试练习】——数组名和数组名、switch循环语句、数据在计算机中的存储顺序、字符串中找出连续最长的数字串、数组中出现次数超过一半的数字

文章目录 C/C笔试练习1.数组名和&数组名&#xff08;1&#xff09;数组名和&数组名的差异&#xff08;2&#xff09;理解数组名和指针偏移&#xff08;3&#xff09;理解数组名代表的含义&#xff08;4&#xff09;理解数组名代表的含义 2.switch循环语句&#xff08;6…...

力扣每日一题(+日常水题|树型dp)

740. 删除并获得点数 - 力扣&#xff08;LeetCode&#xff09; 简单分析一下: 每一个数字其实只有2个状态选 or 不 可得预处理每一个数初始状态(不选为0,选为所有x的个数 * x)累加即可 for(auto &x : nums)dp[x][1] x;每选一个树 i 删去 i 1 和 i - 1 故我们可以将 i…...

使用perming加速训练可预测的模型

监督学习模型的训练流程 perming是一个主要在支持CUDA加速的Windows操作系统上架构的机器学习算法&#xff0c;基于感知机模型来解决分布在欧式空间中线性不可分数据集的解决方案&#xff0c;是基于PyTorch中预定义的可调用函数&#xff0c;设计的一个面向大规模结构化数据集的…...

【数据库】存储引擎InnoDB、MyISAM、关系型数据库和非关系型数据库、如何执行一条SQL等重点知识汇总

目录 存储引擎InnoDB、MyISAM的适用场景 关系型和非关系型数据库的区别 MySQL如何执行一条SQL的 存储引擎InnoDB、MyISAM的适用场景 InnoDB 是 MySQL 默认的事务型存储引擎&#xff0c;只有在需要它不支持的特性时&#xff0c;才考虑使用其它存储引擎。实现了四个标准的隔…...

车道线分割检测

利用opencv&#xff0c;使用边缘检测、全局变化梯度阈值过滤、算子角度过滤、HLS阈值过滤的方法进行车道线分割检测&#xff0c;综合多种阈值过滤进行检测提高检测精度。 1.利用cv2.Sobel()计算图像梯度(边缘检测) import cv2 import numpy as np import matplotlib.pyplot a…...

树莓集团又一力作,打造天府蜂巢成都直播产业园样板工程

树莓集团再次推出惊艳之作&#xff0c;以打造成都天府蜂巢直播产业园为目标。该基地将充分展现成都直播产业园的巨大潜力与无限魅力&#xff0c;成为一个真正的产业园样板工程。 强强联手 打造未来 成都天府蜂巢直播产业园位于成都科学城兴隆湖高新技术服务产业园内&#xff0…...

ubuntu 软件包管理之二制作升级包

Deb 包(Debian 软件包)是一种用于在 Debian 及其衍生发行版(例如 Ubuntu)中分发和安装软件的标准包装格式。它们构成了 Debian Linux 发行版中的软件包管理系统的核心组成部分,旨在简化软件的分发、安装、更新和卸载流程。在本篇文章中,我们将深入探讨以下内容: Deb 包基…...

TCP/IP网络江湖——数据链路层的防御招式(数据链路层下篇:数据链路层的安全问题)

目录 引言 一、 数据链路层的隐私与保密 二、数据链路层的安全协议与加密...

ios项目安装hermes-engine太慢问题

问题说明 ios工程&#xff0c;在使用"pod install"安装依赖的时候&#xff0c;由于超时总是报错 $ pod install ... Installing hermes-engine (0.71.11)[!] Error installing hermes-engine [!] /usr/bin/curl -f -L -o /var/folders/4c/slcchpy55s53ysmz_1_q_gzw…...

构建个人云存储:本地电脑搭建SFTP服务器,开启公网访问,轻松共享与管理个人文件!

本地电脑搭建SFTP服务器&#xff0c;并实现公网访问 文章目录 本地电脑搭建SFTP服务器&#xff0c;并实现公网访问1. 搭建SFTP服务器1.1 下载 freesshd 服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2. 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内…...

springboot 下载文件为excel数据,中文自定义单元格宽度

/**2 * Description:表格自适应宽度(中文支持)3 * Author: 4 * param sheet sheet5 * param columnLength 列数6 */7 private static void setSizeColumn(HSSFSheet sheet, int columnLength) {8 for (int columnNum 0; columnNum < …...

机器学习 面试/笔试题

1. 生成模型 VS 判别模型 生成模型&#xff1a; 由数据学得联合概率分布函数 P ( X , Y ) P(X,Y) P(X,Y),求出条件概率分布 P ( Y ∣ X ) P(Y|X) P(Y∣X)的预测模型。 朴素贝叶斯、隐马尔可夫模型、高斯混合模型、文档主题生成模型&#xff08;LDA&#xff09;、限制玻尔兹曼机…...

某企查ymg_ssr列表详情

js篇— 今天来看下某企查的列表详情–侵删 header发现这个参数 先断点一下 然后上一步 就到了这个地方 就开始扣一下这个js 三大段&#xff0c;先不解混淆了&#xff0c; 给a粘贴出来 &#xff0c;去掉自执行 给结果稍微改一下 缺windows&#xff0c;开始补环境 直接上…...

使用YOLOv5的backbone网络识别图像天气 - P9

目录 环境步骤环境设置包引用声明一个全局的设备 数据准备收集数据集信息构建数据集在数据集中读取分类名称划分训练、测试数据集数据集划分批次 模型设计编写维持卷积前后图像大小不变的padding计算函数编写YOLOv5中使用的卷积模块编写YOLOv5中使用的Bottleneck模块编写YOLOv5…...

TikTok海外扩张:亚马逊的新对手崛起

随着社交媒体和电子商务的融合&#xff0c;TikTok正迅速崭露头角&#xff0c;成为亚马逊等传统电商巨头的潜在竞争对手。这一新兴平台的快速发展引发了广泛的关注&#xff0c;特别是在全球范围内。 在这篇文章中&#xff0c;我们将探讨TikTok海外扩张的战略&#xff0c;以及它…...

CSS详细基础(五)选择器的优先级

本节介绍选择器优先级&#xff0c;优先级决定了元素最终展示的样式~ 浏览器是通过判断CSS优先级&#xff0c;来决定到底哪些属性值是与元素最为相关的&#xff0c;从而作用到该元素上。CSS选择器的合理组成规则决定了优先级&#xff0c;我们也常常用选择器优先级来合理控制元素…...

LLM-TAP随笔——有监督微调【深度学习】【PyTorch】【LLM】

文章目录 5、 有监督微调5.1、提示学习&语境学习5.2、高效微调5.3、模型上下文窗口扩展5.4、指令数据构建5.5、开源指令数据集 5、 有监督微调 5.1、提示学习&语境学习 提示学习 完成预测的三个阶段&#xff1a;提示添加、答案搜索、答案映射 提示添加 “[X] 我感到…...

kafka伪集群部署,使用docker环境拷贝模式

线上启动容器的方式是复制容器的运行环境出来&#xff0c;然后进行运行脚本的形式 1&#xff1a;在home/kafka目录下创建如下目录 2&#xff1a;复制kafka1容器内的数据/bitnami/kafka/data&#xff0c;直接放在1992_data里面&#xff0c;同理,复制kafka2容器内的数据/bitnami/…...

工业交换机一般的价格是多少呢?

工业交换机是一种应用于工业领域的网络设备。它的性能和所有安全指标都比一般商业交换机更加稳定。所以&#xff0c;工业级交换机的价格相对于普通的交换机要稍稍昂贵一些。工业交换机一般的价格是多少呢&#xff1f;每个厂家的交换机价格是不是都一样呢&#xff1f; 首先&…...

QT使用前的知识

QT使用前的知识 常用的快捷键 源文件的内容解释 .pro文件的解释 头文件的解释 构建新的对象—组成对象树 槽函数 自定的信号和槽 槽函数的信号是一个重载函数时 电机按钮触发信号 调用无参数的信号 断开信号...

Unity制作旋转光束

Unity制作旋转光束 大家好&#xff0c;我是阿赵。 这是一个在很多游戏里面可能都看到过的效果&#xff0c;在传送门、魔法阵、角色等脚底下往上散发出一束拉丝形状的光&#xff0c;然后在不停的旋转。 这次来在Unity引擎里面做一下这种效果。 一、准备材料 需要准备的素材很简…...

考研王道强化阶段(二轮复习)“算法题”备考打卡表 记录

问题&#xff1a;做408真题_2010_42题&#xff0c;即王道书 2.2.3_大题_10 思路&#xff1a; 回头补 代码&#xff1a; int moveL(SqlList &L,SqlList &S,int p) {// 健壮性表达if( L.len 0 ){return 0;}// 调用另外一个顺序表存储pos前面的元素for( int i0;i<p;…...

UE4/5数字人MetaHuman通过已有动画进行修改

目录 通过已有动画修改动画 开始制作 创建一个关卡序列 将动画序列烘焙到控制绑定 打开我们自己创建的动画序列 之后便是烘焙出来 通过已有动画修改动画 首先架设我们已经有相关的MetaHuman的动画&#xff0c;但是这个动画因为是外部导入进来的&#xff0c;所以可能会出…...

在Mac M2本地注册GitLab runner

最近在搞公司的CI/CD&#xff0c;简单记录下部分过程 安装runner sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64" 创建runner 这个步骤需要在gitlab中进行&am…...

「大数据-2.2」使用命令操作HDFS文件系统

目录 一、HDFS文件系统基本信息 1. HDFS的路径表达形式 2.HDFS和Linux的根目录的区分 二、 使用命令操作HDFS文件系统 0. Hadoop的两套命令体系 1. 创建文件夹 2. 查看指定目录下内容 3. 上传文件到HDFS指定目录下 4. 查看HDFS文件内容 5. 下载HDFS文件 6. 拷贝HDFS文件 7.…...

面试买书复习就能进大厂?

大家好&#xff0c;我是苍何。 现在进大仓是越来越难了&#xff0c;想通过简单的刷题面试背书&#xff0c;比几年前难的不少&#xff0c; 但也并非毫无希望&#xff0c;那究竟该如何准备才能有希望进大厂呢&#xff1f; 我总结了 4 点&#xff1a; 1、不差的学历背景 2、丰富…...

使用Http Interface客户端解析text/html类型参数

前言 Spring6和Spring Boot3的正式发布也有一段时间了&#xff0c;最低支持的java版本也是直接跳到了17。而且最近java21也出来了&#xff0c;作为一个javaer&#xff0c;你不会还在坚守java8吧&#xff1f; Http Interface是Spring6新推出的一个声明式http客户端&#xff0c;…...

Linux - linux命令进阶

打包压缩解压 基本概述 打包 将多数文件或目录汇总成一个整体 打包默认没有压缩功能&#xff0c;不节省磁盘空间 压缩 将大文件压缩成小文件 可以节省磁盘空间 打包压缩 将一堆零散的文件打包到一起&#xff0c;然后再压缩&#xff0c;可以节省磁盘空间 打包命令 命令格式 ta…...

排序篇(一)----插入排序

1.直接插入排序 插入排序的思想: 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 你可以想像成打牌一样,比如说斗地主,一张一张的摸牌,然后把手上的这些牌变成手续的排列.…...

哪里有网站制作建设/江西seo推广软件

2019独角兽企业重金招聘Python工程师标准>>> uwsgi安装 ubuntu安装uwsgi遇到的问题 Command "/root/myenv/bin/python3.4 -c "import setuptools, tokenize;__file__/tmp/pip-build-7cr2or3v/uwsgi/setup.py;exec(compile(getattr(tokenize, open, open)(…...

专业做消防工程师的正规网站/深圳网站关键词优化推广

2019独角兽企业重金招聘Python工程师标准>>> 以项目名为myTest,当前类名为test(其中package com.sun.app)&#xff0c;test.txt为test同目录下为例&#xff1a; 全路径&#xff1a; 1.当前类test.class文件的URI目录 URL url test.class.getResource("")…...

wordpress禁止制定ip访问/seo销售好做吗

和向左密集比起来向右密集只需要进行小小的额修改&#xff0c;就是更新的时候从右往左更新。。 自己写的被卡死时间。不知道怎么回事&#xff0c;和网上博客的没啥区别。。 /* 给定一个n个数的序列a 每次询问区间[l,r],求出去重后区间中每个数的第一次出现的位置pi pi构成一个新…...

塘沽网站建设优化/电商运营转行后悔了

生活的许多因素可能会引起皮肤老化&#xff0c;皮肤松弛&#xff0c;让皮肤状态看起来更老。为了让皮肤变得更好&#xff0c;我们必须注意饮食&#xff0c;调整心情&#xff0c;不仅如此还需要使用美容仪对自己的皮肤进行保养&#xff0c;让我们一起来了解一下如何避免皮肤松弛…...

建筑网官网软件/泉州seo报价

符号键&#xff08;CTRL开头&#xff09; CTRL1 PROPCLOSEOROPEN 对象特性管理器CTRL2或4 ADCENTER 设计中心CTRL3 CTOOLPALETTES 工具选项板CTRL8或QC QuickCalc 快速计算器控制键CTRLA AI_SELALL 全部选择CTRLC或CO/CP COPYCLIP或COpy 复制CTRLD或F6 COORDINATE 坐标CTRLE或F…...

景观设计公司利润/谷歌优化是什么意思

ftp服务很重要&#xff0c;这里介绍ftp在linux上不连接mysql数据库的搭建方法&#xff0c;ftp也可以连接mysql&#xff0c;有时间再生成文档。先说明ftp的基本原理&#xff1a;FTP &#xfffd;File Transfer Protocol 文件传输协议。能够在网络上提供文件传输服务&#xff0c;…...