关于@ResponseBody 默认输出的误区的解答
背景
@ResponseBody 默认情况返回的数据格式是什么?所谓默认情况 后台接口不指定 produces MediaType
@Controller
public class DemoController {
@ResponseBody
@GetMapping(value = "/demo")
public DemoVO demo() {
return new DemoVO("lengleng", "123456");
}
}
使用百度搜索 @ResponseBody 排名第一的答案, @ResponseBody 的作用其实是将 java 对象转为 json 格式的数据。

正确答案
我们先来公布正确的答案。
@ResponseBody 的输出格式,默认情况取决于客户端的 Accept 请求头。


源码剖析
RequestResponseBodyMethodProcessor
public class RequestResponseBodyMethodProcessor {
// 处理 ResponseBody 标注的方法
@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();
// 获取请求头中的目标资源类型
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;
}
}
}
为什么我要去研究这个问题
当升级至 spring cloud alibaba 2.2.1 时, sentinel 模块 引入以下依赖

当依赖中出现 dataformat jar 时候, RestTemplate ,会在默认 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");
}
当我们使用 RestTemplate 调用接口时候,若不指定 Accept 会返回 XML ,导致不能平滑升级
到此这篇关于关于@ResponseBody 默认输出的误区的解答的文章就介绍到这了,更多相关@ResponseBody 默认输出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
- 详解SpringBoot中添加@ResponseBody注解会发生什么
- 详解SpringBoot定制@ResponseBody注解返回的Json格式
- SpringBoot使用@ResponseBody返回图片的实现
- 解决使用@ResponseBody后返回500错误的问题
- spring boot @ResponseBody转换JSON 时 Date 类型处理方法【两种方法】
- Springmvc 4.x利用@ResponseBody返回Json数据的方法
- spring+mybatis 通过@ResponseBody返回结果中文乱码的解决方法
- springMvc注解之@ResponseBody和@RequestBody详解
- SpringMVC中解决@ResponseBody注解返回中文乱码问题
- @ResponseBody 和 @RequestBody 注解的区别
- SpringMVC注解之@ResponseBody注解原理
相关文章
elasticsearch索引index之engine读写控制结构实现
这篇文章主要为大家介绍了elasticsearch索引index之engine读写控制结构实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-04-04
使用@Order控制配置类/AOP/方法/字段的加载顺序详解
这篇文章主要介绍了使用@Order控制配置类/AOP/方法/字段的加载顺序详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-02-02
IntelliJ IDEA安装scala插件并创建scala工程的步骤详细教程
这篇文章主要介绍了IntelliJ IDEA安装scala插件并创建scala工程的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2020-07-07


最新评论