欢迎来到代码驿站!

JAVA代码

当前位置:首页 > 软件编程 > JAVA代码

关于@ResponseBody 默认输出的误区的解答

时间:2022-11-23 09:42:49|栏目:JAVA代码|点击:

背景

@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 ,导致不能平滑升级

上一篇:Spring中事务传播行为的介绍

栏    目:JAVA代码

下一篇:Java并发编程之原子操作类详情

本文标题:关于@ResponseBody 默认输出的误区的解答

本文地址:http://www.codeinn.net/misctech/219652.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有