SpringBoot之統(tǒng)一數(shù)據(jù)返回格式的實現(xiàn)示例
之前我們實現(xiàn)的圖書管理系統(tǒng),函數(shù)的返回值格式都不統(tǒng)一,如果將這些函數(shù)的返回值格式都進行統(tǒng)一,將方便后續(xù)的返回和接收,但是如果我們挨個修改這些函數(shù)的返回值格式,有些麻煩,那么有沒有別的好的辦法呢?----有,就是下面我們要講解的"SpringBoot之統(tǒng)一數(shù)據(jù)返回格式"。
統(tǒng)一數(shù)據(jù)返回格式
使用
統(tǒng)?的數(shù)據(jù)返回格式使? @ControllerAdvice 和 ResponseBodyAdvice 的?式實現(xiàn)
@ControllerAdvice 表?控制器通知類。
定義類 ResponseAdvice , 實現(xiàn) ResponseBodyAdvice 接?, 并在類上添加
@ControllerAdvice 注解。
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result){
return body;
}
return Result.success(body);
}
}運行結(jié)果:

定義測試接口
@RequestMapping("/test")
@RestController
public class TestController {
@RequestMapping("/t1")
public String t1(){
return "string";
}
@RequestMapping("/t2")
public Integer t2(){
return 1;
}
@RequestMapping("/t3")
public Boolean t3(){
return true;
}
}運行結(jié)果
t2返回結(jié)果:

t3返回結(jié)果:

t1返回結(jié)果:


為什么其他方法都能夠正常返回,而返回類型為String時卻不能正常返回,而且還拋出了ClassCastException異常,這是為什么呢?
問題解答(結(jié)合源碼)
根據(jù)IDEA控制臺打印的堆棧信息,我們首先看看StringHttpMessageConverter和AbstractHttpMessageConverter這兩個類,特別是StringHttpMessageConverter的addDefaultHeaders方法和AbstractHttpMessageConverter的write方法,其中StringHttpMessageConverter是繼承了AbstractHttpMessageConverter并重寫了幾個方法,特別是addDefaultHeaders方法,下面通過Debug方式運行:


再繼續(xù)運行,會捕獲到異常

由此我們知道,是因為返回結(jié)果為String類型的"string"被轉(zhuǎn)換成了Result類型,但是在執(zhí)行AbstractHttpMessageConverter的write方法時,因為AbstractHttpMessageConverter的派生類StringHttpMessageConverter重寫了addDefaultHeaders方法,此時會調(diào)用StringHttpMessageConverter的addDefaultHeaders方法,但是StringHttpMessageConverter的addDefaultHeaders方法要求 t 的類型是String類型,但是無法從自定義的Result類型轉(zhuǎn)換成String類型,因此拋出了ClassCastException異常。

那么問題來了,上面的三個測試接口,走的都是Result.success()方法,為什么卻有不一樣的結(jié)果,通過調(diào)試:
對于返回類型為String類型,在AbstractMessageConverterMethodProcessor里面的writeWithMessageConverters()方法時,在經(jīng)過下圖所示過程中,String類型會被轉(zhuǎn)換成Result類型的結(jié)果,而且后面走的是StringHttpMessageConverter的addDefaultHeaders方法,其中StringHttpMessageConverter重寫了AbstractHttpMessageConverter的addDefaultHeaders方法;


而返回值類型不是String類型時,經(jīng)過和剛剛同樣的步驟時,直接走的是AbstractHttpMessageConverter的addDefaultHeaders方法,而沒有走StringHttpMessageConverter的addDefaultHeaders方法。

解決方法:對返回類型為String類型的字符串進行序列化
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import springbook.model.Result;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result){
return body;
}
if (body instanceof String){
return objectMapper.writeValueAsString(Result.success(body));
}
return Result.success(body);
}
}運行結(jié)果:

優(yōu)點
1. ?便前端程序員更好的接收和解析后端數(shù)據(jù)接?返回的數(shù)據(jù)
2. 降低前端程序員和后端程序員的溝通成本, 按照某個格式實現(xiàn)就可以了, 因為所有接?都是這樣返回的.
3. 有利于項?統(tǒng)?數(shù)據(jù)的維護和修改.
4. 有利于后端技術(shù)部?的統(tǒng)?規(guī)范的標(biāo)準(zhǔn)制定, 不會出現(xiàn)稀奇古怪的返回內(nèi)容.
到此這篇關(guān)于SpringBoot之統(tǒng)一數(shù)據(jù)返回格式的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot 統(tǒng)一數(shù)據(jù)返回格式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
這篇文章將通過Java實現(xiàn)一個簡答的圖書管理系統(tǒng),本圖書管理系統(tǒng)用對象數(shù)組的方式來提供操作方法,比較特別,建議新手學(xué)習(xí),這對理解Java面向?qū)ο笥泻艽髱椭?/div> 2022-11-11
Java線程創(chuàng)建靜態(tài)代理模式代碼實例
這篇文章主要介紹了Java線程創(chuàng)建靜態(tài)代理模式代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11
一文詳解Spring Aop @After(后置通知)的使用場景
@After 是 Spring AOP 中的另一種通知(Advice)類型,通常被稱為“后置通知”或“最終通知”,本文將通過詳細(xì)的代碼示例給大家介紹一下Spring Aop @After(后置通知)的使用場景,需要的朋友可以參考下2025-06-06
Spring boot 使用JdbcTemplate訪問數(shù)據(jù)庫
SpringBoot 是為了簡化 Spring 應(yīng)用的創(chuàng)建、運行、調(diào)試、部署等一系列問題而誕生的產(chǎn)物。本文重點給大家介紹spring boot 使用JdbcTemplate訪問數(shù)據(jù)庫,需要的朋友可以參考下2018-05-05
四步教你完美解決IDEA運行maven項目時報錯:java:?錯誤:?不支持發(fā)行版本?5
這篇文章主要介紹了四步教你完美解決IDEA運行maven項目時報錯:java:?錯誤:?不支持發(fā)行版本?5的相關(guān)資料,文中通過圖文將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2025-09-09
Java Stream 的 forEachOrdered 與 forE
在Java Stream API中,forEach和forEachOrdered是兩個常用的終止操作,用于對流中的元素執(zhí)行迭代處理,本文將從多個維度深入分析Java Stream的forEachOrdered與forEach的區(qū)別與適用場景,感興趣的朋友一起看看吧2025-08-08最新評論

