目录
内容协商
1、引入xml依赖
2、postman分别测试返回json和xml
3、开启浏览器参数方式内容协商功能
4、内容协商原理
5、自定义 MessageConverter
综上
根据客户端接收能力不同,返回不同媒体类型的数据。
若客户端无法解析服务端返回的内容,即媒体类型未匹配,那么相应406。
默认没有返回xml的能力
com.fasterxml.jackson.dataformat jackson-dataformat-xml 只需要改变请求头中Accept字段。(Http协议中规定的,告诉服务器,该客户端可以接收的数据类型。)

spring: mvc: contentnegotiation: # 开启请求参数内容协商模式 favor-parameter: true # 修改parameterName,默认为format parameter-name: xx 发请求格式:
http://localhost:8080/test/person?format=json
http://localhost:8080/test/person?format=xml

注意:1.如果没有定义参数名字,默认parameterName为format。
2.引入jackson转换xml包后,则支持json、xml两种媒体类型。(如果需要其他类型数据,可自定义MessageConverter,实现多协议数据兼容)
浏览器端不传参数或者是没匹配到,就是"*/*",都能匹配,然后按权重匹配。
内容协商的内容在返回值处理器 RequestResponseBodyMethodProcessor->writeWithMessageConverters() 方法中


获取的原理:调用返回值处理器的内容协商管理器来获取到当前请求头中 Accept 字段的值,封装到 List 中,并按权重进行排序。


获取的原理:获取当前处理器中保存的所有 MessageConverter,匹配支持当前返回值类型的 MessageConverter,将这些 MessageConverter 支持的所有 MediaType 返回。


对 mediaTypesToUse 按权重进行排序,优先选中优先级较高的作为选定的 MediaType:selectedMediaType。如果匹配到不是具体的 MediaType(带通配符 *),则 selctedMediaType = application/octet-stream。



实现多协议数据兼容。json、xml、xx-media。
如何新增一个自定义的xx-media格式?
使用spring boot可以基于配置文件快速修改媒体类型。
spring: mvc: contentnegotiation: # 开启请求参数内容协商模式 favor-parameter: true # 修改parameterName,默认为format parameter-name: xx # 自定义媒体类型 media-types: xx-media: application/xx-media 或者如果不修改xml文件,还可以通过重写configureContentNegotiation方法来实现。
@Configuration public class WebConfig { @Bean public WebMvcConfigurer webMvcConfigurer () { return new WebMvcConfigurer() { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.mediaType("xx-media", MediaType.parseMediaType("application/xx-media")); } @Override public void extendMessageConverters(List> converters) { converters.add(new CustomConverter()); } }; } } 配置完,可以看到客户端、浏览器可接收的媒体类型如下:

无论使用xml形式,还是重写configureContentNegotiation都需要写一个自定义converter。
举个例子,只处理写数据。
public class CustomConverter implements HttpMessageConverter { @Override public boolean canRead(Class clazz, MediaType mediaType) { return false; } @Override public boolean canWrite(Class clazz, MediaType mediaType) { return clazz.isAssignableFrom(User.class); } @Override public List getSupportedMediaTypes() { return MediaType.parseMediaTypes("application/xx-media"); } @Override public User read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return null; } @Override public void write(User user, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // 自定义协议数据写出 String data = user.getName() + "---" +user.getSex() + "---" + user.getAge(); //写出去 OutputStream body = outputMessage.getBody(); body.write(data.getBytes()); } } 请求结果显示如下:

无论使用浏览器参数访问形式,还是通过postman修改请求头的accept接收值,都可以支持application/xml、application/json、application/xx-media类型的数据。