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

Spring Boot接口返回统一格式

统一的标准数据格式好处

SpringBoot返回统一的标准数据格式主要有以下几点好处:

  • 增强接口的可读性和可维护性,使得前端开发人员能够更加清晰地理解接口返回的数据结构,从而提高开发效率。

  • 降低前后端耦合度,当后端需要修改返回数据结构时,只需要调整统一的数据格式,而不用修改大量的前端代码。

  • 有利于统一异常处理,对于出错时的返回数据格式也是一致的,便于前端统一处理错误信息。

  • 当接口版本的升级和兼容时,可以通过统一的数据格式进行向下兼容或者向上兼容,减少接口变更带来的影响

格式不同的痛楚

一般情况下,SpringBoot服务的返回格式有如下几种:

第一种:返回String

@GetMapping("/hello")
public String getStr() {return "hello";
}

此时调用接口获取到的返回值是这样:

hello

第二种:返回自定义对象

@GetMapping("/aniaml")
public Aniaml getAniaml(){Aniaml aniaml = new Aniaml(1,"pig");return aniaml;
}

此时调用接口获取到的返回值是这样:

{"id": 1,"name": "pig"
}

第三种:接口异常

@GetMapping("/error")
public int error(){int i = 10/0;return i;
}

此时调用接口获取到的返回值是这样:

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

看了上边的几种情况,不难发现,一个接口在不同情况下,返回的数据格式竟然截然不同?那作为API的使用方估计就要骂娘了。此时,返回统一的标准数据格式就显得很有必要。

标准格式

一个标准的返回格式应包含以下三部分:

  • Status(状态):由后端统一定义各种返回结果的状态码。

  • Message(描述):描述本次接口调用的结果信息。

  • Data(数据):包含本次返回的具体数据内容。

{"status":"100","message":"操作成功","data":"hello"
}

当然了这并不是绝对的,在有了主要的字段后,可以按需加入其他扩展值,比如我们就在返回对象中添加了接口调用时间timestamp等。

定义返回对象

@Data
public class ResultData<T> {private int status;private String message;private T data;private long timestamp ;public ResultData (){this.timestamp = System.currentTimeMillis();}public static <T> ResultData<T> success(T data) {ResultData<T> resultData = new ResultData<>();resultData.setStatus(ReturnCode.RC100.getCode());resultData.setMessage(ReturnCode.RC100.getMessage());resultData.setData(data);return resultData;}public static <T> ResultData<T> fail(int code, String message) {ResultData<T> resultData = new ResultData<>();resultData.setStatus(code);resultData.setMessage(message);return resultData;}}

定义状态码

public enum ReturnCode {/**操作成功**/RC100(100,"操作成功"),/**操作失败**/RC999(999,"操作失败"),/**服务限流**/RC200(200,"服务开启限流保护,请稍后再试!"),/**服务降级**/RC201(201,"服务开启降级保护,请稍后再试!"),/**热点参数限流**/RC202(202,"热点参数限流,请稍后再试!"),/**系统规则不满足**/RC203(203,"系统规则不满足要求,请稍后再试!"),/**授权规则不通过**/RC204(204,"授权规则不通过,请稍后再试!"),/**access_denied**/RC403(403,"无访问权限,请联系管理员授予权限"),/**access_denied**/RC401(401,"匿名用户访问无权限资源时的异常"),/**服务异常**/RC500(500,"系统异常,请稍后重试"),CLIENT_AUTHENTICATION_FAILED(1001,"客户端认证失败"),USERNAME_OR_PASSWORD_ERROR(1002,"用户名或密码错误"),UNSUPPORTED_GRANT_TYPE(1003, "不支持的认证模式");/**自定义状态码**/private final int code;/**自定义描述**/private final String message;ReturnCode(int code, String message){this.code = code;this.message = message;}public int getCode() {return code;}public String getMessage() {return message;}
}

统一返回格式

经过上边我们定义的数据格式,再次调用API,在Controller层通过ResultData.success()对返回结果进行包装后返回给前端。

@GetMapping("/hello")
public String getStr() {return ResultData.success("hello");
}

此时调用接口获取到的返回值已经是标准的格式,符合我们预期的效果。

{"status": 100,"message": "hello","data": null,"timestamp": 1625736481648
}

最大的弊端就是我们后面每写一个接口都需要调用ResultData.success()这行代码对结果进行包装,重复劳动,浪费体力;而且还很容易被其他老鸟给嘲笑。所以呢我们需要对代码进行优化,目标就是不要每个接口都手工制定ResultData返回值。

高级实现方式

要优化这段代码很简单,我们只需要借助SpringBoot提供的ResponseBodyAdvice即可。


ResponseBodyAdvice的作用:拦截Controller方法的返回值,统一处理返回值/响应体,一般用来统一返回格式,加解密,签名等等。

先来看下ResponseBodyAdvice的源码:

public interface ResponseBodyAdvice<T> {/*** 是否支持advice功能* true 支持,false 不支持*/boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);/*** 对返回的数据进行处理*/@NullableT beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}

我们只需要编写一个具体实现类即可

/*** @author jam* @date 2021/7/8 10:10 上午*/
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {if(o instanceof String){return objectMapper.writeValueAsString(ResultData.success(o));}        return ResultData.success(o);}
}

需要注意两个地方:
@RestControllerAdvice注解

  • @RestControllerAdvice@RestController注解的增强,可以实现三个方面的功能:
  1. 全局异常处理

  2. 全局数据绑定

  3. 全局数据预处理

  • String类型判断
if(o instanceof String){return objectMapper.writeValueAsString(ResultData.success(o));
} 

这段代码一定要加,如果Controller直接返回String的话,SpringBoot是直接返回,故我们需要手动转换成json。
经过上面的处理我们就再也不需要通过ResultData.success()来进行转换了,直接返回原始数据格式,SpringBoot自动帮我们实现包装类的封装。

@GetMapping("/hello")
public String getStr(){return "hello";
}

此时我们调用接口返回的数据结果为:

@GetMapping("/hello")
public String getStr(){return "hello";
}

是不是感觉很完美,别急,还有个问题在等着你呢。

接口异常问题

此时有个问题,由于我们没对Controller的异常进行处理,当我们调用的方法一旦出现异常,就会出现问题,比如下面这个接口:

@GetMapping("/wrong")
public int error(){int i = 9/0;return i;
}

相关文章:

Spring Boot接口返回统一格式

统一的标准数据格式好处 SpringBoot返回统一的标准数据格式主要有以下几点好处&#xff1a; 增强接口的可读性和可维护性&#xff0c;使得前端开发人员能够更加清晰地理解接口返回的数据结构&#xff0c;从而提高开发效率。 降低前后端耦合度&#xff0c;当后端需要修改返回数…...

Flink如何基于数据版本使用最新离线数据

业务场景 假设批量有一张商户表&#xff0c;表字段中有商户名称和商户分类两个字段。 批量需要将最新的商户名称和分类的映射关系推到hbase供实时使用。 原实现方案 a.原方案内容 为解决批量晚批问题&#xff0c;批量推送hbase表时一份数据产生两类rowkey&#xff1a;T-1和…...

软件开发中的常用性能指标

大家好&#xff01;我是今越。在软件开发中我们经常会遇到一些性能指标&#xff0c;下面就带大家一起来看看。 QPS Queries Per Second&#xff0c;每秒查询率&#xff0c;一台服务器每秒能够响应的查询次数。它是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准…...

cmakelist使用总结

支持能编译成在不同系统上运行程序的方法 我们代码就一份&#xff0c;但有时需要编译成arm32&#xff0c;有时需要编译成x86_64,或更多 1、首先先将代码定义一个名称&#xff1a; #将所有的源文件列为一个集合&#xff0c;集合名字叫做SRC_LISTS set(SRC_LISTS main.cpp A.cpp…...

准备阶段 Unity优化总纲

Unity优化总纲 我们在学习优化课程之前要预先做好准备功能 例如最主要是的接收到一个优化的任务&#xff0c;应该怎么做&#xff0c;其次怎么做&#xff0c;最后怎么做。 也要学习一些专业工具以及专业术语 了解游戏运行机制&#xff0c;在排查期间思路会更清晰 1.优化目的…...

ubuntu防火墙(三)——firewalld使用与讲解

本文是Linux下&#xff0c;用ufw实现端口关闭、流量控制(二) firewalld使用方式 firewalld 是一个动态管理防火墙的工具&#xff0c;主要用于 Linux 系统&#xff08;包括 Ubuntu 和 CentOS 等&#xff09;。它提供了一个基于区域&#xff08;zones&#xff09;和服务&#x…...

zookeeper 搭建集群

基础的java 环境先安好&#xff0c;选择3台虚拟机 ip 不一样 机器应为奇数个 zookeeper 奇数个节点实际上是(2*n-1) 比偶数台机器少一台解决成本,并且能够满足 zookeeper 集群过半选举leader 的规则 # 3台虚拟机 将zookeeper 解压到服务器上 #在 conf/ 目录下 找到zoo_s…...

Java——异常机制(下)

1 异常处理之(捕获异常) (一般处理运行时异常) (try-catch-finally子句) (finally一般用于文件最后关闭) (catch捕获的子类在前父类在后——>不然父类在前面都让父类捕获掉了&#xff0c;会报错) (Exception是父类放在最后&#xff0c;如果前面没有捕获到&#xff0c;就…...

centos 手动安装libcurl4-openssl-dev库

下载源代码 curl downloadshttps://curl.se/download/ 选择需要下载的版本&#xff0c;我下载的是8.11.0 解压 tar -zxvf curl-8.11.0 查看安装命令 查找INSTALL.md&#xff0c;一般在docs文件夹下 –prefix &#xff1a;指定安装路径&#xff08;默认安装在/usr/local&…...

JS学习(1)(基本概念与作用、与HTML、CSS区别)

目录 一、JavaScript是什么&#xff1f; &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;简称&#xff1a;JS&#xff1f; 二、JavaScript的作用。 三、HTML、CSS、JS之间的关系。 &#xff08;1&#xff09;html、css。 &#xff08;2&#xff09;JavaScript。 …...

代码随想录算法训练营day50|动态规划12

不同的子序列 给定一个字符串 s 和一个字符串 t &#xff0c;计算在 s 的子序列中 t 出现的个数。、 编辑距离中的删除元素&#xff0c;其实就是直接变数字&#xff0c;其只删除原来的较长的数组里的元素 递推模拟&#xff0c;使用s的最后一个元素匹配&#xff0c;或者删除…...

JavaWeb学习(2)(Cookie原理(超详细)、HTTP无状态)

目录 一、HTTP无状态。 &#xff08;1&#xff09;"记住我"&#xff1f; &#xff08;2&#xff09;HTTP无状态。 &#xff08;3&#xff09;信息存储客户端中。如何处理&#xff1f; 1、loaclStorage与sessionStorage。 2、Cookie。 二、Cookie。 &#xff08;1&…...

java抽象类

目录 一.抽象类 1.什么是抽象类 2.抽象类特点 (1)抽象类不能直接实例化对象 (2)可以包含抽象方法和具体方法 (3)可以有构造方法 (4)抽象类必须被继承&#xff0c;并且继承后子类要重写父类中的抽象方法&#xff0c;否则子类也是抽象类&#xff0c;必须要使用 abstract 修…...

minio集群部署–linux环境

原文地址&#xff1a;minio集群部署–linux环境 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 第一步&#xff1a;安装 有rpm、deb、和二进制文件安装方式。参考文档在&#xff1a;MinIO Object Storage for Linux — MinIO Object Storage …...

在vue3里使用scss实现简单的换肤功能

实现的换肤功能&#xff1a;主题色切换、亮色模式和暗黑模式切换、背景图切换 主题色就是网站主色&#xff0c;可以配置到组件库上面&#xff1b;亮色模式又分为两种风格&#xff1a;纯白风格和背景图风格&#xff0c;不需要背景图的话可以删掉这部分逻辑和相关定义&#xff1b…...

JavaScript编写css自定义属性

一、自定义属性 是在 CSS 中定义的变量&#xff0c;以 --开头。它们可以存储颜色、尺寸、字体等任何 CSS 值&#xff0c;并且可以在整个文档中重复使用。 :root {--primary-color: #3498db;--font-size: 16px; }body {color: var(--primary-color);font-size: var(--font-siz…...

我们来学webservie - WSDL

WSDL 题记WSDL系列文章 题记 举个例子 酒桌上大领导们谈笑风生&#xff0c;把酒临风,其喜洋洋者矣老张说能签下xx项目&#xff0c;一来证明了集团在行业中的翘楚地位&#xff0c;二来感谢各位领导给予的大力支持接下来的一周&#xff0c;项目经理、业务顾问相继入场&#xff0…...

【Agent】构建智能诗歌创作系统:基于多 Agent 的协同创作实现

在探索大语言模型的创意应用过程中&#xff0c;我们开发了一个基于多 Agent 的智能诗歌创作系统。本文将介绍如何通过多个专业化的 Agent 协同工作&#xff0c;实现根据地点和天气信息自动创作诗歌的功能。 GitHub Code 项目地址 核心架构设计 1. Agent 基类设计 from pydan…...

001 LVGL PC端模拟搭建

01 LVGL模拟器介绍 使用PC端软件模拟LVGL运行&#xff0c;而不需要任何嵌入式硬件 环境搭建&#xff1a;codeblocks-20.03mingw-setup 正常安装流程即可 工程获取&#xff1a;LVGL官网-> github仓库 本地安装包下载资源包 工程模版和软件安装包 补充&#xff1a;…...

AJAX三、XHR,基本使用,查询参数,数据提交,promise的三种状态,封装-简易axios-获取省份列表 / 获取地区列表 / 注册用户,天气预报

一、XMLHttpRequest基本使用 XMLHttpRequest&#xff08;XHR&#xff09;对象用于与服务器交互。 二、XMLHttpRequest-查询参数 语法: 用 & 符号分隔的键/值对列表 三、XMLHttpRequest-数据提交 核心步骤 : 1. 请求头 设置 Content-Type 2. 请求体 携带 符合要求 的数…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...