异常封装类统一后端响应的数据格式

news2024/11/24 3:31:32

异常封装类 如何统一后端响应的数据格式

1. 背景

后端作为数据的处理和响应,如何才能和前端配合好,能够高效的完成任务,其中一个比较重要的点就是后端返回的数据格式。

没有统一的响应格式:

// 第一种:
{
    "data": -1
}

// 第二种:
{
  "timestamp": "2021-07-08T08:05:15.423+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/wrong"
}

// 第三种:
hello,javadaily

如果你作为一个后端开发的人员将这样式的数据返回给前端的话,那你肯定会被骂屎,如果前后端都是你干那当我没说,所以一个格式规范的响应是至关重要的

有统一的响应格式:

// 规范的返回响应的格式
{
  "message":"ok",
  "code": 0,
  "data":{
      "id": 007,
      "userName": "xdm"
  }
}

认识到了响应格式的规范性那么我们就来讲解一个如何实现

2. 代码实现

  1. 实现逻辑

    • 编写一个异常信息枚举类(自定义错误码),将所有可能出现的异常信息通过枚举的方式列出来,方便后续使用
    • 编写一个通用的异常返回类(构建一个语法糖)参数可以是自定义的也可以是枚举类传入的
    • 编写一个异常返回的工具类,包含成功的返回和失败的返回
    • 编写一个基础的异常类来继承运行时异常(目的就是为了能被全局异常处理器捕获到)
    • 编写一个全局异常处理器通过ExceptionHandler来识别到不同的异常(自定的异常还是运行时异常)
  2. 具体实现

    1. 自定义错误码

      public enum ErrorCode {
      
          SUCCESS(0, "ok"),
          PARAMS_ERROR(40000, "请求参数错误"),
          NOT_LOGIN_ERROR(40100, "未登录"),
          NO_AUTH_ERROR(40101, "无权限"),
          NOT_FOUND_ERROR(40400, "请求数据不存在"),
          SYSTEM_ERROR(50000, "系统内部异常"),
          OPERATION_ERROR(50001, "操作失败");
      
          /**
           * 错误信息
           */
          private final String message;
      
          /**
           * 状态码
           */
          private final int code;
      
          ErrorCode(int code, String message) {
              this.message = message;
              this.code = code;
          }
      
          public String getMessage() {
              return message;
          }
      
          public int getCode() {
              return code;
          }
      }
      
    2. 通用的异常返回类

      // 在返回的类型中 数据data的响应是一个泛型
      public class BaseResponse<T> implements Serializable {
      
          private static final long serialVersionUID = -3209965291812271422L;
      
          // 异常详细信息
          private String message;
      
          // 异常编码
          private int code;
      
          // 异常数据  泛型
          private T data;
      
          public BaseResponse(int code, T data, String message) {
              this.code = code;
              this.data = data;
              this.message = message;
          }
      
          // 不传错误信息的构造方法
          public BaseResponse(int code, T data) {
              this(code, data, "");
          }
      
          // 通过枚举类来作为异常参数传入
          public BaseResponse(ErrorCode errorCode) {
              this(errorCode.getCode(), null, errorCode.getMessage());
          }
      }
      
    3. 返回工具类

      public class ResultUtils {
          /**
           * 成功的返回   需要使用泛型进行数据的返回
           * @param data
           * @return
           * @param <T>
           */
          public static <T> BaseResponse<T> success(T data) {
              return new BaseResponse(0, data, "ok");
          }
      
          /**
           * 失败的返回 使用自定义错误码
           * @param errorCode
           * @return
           */
          public static BaseResponse error(ErrorCode errorCode) {
              return new BaseResponse(errorCode.getCode(), null, errorCode.getMessage());
          }
      
          /**
           * 失败的返回  没有使用自定义错误码  自定义的异常信息 + 错误码
           * @param code
           * @param message
           * @return
           */
          public static BaseResponse error(int code, String message) {
              return new BaseResponse(code, null, message);
          }
      
          /**
           * 自定义错误码 + 自定义的异常信息
           * @param errorCode
           * @param message
           * @return
           */
          public static BaseResponse error(ErrorCode errorCode, String message) {
              return new BaseResponse(errorCode.getCode(), null, message);
          }
      }
      
    4. 基础的异常类来继承运行时异常(实现全局异常处理)

      public class BusinessException extends RuntimeException {
      
          /**
           * 错误码
           */
          private final int code;
      
          /**
           * 错误码和错误信息的构造方法
           * @param code
           * @param message
           */
          public BusinessException(int code, String message) {
              super(message);
              this.code = code;
          }
      
          /**
           * 通过传入的自定义错误码
           */
          public BusinessException(ErrorCode errorCode) {
              super(errorCode.getMessage());
              this.code = errorCode.getCode();
          }
      
          /**
           * 自定义错误码 + 自定义异常消息
           * @param errorCode
           * @param message
           */
          public BusinessException(ErrorCode errorCode, String message) {
              super(message);
              this.code = errorCode.getCode();
          }
      
          public int getCode() {
              return code;
          }
      }
      
      
    5. 全局异常处理器

      @RestControllerAdvice // 实现bean注入
      @Slf4j
      
      /**
       * 全局异常处理器
       */
      public class GlobalExceptionHandler {
      
          /**
           * 自定义的异常
           * @param e
           * @return
           */
          @ExceptionHandler(BusinessException.class)
          public BaseResponse<?> businessExceptionHandler(BusinessException e) {
              log.error("BusinessException: ", e);
              return ResultUtils.error(e.getCode(), e.getMessage());
          }
      
          /**
           * 运行时异常  系统异常
           * @param e
           * @return
           */
          @ExceptionHandler(RuntimeException.class)
          public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
              log.error("RuntimeException: ", e);
              return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
          }
      }
      
      

      至此一个全局异常的处理我们就实现了,能够在后续的代码编写中方便的返回我们的数据并且规范

3. 具体使用

在正确的返回,最终结果的返回的时候我们只需要使用异常工具类调用其中的成功的响应方法即可;失败的返回我们需要通过抛出异常的形式进行返回,然后全局异常处理器就能捕获到异常并输出。

 @PostMapping("/register")
	// 这里使用通用的异常类的类型
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userLoginRequest) {
        if(userLoginRequest == null) {
            // 这里通过基础异常类来进行返回它继承的是运行时异常会被全局异常处理器捕获到
            // 传入的参数就是我们自定义的错误码(枚举)
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userLoginRequest.getUserAccount();
        String userPassword = userLoginRequest.getUserPassword();
        String checkPassword = userLoginRequest.getCheckPassword();
        if(StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long result = userService.userRegister(userAccount, userPassword, checkPassword);
        // 成功的返回 使用异常工具类
        return ResultUtils.success(result);
    }

我们在使用在线接口文档进行测试的时候就能看到返回的数据是我们想要的格式

image-20240614165426295

总结:

​ 到这里整个异常类的统一处理就实现了,我们可以将这段代码自己保留下来然后直接复制到其他的项目上复用,这样你距离cv工程师又又又近了一步。

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

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

相关文章

UniApp+Vue3使用Vant-微信小程序组件

第一步&#xff1a;打开创建好的UniappVue3的项目 第二步&#xff1a;下载Vant-Weapp npm i vant/weapp -S --production 第三步&#xff1a;修改目录名称 wxcomponents 必须是wxcomponents 第四步&#xff1a;将下载好的vant中的dist目录剪切到当前wxcomponents目录下 第五…

贪心算法学习五

例题一 解法&#xff08;贪⼼&#xff09;&#xff1a; 贪⼼策略&#xff1a; 我们的任何选择&#xff0c;应该让这个数尽可能快的变成 1 。 对于偶数&#xff1a;只能执⾏除 2 操作&#xff0c;没有什么分析的&#xff1b; 对于奇数&#xff1a; i. 当 n 1 的时候…

低代码开发MES系统,一周实现数字化

随着工业4.0和智能制造的兴起&#xff0c;企业对于生产过程的数字化、智能化需求日益迫切。制造执行系统&#xff08;MES&#xff09;作为连接计划层与控制层的关键信息系统&#xff0c;在提升生产效率、优化资源配置、保障产品质量等方面发挥着重要作用。然而&#xff0c;传统…

不可不知的Java SE技巧:如何使用for each循环遍历数组

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

LVGL刷屏优化(基于ESP32)

主要参考资料&#xff1a; 乐鑫ESP-IDF官方手册SPI Flash and External SPI RAM Configuration: https://docs.espressif.com/projects/esp-idf/zh_CN/release-v5.0/esp32s3/api-guides/flash_psram_config.html 目录 驱动和端口优化RAM与PSRAMFLASH SPI与PSRAM SPI LVGL优化修…

使用Vue中的<TransitionGroup/>进入动画不生效不显示问题

Vue中有两个过渡动画组件分别是&#xff1a;<TransitionGroup/> <TransitionGroup/>进入动画不生效不显示问题 &#xff0c;在渲染列表上加上v-if&#xff0c;看代码&#xff0c;让他每次渲染都重新渲染 加上v-if即可 <template> <TransitionGroup nam…

Day01_Ajax入门

文章目录 学习目标一、AJAX 概念和 axios 使用1. 目标2. 讲解2.1 什么是 AJAX ?2.2 什么是服务器&#xff1f;2.3 为何学 AJAX ?2.4 怎么学 AJAX ?2.5 例子2.6 axios语法 二、认识 URL1. 目标2. 讲解2.1 为什么要认识 URL ?2.2 什么是 URL &#xff1f;2.3 URL的组成 &…

手把手教你改造Sentinel Dashboard 实现配置持久化

一. 概述 Sentinel客户端默认情况下接收到 Dashboard 推送的规则配置后&#xff0c;可以实时生效。但是有一个致命缺陷&#xff0c;Dashboard和业务服务并没有持久化这些配置&#xff0c;当业务服务重启后&#xff0c;这些规则配置将全部丢失。 Sentinel 提供两种方式修改规则…

【C语言】解决C语言报错:Use of Uninitialized Variable

文章目录 简介什么是Use of Uninitialized VariableUse of Uninitialized Variable的常见原因如何检测和调试Use of Uninitialized Variable解决Use of Uninitialized Variable的最佳实践详细实例解析示例1&#xff1a;局部变量未初始化示例2&#xff1a;数组未初始化示例3&…

Linux iptables使用详解

一、Linux系统下使用iptables 在Linux中&#xff0c;常用的防火墙工具是iptables。以下是一些基本的iptables命令&#xff0c;用于配置防火墙规则。 查看现有的iptables规则&#xff1a; sudo iptables -L 清除所有现有的规则&#xff08;慎用&#xff0c;可能导致服务不可用…

基于android开发平台的聊天软件实现(论文+源码)_kaic

摘要&#xff1a;互联网时代的到来使得手机通讯变得更为普及和强大&#xff0c;人们可以随时随地地进行交流。由于工作的繁忙以及生活节奏的加快&#xff0c;人们无法有更多时间展开面对面的交谈&#xff0c;导致在线聊天软件的使用更加频繁&#xff0c;所以本文尝试设计了一款…

代码随想录算法训练营第六十二天 | 739.每日温度、496.下一个更大元素 I、503.下一个更大元素II

739.每日温度 文字讲解&#xff1a;代码随想录 视频讲解&#xff1a;单调栈&#xff0c;你该了解的&#xff0c;这里都讲了&#xff01;LeetCode:739.每日温度_哔哩哔哩_bilibili 解题思路 思路一&#xff1a;暴力双循环 O&#xff08;n^2&#xff09; 思路二&#xff1a;单…

医学人工智能项目如何申请基金?

小罗碎碎念 本期推文面向的群体 青年教师有志硕博/博后 尤其适合一直认真追小罗推文的老师/同学&#xff0c;你们会发现自己在看这篇推文的时候&#xff0c;遇到自己领域的项目时&#xff0c;文思如泉涌&#xff0c;仿佛马上就能把本子写好&#xff0c;哈哈。&#xff08;运用…

phpStudy安装sqli-labs

phpStudy安装sqli-labs git地址&#xff1a;https://github.com/Audi-1/sqli-labs 点击管理–>根目录 将git下载的sqli-labs文件放进去并解压 进入sql-connections修改 修改db-creds.inc文件为自己数据库的账号密码 更改php版本为5.*&#xff0c;因为这个程序只能在php 5.…

MacOS之Rosetta技术的引入

提示&#xff1a;宝子们&#xff0c;希望文章对你们有所帮助&#xff0c; 请一键三连支持博主下吧&#xff5e; 文章目录 前言一、Rosetta 是什么&#xff1f;二、关于安装Rosetta三、关于Rosetta的问题分享总结 前言 博主的个人开发环境和配置说明&#xff1a; MacOS Montere…

保险丝选取

保险丝 1、保险丝的电压要≥输入最大电压 2、确定外形尺寸 3、确定外形尺寸安全标志如UL、IEC等 4、确定最小额定电流 5、确定I^2t 电压额定值 (Voltage Ratings)&#xff1a; 保险丝的电压额定值必须大于或者等于断开电路的最大电压。由于保险丝的阻值非常低&#xff0c…

[Qt的学习日常]--常用控件1

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、什么是控…

Vue49-props属性

一、当同一个组件标签被使用多次 因为data属性写的是函数形式&#xff01; 二、需求&#xff1a;老王也想用<Student>组件&#xff0c;但是需要动态把老王想要的值传进来。 2-1、使用props属性接收参数 使用props属性&#xff0c;接收的这三个参数&#xff0c;是被保存在…

笔记 | 用go写个docker

仅作为自己学习过程的记录&#xff0c;不具备参考价值 前言 看到一段非常有意思的话&#xff1a; 很多人刚接触docker的时候就会感觉非常神奇&#xff0c;感觉这个技术非常新颖&#xff0c;其实并不然&#xff0c;docker使用到的技术都是之前已经存在过的&#xff0c;只不过旧…

【笔记】为什么不同硬件的1T实际硬盘容量硬盘是954GB或者931GB?

问题描述 不管是电脑还是移动硬盘&#xff0c;厂家描述的1T硬盘容量都不是计算机知识领域内真正的1T大小&#xff0c;硬盘容量实际是小于1TB的。 另外还发现对于1TB的不同厂家设备有着实际不同的磁盘容量&#xff0c;比如为什么有的1T电脑硬盘是954GB&#xff0c;而移动硬盘是…