关于@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 ,导致不能平滑升级
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
互联网寒冬、裁员,作为程序员的我们,应该如何去应对?
前言: 要说互联网“寒冬”,从各大互联网企业的纷纷裁员及一系列降低成本的举措来看,已经是不争的事实了。 具体表现如下: 1、 大形式不好,根本不只互联网有点冷,像房地产,金融证券也冷的一踏糊涂,金融行业降薪很普遍。 2、 很多小公司小企业倒闭裁员,新闻不报道,你没发现。 3、 互联网本来就是泡沫的重灾区,搞个概念就开始炒,然后融资,前面的人成功的多,后面的人只能是横尸遍野。 4、 各个行业都缺乏优质人才,据我观察各行各业的人员都存在低端者和初级者过剩的情况。低端码农的过剩,同时带来了前端、美工、产品策划、运营、客服的优质人才短缺。各大企业前几年疯狂搞什么新媒体运营,搞来搞去钱没少花,也没搞出什么结果,带来了新媒体运营、文案的过剩泡沫。 淘宝天猫店大批亏钱运营甚至倒闭,带来的是淘宝运营人员的过程。甚至现在营销号、网红、主播都是过剩的。为什么会有这个情况呢?14亿人,每年那么多毕业生,人人都要进城,可我们目前的产业还没达到能支撑这么多就业人员,前期靠烧融资烧钱挺着,无钱可烧之后,这批人还是要从哪来,回哪儿去的。 作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流...
- 下一篇
国家发改委首次明确“新基建”范围
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 国家发改委今天首次明确新型基础设施的范围,国家发改委相关负责人表示,初步研究认为,新型基础设施是以新发展理念为引领,以技术创新为驱动,以信息网络为基础,面向高质量发展需要,提供数字转型、智能升级、融合创新等服务的基础设施体系。 目前来看,新型基础设施主要包括3个方面内容:一是信息基础设施。主要是指基于新一代信息技术演化生成的基础设施,比如,以5G、物联网、工业互联网、卫星互联网为代表的通信网络基础设施,以人工智能、云计算、区块链等为代表的新技术基础设施,以数据中心、智能计算中心为代表的算力基础设施等。 二是融合基础设施。主要是指深度应用互联网、大数据、人工智能等技术,支撑传统基础设施转型升级,进而形成的融合基础设施,比如,智能交通基础设施、智慧能源基础设施等。 三是创新基础设施。主要是指支撑科学研究、技术开发、产品研制的具有公益属性的基础设施,比如,重大科技基础设施、科教基础设施、产业技术创新基础设施等。 当然,伴随着技术革命和产业变革,新型基础设施的内涵、外延也不是一成不变的,将持续跟...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS8安装Docker,最新的服务器搭配容器使用