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

Spring统一格式返回

目录

一:统一结果返回

1:统一结果返回写法

2:String类型报错问题

解决方法

二:统一异常返回

统一异常返回写法

三:总结


同志们,今天咱来讲一讲统一格式返回啊,也是好久没有讲过统一格式返回了,说实话这个统一格式返回就是一个让咱返回的数据能有一个统一的格式嘛,不为别的就为了和你一块共事的同事不会提着刀追着你满大街跑,要跟你交流交流工作经验。

前端:我这数据咋老是对不上啊?

后端:奥兄弟,这个接口我返回的是Boolean类型

前端:我这数据怎么又对不上了啊?

后端:奥好兄弟,我觉得Boolean类型太丑了我就换成String类型了,我觉得它顺眼点。

前端:

那咱肯定不能让同事追着我们交流经验啊,所以我们一定要让咱返回的数据能有一个统一的格式

一:统一结果返回

1:统一结果返回写法

定义返回模板

想要统一返回一个结果,就肯定要有一个返回结果的模板这里我们用Result类来定义

下面代码中有Result有三个属性,状态码,错误信息,返回的数据,三个方法分别是成功时返回,和失败时返回。

@Data
public class Result<T> {private Integer code;//后端响应状态码,成功200,失败-1,-2表示未登录private String errmsg;//后端发生错误的原因private T data;//每个接口返回的类型(BookInfo,boolean之类的,类型不固定所以要用泛型)/** 成功时设置* */public  static<T> Result<T> success(T data){//泛型方法加static需要加上<T>Result result = new Result<>();result.setData(data);result.setCode(200);return result;}/*失败时设置* */public  static<T> Result<T> fail(String errMsg){Result result = new Result<>();result.setCode(-1);result.setErrmsg(errMsg);return result;}public  static<T> Result<T> fail(T data,String errMsg){Result result = new Result<>();result.setData(data);result.setCode(-1);result.setErrmsg(errMsg);return result;}
}

实现ResponseBodyAdvice接口并重写方法,再加上@ControllerAdvice注解

@ControllerAdvice:这个注解的作用就是标记这个类为全局控制器增强类

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {return Result.success(body);//返回封装后结果结果}
}

support()方法:

作用:

supports 方法用于判断是否需要对某个返回值进行处理,返回true就是处理,返回false就是不处理

参数解析:

returnType:这个参数就是表示控制器方法(Controller类)的返回类型信息,它封装的有方法的返回参数的详细信息,比如方法本身,方法所属的类,返回的类型等等...可以根据这些信息来决定是否要对返回值进行处理,返回对应的true或false

Class converterType:这个参数的意思就是用于将响应体对象,转换为,HTTP响应消息的那个消息转换器的类型,后面我们会说到,先按下不表

beforeBodyWrite()方法:

作用:

我们直译一下这个方法的名字是:写 body 之前 ,意思就是在控制器方法返回之前进行的处理

当support方法返回true之后,beforeBodyWrite()方法就需要对返回值进行一些处理

参数解析:

Object body:该参数表示控制器方法实际返回的响应体对象

MethodParameter returnType:同supports方法中的returnType

 MediaType selectedContentType:表示响应的类型,如application/json

 Class selectedConverterType:表示用于将响应体对象转换为 HTTP 响应的消息转换器的类型

 request和response:这个我们很熟悉,就是代表Http的请求和响应

我们定义几个简单的控制器类

@RestController
public class Controller {@RequestMapping("/t1")public int t1(){return 1;}@RequestMapping("/t2")public Boolean t2(){return true;}@RequestMapping("/t2")public String t3(){return "老皇甫";}
}

然后启动项目测试发现

t1和t2方法没问题,都对控制器的返回结果进行了封装,但是返回String类型的t3却报错了,这是为什么呢?

 

2:String类型报错问题

首先明确一点,这个报错的原因是类型不匹配问题,报的是ClassCastException

我黄色框框里面框的翻译一下就是Result类型和String类型不匹配,那么为什么呢?

还记得我在解释方法的参数的时候那个先按下不表的Class converterType 参数吗?converterType的意思是转换器类型,SpringMVC默认会注册⼀些⾃带的 HttpMessageConverter(Http消息转换器),它是以链表的形式组织的,它们的顺序是

 ByteArrayHttpMessageConverter()->StringHttpMessageConverter()
->SourceHttpMessageConverter<>()->AllEncompassingFormHttpMessageConverter()

 其中这个AllEncompassingFormHttpMessageConverter()是根据项目的依赖情况来添加对应的转换器的,如果我们添加了Jackson依赖一般会添加MappingJackson2HttpMessageConverter()转换器到消息转换器链表的末尾

Spring会根据返回的数据类型, 从 messageConverters 链(就是那个链表)选择 合适的消息转换器 .
当返回的数据是⾮字符串时, 使⽤的 MappingJackson2HttpMessageConverter 写⼊返回对象(那个在链表末尾的消息转换器)
.
当返回的数据是字符串时 StringHttpMessageConverter 会先被遍历到,这时会认为
StringHttpMessageConverter 可以使⽤,然后就会用StringHttpMessageConverter

我们下面调用的堆栈信息中也发现,最后AbstractMessageConverterMethodProcessor调用的也是StringHttpMessageConverter

这里是AbstractMessageConverterMethodProcessor中的逻辑,body在经过beforeBody方法包装过之后,就会从String类型变为Result类型,但现在匹配到的还是StringHttpMessageConverter 消息转换器

我们点进去这个 StringHttpMessageConverter 的write方法中看一下(点击那个由AbstractHttpMessageConverter实现的

)发现里面有一个addDefaultHeader方法(由 StringHttpMessageConverter实现的),再点进去这个方法,发现这个方法接收到的是String参数,但在上面的我们在beforBodyWrite方法中已经将参数转换为了Result类型,所以才会报出类型不匹配异常

解决方法

既然是因为参数不匹配导致的错误,那就只需要将参数搞成匹配的就行了,如下图所示,如果返回的是字符串类型,那么就将返回类型序列化成字符串类型,而不是Result类型
 

我知道同志们有时候看源码很懵,不知道哪个调用哪个,这里可以说一下在控制台打印的日志中,调用的顺序一般就是下面的调用上面的,一层一层的,Spring的调用链几乎都有十几层,所以看的很懵是很正常的 

二:统一异常返回

还有一个问题,不知道同志们发现没有,就是上面我们在由于String类型不匹配报错的时候哪个返回结果状态码竟然还是200,但这个200可是成功的状态码,这都报错了,那状态码肯定能是200啊,所以这个返回结果肯定是不正确的。

统一异常返回写法

这时候我们就需要通过统一异常捕获,构造出另一种返回结果失败的格式,来返回我们可以用

@ControllerAdvice + @ExceptionHandler 两个注解来实现
写法非常简单,就是加上个@ExceptionHandler后面指定要捕获哪种类型的异常,然后进行对应的封装逻辑,Exception你也可以进行自定义异常,来满足你不同的项目需求
因为我们希望给客户端返回的是数据类型,而不是一个视图,所以要加上@ResponseBody注解
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {@ExceptionHandler(Exception.class)//捕获所有异常public Result handleException(Exception e) {return Result.fail(e.getMessage()+"异常");}@ExceptionHandler(Error.class)//捕获error类型public Result handleError(Error e) {return Result.fail(e.getMessage()+"错误");}@ExceptionHandler(RuntimeException.class)//捕获运行时异常public Result handleRuntimeException(RuntimeException e) {return Result.fail(e.getMessage()+"运行时异常");}@ExceptionHandler(NullPointerException.class)//捕获空指针异常public Result handleNullPointerException(NullPointerException e) {return Result.fail(e.getMessage()+"空指针异常");}}

我们来认为制造几个异常

查看测试结果

状态码为-1,返回结果符合预期

三:总结

这篇我们说的也不多,大概就是说了一下

为什么要进行统一的格式返回,

然后统一格式返回的写法

再是String类型会报错的问题以及源码级别的原因,

然后是统一异常返回问题

相关文章:

Spring统一格式返回

目录 一&#xff1a;统一结果返回 1&#xff1a;统一结果返回写法 2&#xff1a;String类型报错问题 解决方法 二&#xff1a;统一异常返回 统一异常返回写法 三&#xff1a;总结 同志们&#xff0c;今天咱来讲一讲统一格式返回啊&#xff0c;也是好久没有讲过统一格式返…...

Unity多Pass渲染与GPU Instancing深度优化指南

一、技术背景与挑战 1. 多Pass渲染的定位 多Pass渲染策略通过单个Shader中定义多个渲染阶段&#xff08;如阴影生成、光照计算、后处理等&#xff09;实现复杂视觉效果&#xff0c;但传统实现会显著增加DrawCall数量。例如标准渲染管线中&#xff0c;一个物体可能经历Base Pa…...

Redis高频面试题10个

1. Redis 的特点及与 Memcached 的区别 特点&#xff1a; 基于内存的键值数据库&#xff0c;支持持久化&#xff08;RDB/AOF&#xff09;。 单线程模型&#xff0c;通过 IO 多路复用实现高并发。 支持多种数据结构&#xff1a;字符串、哈希、列表、集合、有序集合等。 提供…...

【数据库】MySQL常见聚合查询详解

在数据库操作中&#xff0c;聚合查询是非常重要的一部分。通过聚合查询&#xff0c;我们可以对数据进行汇总、统计和分析。MySQL提供了丰富的聚合函数来满足不同的需求。本文将详细介绍MySQL中常见的40个聚合函数及其使用场景&#xff0c;并通过8个的案例展示它们的用法。 一、…...

蓝桥备赛(11)- 数据结构、算法与STL

一、数据结构 1.1 什么是数据结构&#xff1f; 在计算机科学中&#xff0c;数据结构是一种 数据组织、管理和存储的格式。它是相互之间存在一种 或多种特定关系的数据元素的集合。 ---> 通俗点&#xff0c;数据结构就是数据的组织形式 &#xff0c; 研究数据是用什么方…...

Linux的系统ip管理

ip地址 命令&#xff1a;ifconfig 127.0.0.1这个ip地址用于指本机。 0.0.0.0特殊ip地址用于指代本机&#xff0c;可以在端口绑定中用来确定绑定关系&#xff0c;在一些ip地址限制中&#xff0c;表示所有ip的意思。如放行规则设置为0.0.0.0&#xff0c;表示允许任意ip访问。 …...

【决策树】分类属性的选择

文章目录 1.信息增益&#xff08;ID3&#xff09;2.信息增益率&#xff08;C4.5&#xff09;3.基尼指数&#xff08;CART&#xff09;ps.三者对比 实现决策树算法最关键的一点就是如何从所有的特征属性中选择一个最优的属性对样本进行分类&#xff0c;这种最优可以理解为希望划…...

uniapp vue3 微信小程序 uni.chooseLocation使用

申请 先要去微信公众平台申请使用接口 开通成功之后就可以在项目中配置使用了 配置 配置manifest.json "mp-weixin": {/* 小程序特有相关 */"requiredPrivateInfos": ["chooseLocation"],"permission": {"scope.userLocati…...

9. Flink的性能优化

1. Flink的资源和代码优化 1.1 slot资源配置 Flink中具体跑任务的进程叫TaskManager&#xff0c;TM进程又会根据配置划分出诺干个TaskSlot&#xff0c;它是具体运行SubTask的地方。slot是Flink用来隔离各个subtask的资源集合&#xff0c;这里的资源一把指内存&#xff0c;TCP…...

十二、OSG学习笔记-Control

上一章节&#xff1a; 十一、OSG学习笔记-操作系统接口-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145891502 本章节代码&#xff1a; OsgStudy/Controls CuiQingCheng/OsgStudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/osg-study/tree/ma…...

集群、分布式与微服务架构 区别

集群、分布式与微服务架构&#xff1a;概念解析与核心差异 在构建现代软件系统时&#xff0c;集群架构、分布式系统和微服务架构是三种常见的技术方案。它们常被混淆&#xff0c;但各自解决的问题、设计理念和应用场景截然不同。本文将从基础概念出发&#xff0c;深入分析三者…...

如何使用SSH命令安全连接并转发端口到远程服务器

ssh -p 22546 rootconnect.westc.gpuhub.com d6IS/mQKq/iG ssh -CNgv -L 6006:127.0.0.1:6006 rootconnect.westc.gpuhub.com -p 22546 第一条命令&#xff1a;用于登录远程服务器&#xff0c;进行交互式操作。第二条命令&#xff1a;用于建立 SSH 隧道&#xff0c;进行端口转…...

【Java 基础】-- 设计模式

目录 Java 设计模式详解 1. 设计模式定义 2. 设计模式示例 2.1 单例模式&#xff08;Singleton Pattern&#xff09; 2.2 工厂模式&#xff08;Factory Pattern&#xff09; 2.3 观察者模式&#xff08;Observer Pattern&#xff09; 2.4 代理模式&#xff08;Proxy Pat…...

ComfyUI进阶学习全指南(2025年最新版)

ComfyUI进阶学习全指南&#xff08;2025年最新版&#xff09; 一、自定义节点与扩展管理 1.1 自定义节点安装与维护 ComfyUI的核心竞争力在于其可扩展性。通过安装第三方节点模块&#xff0c;用户可实现超分辨率修复、骨骼绑定动画生成等高级功能。安装方式主要分为三种&…...

Linux和gcc/g++常用命令总结

目录 Linux命令总结 文件操作相关命令 ls cd pwd cp mv rm cat mkdir rmdir touch 文本处理操作命令 grep awk sed 进程管理操作相关命令 ps top htop kill pkill killall chmod chown 网络操作相关命令 ping ifconfig netstat ss lsof curl …...

uniapp封装路由管理(兼容Vue2和Vue3)

1&#xff1a;uniapp已经有路由管理了为什么还要二次封装路由&#xff1f; 简化配置和调用增强灵活性和可扩展性实现统一的功能和策略提升开发效率和团队协作 2. 增强灵活性和可扩展性 灵活配置&#xff1a;二次封装允许开发者根据实际需求灵活配置路由参数&#xff0c;如跳…...

π0源码解析——一个模型控制7种机械臂:对开源VLA sota之π0源码的全面分析,含我司的部分落地实践

前言 ChatGPT出来后的两年多&#xff0c;也是我疯狂写博的两年多(年初deepseek更引爆了下)&#xff0c;比如从创业起步时的15年到后来22年之间 每年2-6篇的&#xff0c;干到了23年30篇、24年65篇、25年前两月18篇&#xff0c;成了我在大模型和具身的原始技术积累 如今一转眼…...

【C++】Class(1)

《C程序设计基础教程》——刘厚泉&#xff0c;李政伟&#xff0c;二零一三年九月版&#xff0c;学习笔记 文章目录 1、类的定义1.1、结构体和类1.2、基本概念1.3、成员函数的定义1.4、内联成员函数 2、对象2.1、对象的定义2.2、成员访问 3、构造函数3.1、构造函数的定义3.2、子…...

doris: Oracle

Apache Doris JDBC Catalog 支持通过标准 JDBC 接口连接 Oracle 数据库。本文档介绍如何配置 Oracle 数据库连接。 使用须知​ 要连接到 Oracle 数据库&#xff0c;您需要 Oracle 19c, 18c, 12c, 11g 或 10g。 Oracle 数据库的 JDBC 驱动程序&#xff0c;您可以从 Maven 仓库…...

Android14 OTA差分包升级报Package is for source build

制作好差分包&#xff0c;使用adb线刷模式验证ota升级&#xff0c;出现E:Package is for source build错误 使用adb方式验证 进入recovery模式 adb reboot recovery稍等一会界面会提示 Now send the package you want to apply to the device with "adb sidelaod <…...

双向选择排序算法

一 概述 双向选择排序(又称鸡尾酒选择排序)是选择排序的优化版本,核心改进在于每轮遍历同时确定未排序部分的最小值和最大值,分别交换到序列两端,从而减少遍历轮数。 二 时间复杂度 时间复杂度为(O(n^2)),但实际比较次数约为标准选择排序的 (1/2)。 三 C++实现代…...

Node.js setImmediate 教程

Node.js setImmediate 教程 简介 setImmediate() 是 Node.js 环境中的一个函数&#xff0c;用于安排一个回调函数在当前事件循环周期结束后立即执行。它提供了一种在当前操作完成后&#xff0c;但在任何 I/O 事件或定时器触发之前执行代码的方法。 基本用法 setImmediate((…...

MyBatis @Param 注解详解:多参数传递与正确使用方式

Param 注解主要用于 MyBatis 进行参数传递时给 SQL 语句中的参数 起别名&#xff0c;通常用于 多参数 方法&#xff0c;使参数在 XML Mapper 文件或注解 SQL 语句中更清晰易用。 1. 基本用法 在 Mapper 接口中使用 Param 来为参数命名&#xff0c;避免 MyBatis 解析时出现参数…...

Spring实战spring-ai运行

目录 1. 配置 2 .搭建项目 3. 查看对应依赖 3.1 OpenAI 依赖 3.2 配置 OpenAI API 密钥 application.properties application.yml 4. openai实战 5. 运行和测试 6. 高级配置 示例&#xff1a;配置模型和参数 解释&#xff1a; 7. 处理异常和错误 示例&#xff1a;…...

STL:C++的超级工具箱(一)

书接上回&#xff0c;内存管理和指针&#xff1a;C的双刃手术刀&#xff08;一&#xff09;-CSDN博客&#xff0c;在上篇我们聊到了什么是内存&#xff0c;堆栈&#xff0c;内存管理和智能指针相关的内容&#xff0c;接下来让我们一起去看看STL是什么吧。 第一步&#xff1a;提…...

leetcode349 两个数组的交集

求两个数组的交集&#xff0c;直白点儿就是【nums2 的元素是否在 nums1 中】。 在一堆数中查找一个数&#xff0c;当然是扔出哈希。碰到这种对目前来说是未知数值大小的情况&#xff0c;我们可以使用集合 set 来解决。 使用数组来做哈希的题目&#xff0c;是因为题目都限制了数…...

快速生成viso流程图图片形式

我们在写详细设计文档的过程中总会不可避免的涉及到时序图或者流程图的绘制&#xff0c;viso这个软件大部分技术人员都会使用&#xff0c;但是想要画的好看&#xff0c;画的科学还是比较难的&#xff0c;现在我总结一套比较好的方法可以生成好看科学的viso图(图片格式)。主要思…...

鸿蒙Android4个脚有脚线

效果 min:number122max:number150Row(){Stack(){// 底Text().border({width:2,color:$r(app.color.yellow)}).height(this.max).aspectRatio(1)// 长Text().backgroundColor($r(app.color.white)).height(this.max).width(this.min)// 宽Text().backgroundColor($r(app.color.w…...

【NetTopologySuite类库】geojson和shp互转,和自定义对象互转

geojson介绍 1. 示例 在visual studio中使用NuGet中安装了三个库&#xff08;.net4.7.2环境&#xff09;&#xff1a; NetTopologySuite 2.5NetTopologySuite.IO.Esri.Shapefile 1.2NetTopologySuite.IO.GeoJSON 4.0 1.1 shp数据转geojson 先创建一个shp文件作为例子&…...

【哇! C++】类和对象(三) - 构造函数和析构函数

目录 一、构造函数 1.1 构造函数的引入 1.2 构造函数的定义和语法 1.2.1 无参构造函数&#xff1a; 1.2.2 带参构造函数 1.3 构造函数的特性 1.4 默认构造函数 二、析构函数 2.1 析构函数的概念 2.2 特性 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中…...