内容协商原理
根据客户端接收能力的不同,返回不同媒体类型的数据。改变请求头中Accept
字段,告诉服务器客户端可以接收的数据类型。
-
判断当前响应头中是否已经有确定的媒体类型,如果有就使用之前确定的媒体类型
-
使用
contentNegotiationManager
内容协商管理器,默认使用基于请求头的策略,来获取客户端支持接收的内容类型,即获取请求头中的Accept
字段的值
-
获取服务器能够产生的媒体类型。循环遍历所有当前系统的
MessageConverter
,找到支持操作当前对象的消息转换器
-
找到支持操作当前对象的
converter
,把converter
支持的媒体类型统计出来
-
进行协商内容的最佳匹配媒体类型,即匹配客户端想要接收的内容类型和服务器能够产生的内容类型
-
再次循环遍历所有
MessageConverter
,利用支持将对象转为最佳匹配媒体类型的converter
,调用它进行转换
基于请求参数的内容协商原理
开启基于请求参数的内容协商模式
spring:
mvc:
contentnegotiation:
favor-parameter: true
内容协商管理器的管理策略变成了两个,一个是基于参数的内容协商策略,一个是基于请求头的内容协商策略
遍历所有的内容协商策略,确定客户端接收什么样的内容类型。基于请求参数的策略优先确定是要返回json
数据还是xml
数据,这是根据请求参数format
确定的
自定义MessageConverter
自定义MessageConverter
可以实现多协议数据兼容
@ResponseBody
响应数据出去 调用RequestResponseBodyMethodProcessor
处理RequestResponseBodyMethodProcessor
通过MessageConverter
处理方法返回值- 所有
MessageConverter
合起来可以支持各种媒体类型数据的操作(读、写) - 内容协商找到最终的
messageConverter
自定义MessageConverter
public class MyMessageConverter implements HttpMessageConverter<Person> {
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return false;
}
/**
* 能够写Person类型的数据
* @param clazz 传入的数据类型
* @param mediaType 传入的媒体类型
* @return 返回是否能够写指定的数据类型
*/
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return clazz.isAssignableFrom(Person.class);
}
/**
* 服务器要统计所有的MessageConverter都能支持哪些媒体类型
* @return 支持的媒体类型集合
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/myMediaType");
}
@Override
public Person read(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//自定义协议数据的写出
String data = person.getUserName() + ";" + person.getAge() + ";" + person.getBirth();
//将数据写出去
OutputStream body = outputMessage.getBody();
body.write(data.getBytes());
}
}
将自定义的MessageConverte
通过自动配置类,重写extendsMessageConverter()
方法,来添加到容器中
这样通过基于请求头的策略,就可以使用自定义的媒体类型来进行内容协商
如果是基于请求参数的内容协商原理,需要在自动配置类中重写configureContentNegotiation()
方法,创建一个支持自定义媒体类型的基于请求参数的内容协商策略,并注册到内容协商策略中