SpringBoot統(tǒng)一返回格式的方法詳解
前言
目前很多項目都是前后端分離,前后端會事先約定好返回格式。那么后端如何做,才能優(yōu)雅的返回統(tǒng)一格式呢,接下來,請大家跟著我,一步步來實現(xiàn)。
1. 直接返回結(jié)果
先看一下最基本的例子,直接將結(jié)果原封不動返回:
@Data @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown?=?true) public?class?TestVo?{ ????private?static?final?long?serialVersionUID?=?1L; ????@Schema(name?=?"姓名") ????private?String?name; ????@Schema(name?=?"年齡") ????private?Integer?age; }
@RestController @RequestMapping(value?=?"/test") public?class?TestApi?{ ????@GetMapping("/simple") ????public?TestVo?simple()?{ ????????TestVo?testVo?=?new?TestVo("張三",?30); ????????return?testVo; ????} }
返回結(jié)果:
{
"name": "張三",
"age": 30
}
2. 約定返回格式
假如已經(jīng)與前端開發(fā)妹子約定好了格式,比如:
{ ????"code":?0, ????"msg":?"錯誤信息", ????"data":?實際返回結(jié)果 }
那么我們首先需要編寫一個封裝結(jié)果類Result。為了方便封裝,在這個類中增加一個success方法:
@Data @JsonInclude(JsonInclude.Include.NON_NULL) public?class?Result<T>?implements?Serializable?{ ????private?static?final?long?serialVersionUID?=?1L; ????/** ?????*?返回編碼 ?????*/ ????private?Integer?code; ????/** ?????*?編碼描述 ?????*/ ????private?String?msg; ????/** ?????*?業(yè)務(wù)數(shù)據(jù) ?????*/ ????private?T?data; ????/** ?????*?返回成功結(jié)果對象 ?????* ?????*?@param?data ?????*?@param?<T> ?????*?@return ?????*/ ????public?static?<T>?Result<T>?success(T?data)?{ ????????Result?result?=?new?Result(); ????????result.setCode(0); ????????result.setMsg("success"); ????????result.setData(data); ????????return?result; ????} }
3. 返回統(tǒng)一格式結(jié)果
后臺接口代碼微調(diào)一下,返回值改為Result,泛型為原返回值的類型:
@RestController @RequestMapping(value?=?"/test") public?class?TestApi?{ ????@GetMapping("/withResult") ????public?Result<TestVo>?withResult()?{ ????????TestVo?testVo?=?new?TestVo("張三",?30); ????????return?Result.success(testVo); ????} }
返回結(jié)果:
{
"code": 0,
"msg": "success",
"data": {
"name": "張三",
"age": 30
}
}
至此,返回結(jié)果完美符合格式。
但是這樣的代碼并不算簡潔:每個接口的返回值都必須是Result<>,并且return的時候都要用Result.success()方法封裝一下。
那么,有沒有更優(yōu)雅的方法?我們繼續(xù)往下看:
4. 切片封裝統(tǒng)一格式
編寫注解
實際使用場景中,并不是所有接口都需要統(tǒng)一格式。我們這里使用一個注解作為開關(guān),按需控制接口返回格式。
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public?@interface?ApiResult?{ ????String?value()?default?""; ????int?successCode()?default?0; ????String?successMsg()?default?"success"; ????Class<??extends?IResult>?resultClass()?default?Result.class; }
編寫ControllerAdvice
@ControllerAdvice public?class?MyResponseBodyAdvice?implements?ResponseBodyAdvice?{ ????protected?boolean?isStringConverter(Class?converterType)?{ ????????return?converterType.equals(StringHttpMessageConverter.class); ????} ????protected?boolean?isApiResult(MethodParameter?returnType)?{ ????????return?returnType.hasMethodAnnotation(ApiResult.class); ????} ????@Override ????public?boolean?supports(MethodParameter?returnType,?Class?converterType)?{ ????????return?!isStringConverter(converterType)?&&?isApiResult(returnType); ????} ????@Override ????public?Object?beforeBodyWrite(Object?body,?MethodParameter?returnType,?MediaType?selectedContentType, ????????????????????????????????Class?selectedConverterType,?ServerHttpRequest?request,?ServerHttpResponse?response)?{ ????????//關(guān)鍵????????????????????????? ????????return?Result.success(body); ????} }
這里有一點要注意,這個advice中supports方法中判斷返回結(jié)果類型必須為非String類型。如果返回結(jié)果為String類型,那么result要轉(zhuǎn)為json字符串后再返回,需要再寫一個advice。
見證奇跡的時刻到了
@ApiResult @GetMapping("/withResultHide") public?TestVo?withResultHide()?{ ????TestVo?testVo?=?new?TestVo("張三",?30); ????return?testVo; }
這段代碼與最開始一樣,并沒有返回Result,僅僅加上了@ApiResult注解,我們看返回結(jié)果:
{
"code": 0,
"msg": "success",
"data": {
"name": "張三",
"age": 30
}
}
大功告成!
以上只是最精簡的例子,實際使用中還結(jié)合了 統(tǒng)一異常封裝、自定義返回格式 等功能。我們注意到@ApiResult注解中,有三個參數(shù):successCode、successMsg、resultClass,就是為了自定義返回格式預(yù)留的,下面再看兩個場景:
5. 自定義返回格式
場景1:返回成功時code為200
如果個別接口的返回格式與默認格式相同,但是要求code等于200時才代表成功,那么修改下successCode參數(shù)即可:
@ApiResult(successCode?=?200,?successMsg?=?"ok") @GetMapping("/withResultHide") public?TestVo?withResultHide()?{ ????TestVo?testVo?=?new?TestVo("張三",?30); ????return?testVo; }
返回成功時,結(jié)果中的code和msg都變?yōu)樵O(shè)置的值:
{
"code": 200,
"msg": "ok",
"data": {
"name": "張三",
"age": 30
}
}
場景2:自定義返回格式
如果某個接口的返回格式不是默認的返回格式,比如約定返回returnCode、returnDesc、data(對應(yīng)默認的code、msg、data)。那么則需要新增一個返回結(jié)果類,比如ReturnResult:
@Data @JsonInclude(JsonInclude.Include.NON_NULL) public?class?ReturnResult<T>?implements?Serializable?{ ????private?static?final?long?serialVersionUID?=?1L; ????/** ?????*?返回編碼 ?????*/ ????private?String?returnCode; ????/** ?????*?編碼描述 ?????*/ ????private?String?returnDesc; ????/** ?????*?業(yè)務(wù)數(shù)據(jù) ?????*/ ????private?T?data; ????/** ?????*?返回成功結(jié)果對象 ?????* ?????*?@param?data ?????*?@param?<T> ?????*?@return ?????*/ ????public?static?<T>?ReturnResult<T>?success(T?data)?{ ????????ReturnResult?result?=?new?ReturnResult(); ????????result.setReturnCode(0); ????????result.setReturnDesc("success"); ????????result.setData(data); ????????return?result; ????} }
然后修改接口上的@ApiResult注解中的resultClass屬性
@ApiResult(resultClass?=?ReturnResult.class) @GetMapping("/withResultHide") public?TestVo?withResultHide()?{ ????TestVo?testVo?=?new?TestVo("張三",?30); ????return?testVo; }
這時,返回結(jié)果就變?yōu)橄胍母袷搅耍?/p>
{
"returnCode": "0",
"returnDesc": "success",
"data": {
"name": "張三",
"age": 30
}
}
到此這篇關(guān)于SpringBoot統(tǒng)一返回格式的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot統(tǒng)一返回格式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實現(xiàn)本地上傳文件到resources目錄
Java后端項目上傳文件是一個很常見的需求,這篇文章主要為大家介紹了SpringBoot如何實現(xiàn)本地上傳文件到resources目錄永久保存下載,需要的可以參考一下2023-07-07SpringBoot如何對LocalDateTime進行格式化并解析
這篇文章主要介紹了SpringBoot如何對LocalDateTime進行格式化方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07利用SpringMVC接收復(fù)雜對象和多個文件(前端使用JQuery)
這篇文章主要介紹了利用SpringMVC接收復(fù)雜對象和多個文件(前端使用JQuery),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10SpringMVC請求、響應(yīng)和攔截器的使用實例詳解
攔截器(Interceptor) 它是一個Spring組件,并由Spring容器管理,并不依賴Tomcat等容器,是可以單獨使用的,這篇文章給大家介紹SpringMVC請求、響應(yīng)和攔截器的使用,感興趣的朋友一起看看吧2024-03-03Spring?Data?JPA?在?@Query?中使用投影的方法示例詳解
這篇文章主要介紹了Spring?Data?JPA?在?@Query?中使用投影的方法,大家需要注意如果要在 @Query 中使用投影,必須要主動聲明要查詢的字段,并且主動寫明字段的別名才行,本文通過sql代碼給大家介紹的非常詳細,需要的朋友參考下吧2022-07-07