關(guān)于@ResponseBody 默認(rèn)輸出的誤區(qū)的解答
背景
@ResponseBody 默認(rèn)情況返回的數(shù)據(jù)格式是什么?所謂默認(rèn)情況 后臺接口不指定 produces MediaType
@Controller
public class DemoController {
@ResponseBody
@GetMapping(value = "/demo")
public DemoVO demo() {
return new DemoVO("lengleng", "123456");
}
}
使用百度搜索 @ResponseBody 排名第一的答案, @ResponseBody 的作用其實是將 java 對象轉(zhuǎn)為 json 格式的數(shù)據(jù)。

正確答案
我們先來公布正確的答案。
@ResponseBody 的輸出格式,默認(rèn)情況取決于客戶端的 Accept 請求頭。


源碼剖析
RequestResponseBodyMethodProcessor
public class RequestResponseBodyMethodProcessor {
// 處理 ResponseBody 標(biāo)注的方法
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
// 處理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 處理返回值
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
writeWithMessageConverters
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
HttpServletRequest request = inputMessage.getServletRequest();
// 獲取請求頭中的目標(biāo)資源類型
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
// 獲取接口指定支持的資源類型
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
// 獲取能夠輸出資源類型
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
/// 排序
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
for (MediaType mediaType : mediaTypesToUse) {
// 判斷資源類型是否是具體的類型,而不是帶通配符 * 這種
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
selectedMediaType = selectedMediaType.removeQualityValue();
// 查找支持選中資源類型的 HttpMessageConverter,輸出body
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
return;
}
}
}
為什么我要去研究這個問題
當(dāng)升級至 spring cloud alibaba 2.2.1 時, sentinel 模塊 引入以下依賴

當(dāng)依賴中出現(xiàn) dataformat jar 時候, RestTemplate ,會在默認(rèn) Accept 請求頭增加
application/xml | text/xml | application/*+xml

public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, new MediaType("application", "xml", StandardCharsets.UTF_8),
new MediaType("text", "xml", StandardCharsets.UTF_8),
new MediaType("application", "*+xml", StandardCharsets.UTF_8));
Assert.isInstanceOf(XmlMapper.class, objectMapper, "XmlMapper required");
}
當(dāng)我們使用 RestTemplate 調(diào)用接口時候,若不指定 Accept 會返回 XML ,導(dǎo)致不能平滑升級
到此這篇關(guān)于關(guān)于@ResponseBody 默認(rèn)輸出的誤區(qū)的解答的文章就介紹到這了,更多相關(guān)@ResponseBody 默認(rèn)輸出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解SpringBoot中添加@ResponseBody注解會發(fā)生什么
- 詳解SpringBoot定制@ResponseBody注解返回的Json格式
- SpringBoot使用@ResponseBody返回圖片的實現(xiàn)
- 解決使用@ResponseBody后返回500錯誤的問題
- spring boot @ResponseBody轉(zhuǎn)換JSON 時 Date 類型處理方法【兩種方法】
- Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法
- spring+mybatis 通過@ResponseBody返回結(jié)果中文亂碼的解決方法
- springMvc注解之@ResponseBody和@RequestBody詳解
- SpringMVC中解決@ResponseBody注解返回中文亂碼問題
- @ResponseBody 和 @RequestBody 注解的區(qū)別
- SpringMVC注解之@ResponseBody注解原理
相關(guān)文章
elasticsearch索引index之engine讀寫控制結(jié)構(gòu)實現(xiàn)
這篇文章主要為大家介紹了elasticsearch索引index之engine讀寫控制結(jié)構(gòu)實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04
使用@Order控制配置類/AOP/方法/字段的加載順序詳解
這篇文章主要介紹了使用@Order控制配置類/AOP/方法/字段的加載順序詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
詳解SpringBoot啟動項目后執(zhí)行方法的幾種方式
在項目開發(fā)中某些場景必須要用到啟動項目后立即執(zhí)行方式的功能,本文主要聊聊實現(xiàn)立即執(zhí)行的幾種方法,具有一定的參考價值,感興趣的可以了解一下2023-09-09
Java多線程并發(fā)synchronized?關(guān)鍵字
這篇文章主要介紹了Java多線程并發(fā)synchronized?關(guān)鍵字,Java?在虛擬機層面提供了?synchronized?關(guān)鍵字供開發(fā)者快速實現(xiàn)互斥同步的重量級鎖來保障線程安全。2022-06-06
Java實現(xiàn)文件復(fù)制及文件夾復(fù)制幾種常用的方式
這篇文章主要給大家介紹了關(guān)于Java實現(xiàn)文件復(fù)制及文件夾復(fù)制幾種常用的方式,java復(fù)制文件的方式其實有不少種,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Java實現(xiàn)基于token認(rèn)證的方法示例
這篇文章主要介紹了Java實現(xiàn)基于token認(rèn)證的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
IntelliJ IDEA安裝scala插件并創(chuàng)建scala工程的步驟詳細(xì)教程
這篇文章主要介紹了IntelliJ IDEA安裝scala插件并創(chuàng)建scala工程的步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07

