内容协商源码解析与自定义 MessageConverter

目录

内容协商

1、引入xml依赖

2、postman分别测试返回json和xml

 3、开启浏览器参数方式内容协商功能

4、内容协商原理

5、自定义 MessageConverter

综上


内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

若客户端无法解析服务端返回的内容,即媒体类型未匹配,那么相应406。

1、引入xml依赖

默认没有返回xml的能力 

 <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2、postman分别测试返回json和xml

只需要改变请求头中Accept字段。(Http协议中规定的,告诉服务器,该客户端可以接收的数据类型。)

 3、开启浏览器参数方式内容协商功能

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,实现多协议数据兼容)

浏览器端不传参数或者是没匹配到,就是"*/*",都能匹配,然后按权重匹配。

4、内容协商原理

内容协商的内容在返回值处理器 RequestResponseBodyMethodProcessor->writeWithMessageConverters() 方法中

  • 1、判断当前响应头中是否已经保存了 MediaType,如果有则该 MediaType 作为 selectedMediaType。

  • 2、否则,先获取浏览器可接受的所有MediaType: acceptableType

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

  • 3、获取支持当前返回值类型的 MessageConverter 所支持的所有 MediaType:producibleTypes

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

  • 4、对两种类型进行最佳匹配,筛选出所有可以使用的 MediaType:mediaTypesToUse

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

 

  • 5、遍历循环所有当前系统的 MessageConverter,匹配支持将当前返回值类型 转换为 selectedMediaType 的 MessageConverter,并使用其 write() 方法将当前返回值写入到响应体中。

5、自定义 MessageConverter

实现多协议数据兼容。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<HttpMessageConverter<?>> converters) {
                converters.add(new CustomConverter());
            }
        };
    }
}

 配置完,可以看到客户端、浏览器可接收的媒体类型如下:

 

无论使用xml形式,还是重写configureContentNegotiation都需要写一个自定义converter。

举个例子,只处理写数据。

public class CustomConverter implements HttpMessageConverter<User> {
    @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<MediaType> 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类型的数据。

 ​​​​​​       

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot中的内容协商是指根据请求的参数或者请求头中的信息来确定返回的内容类型。在SpringBoot中,默认开启了基于请求头的内容协商功能,即根据请求头中的Accept字段来确定返回的内容类型。同时,也可以通过配置开启基于请求参数的内容协商功能,即根据请求参数来确定返回的内容类型。\[1\]\[2\]内容协商在SpringMVC中也有实现,但SpringMVC默认开启的是基于请求头的内容协商功能。\[1\]所以,如果你在SpringBoot中使用内容协商功能,可以直接使用默认的配置,而如果你在SpringMVC中使用内容协商功能,需要手动配置开启基于请求参数的内容协商功能。\[1\]\[2\]内容协商是一个非常重要的知识点,对于理解和掌握SpringBoot和SpringMVC的请求和响应处理机制非常有帮助。\[3\] #### 引用[.reference_title] - *1* *3* [SpringBoot中的内容协商,颠覆你的认知](https://blog.csdn.net/likun557/article/details/122994859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Springboot-内容协商](https://blog.csdn.net/qq_42250642/article/details/116055710)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值