源码解析-为什么引入了jackson-dataformat-xml 包我的接口全变成了xml格式?
本文从引入jackson-dataformat-xml 之后接口全变成xml 现象开始,一步步排查代码原因,并提出解决方案。希望能对遇到相关问题的人有所帮助
新调用上游一个接口,增加了对方的一个api包,没修改任何逻辑,接口却从json返回全变成了xml格式?
原接口:
现在:
排查之后定位到是因为对方的api包里增加了一个依赖包
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.7</version>
</dependency>
那这个包是怎么生效的呢?
需要从spring-mvc 说起
当我们的代码里这么写的时候
spring-mvc 的执行流程:
SpringMVC执行流程:
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)。
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
11.DispatcherServlet响应用户。
其中第9步骤里,ViewReslover解析后返回具体View 。
这里在找对应的解析器的时候有这样一步 第381行:
我们看到在getDefaultMediaTypes() 这里
就恍然大悟了。spring-webmvc里 已经有写好的判断是否有当前类 如果有作为一个可处理的类型放在map里,而恰好xml 在json之前
那么有什么办法 避免引入这个包之后就变成了xml么?如果能排除当然可以排除这个包,但是仍然无法避免下次其他依赖包里是否有对应的依赖,并且也无法排除你的项目里真的不会遇到这个包。那么怎么样可以避免呢?
其实答案就在上边的这个图里,看下方法 writeWithMessageConvert 的逻辑
protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException { Class<?> returnValueClass = returnValue.getClass(); HttpServletRequest servletRequest = inputMessage.getServletRequest();
//获取客户端Accept字段接收的content-type List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
//获取服务器端指定的content-type,如果@RequestMapping中的produces配置了content-type,则返回此content-type,若果没有,
则获取所有HttpMessageConverter所支持的content-type,然后通过requestedMediaTypes和producibleMediaTypes 对比,选定一个最合适的content-type作为
//selectedMediaType List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass); Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { if (requestedType.isCompatibleWith(producibleType)) { compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (compatibleMediaTypes.isEmpty()) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes); MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null; for (MediaType mediaType : mediaTypes) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> messageConverter :
//遍历所有已注册的HttpMessageConverter,选出一个支持返回值类型returnValueClass和
//selectedMediaType的HttpMessageConverter来进行写入数据到response的body中。
this.messageConverters) { if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } return; } } } throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); }
所以 比较安全的解决办法是:
1) 提供方法时,我们可以指定方法的返回类型
例如: @RequestMapping(value ="/test",produces=“application/json”) 中 produces 可以指定方法对应的类型等
2) 请求方法时,我们可以指定想要的返回类型
例如:
源码解析-为什么引入了jackson-dataformat-xml 包我的接口全变成了xml格式?相关推荐
- SpringSession的源码解析(从Cookie中读取Sessionid,根据sessionid查询信息全流程分析)
前言 上一篇我们介绍了SpringSession中Session的保存过程,今天我们接着来看看Session的读取过程.相对保存过程,读取过程相对比较简单. 本文想从源码的角度,详细介绍一下Sessi ...
- SpringBoot入门-源码解析(雷神)
一.Spring Boot入门 视频学习资料(雷神): https://www.bilibili.com/video/BV19K4y1L7MT?p=1 github: https://github.c ...
- Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(三)-Controller 解析
在之前的博客中Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(一),己经对 Spring MVC 的框架做了详细的分析,但是有一个问题,发现举的例子不常用,因为我们在实际开发项 ...
- python flask源码解析_用尽洪荒之力学习Flask源码
[TOC] 一直想做源码阅读这件事,总感觉难度太高时间太少,可望不可见.最近正好时间充裕,决定试试做一下,并记录一下学习心得. 首先说明一下,本文研究的Flask版本是0.12. 首先做个小示例,在p ...
- Android源码解析(一)动画篇-- Animator属性动画系统
Android源码解析-动画篇 Android源码解析(一)动画篇-- Animator属性动画系统 Android源码解析(二)动画篇-- ObjectAnimator Android在3.0版本中 ...
- [Android] Handler源码解析 (Java层)
之前写过一篇文章,概述了Android应用程序消息处理机制.本文在此文基础上,在源码级别上展开进行概述 简单用例 Handler的使用方法如下所示: Handler myHandler = new H ...
- Redux 源码解析系列(一) -- Redux的实现思想
文章来源: IMweb前端社区 黄qiong(imweb.io) IMweb团队正在招聘啦,简历发至jayccchen@tencent.com Redux 其实是用来帮我们管理状态的一个框架,它暴露给 ...
- clickhouse原理解析与开发实战 pdf_重识SSM,“超高频面试点+源码解析+实战PDF”,一次性干掉全拿走...
重识SSM,"超高频面试点"+"源码解析"+"实战PDF",一次性干掉全拿走!! 01 超高频面试点知识篇 1.1 Spring超高频面试点 ...
- Java HashSet源码解析
本解析源码来自JDK1.7,HashSet是基于HashMap实现的,方法实现大都直接调用HashMap的方法 另一篇HashMap的源码解析文章 概要 实现了Set接口,实际是靠HashMap实现的 ...
- usestate中的回调函数_React Hooks 源码解析(3):useState
React 源码版本: v16.11.0 源码注释笔记: airingursb/reactgithub.com 在写本文之前,事先阅读了网上了一些文章,关于 Hooks 的源码解析要么过于浅显.要么 ...
最新文章
- 服务端关闭session的重要性
- LintCode 1.A+B的问题
- 层次聚类多维度matlab实现_第34集 python机器学习:凝聚聚类
- 2021全州高中高考成绩查询,最新!最全!桂林各中学高考成绩汇总!为桂林考生骄傲!...
- java的autotype,关于 fastjson 异常 autoType is not support 问题分析解决
- 这些大佬,真的牛逼了!
- iOS开发 - 动画实践系列
- 操作系统—死锁的检测和解除
- Klevgrand Tines for Mac(电钢琴模拟插件)
- Linux系统下架设PPTP ×××服务器
- Excel自定义格式详解
- USB Mass Storage大容量存储的基本知识
- 看懂英文数据手册、搭建电路
- 计算机专业需要盲打,计算机盲打的技巧与方法【听看打练习】
- 六、品达通用权限系统__pd-tools-log
- Cookie加密10
- 地壳中元素含量排名记忆口诀_地壳中元素含量_地壳中元素含量口诀
- 几何画板与运筹学作图注记
- 关于css的display:flex inline block inline-block和float
- mysql备份表语句