HTTPMessageConverter原理

1、MessageConverter规范

image.png

HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。

2、默认的MessageConverter

image.png

0 - 只支持Byte类型的

1 - String

2 - String

3 - Resource

4 - ResourceRegion

5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class

6 - MultiValueMap

7 - 所有类型

8 - 所有类型

9 - 支持注解方式xml处理的。

 

最终 MappingJackson2HttpMessageConverter  把对象转为JSON(利用底层的jackson的objectMapper转换的)

image.png

 

3、内容协商

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

1、引入xml依赖

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

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

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

image.png

 

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

  • 开启基于请求参数的内容协商功能。
spring:
    contentnegotiation:
      favor-parameter: true  #开启请求参数内容协商模式

发请求: http://localhost:8080/user?format=json 、http://localhost:8080/user?format=xml

 

image.png

确定客户端接收什么样的内容类型;

1、Parameter策略优先确定是要返回json数据(获取请求头中的format的值)

image.png

2、最终进行内容协商返回给客户端json即可。

4、内容协商原理

1、判断当前响应头中是否已经有确定的媒体类型。MediaType

2、获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】

3、contentNegotiationManager 内容协商管理器 (有两种策略)

  • HeaderContentNegotiationStrategy(请求头的内容协商策略,默认使用)

HeaderContentNegotiationStrategy 确定客户端可以接收的内容类型,然后根据权重返回相应的类型

  • ParameterContentNegotiationStrategy(请求参数的内容协商策略))

基于上述浏览器参数方式内容协商功能,客户端可以根据请求参数指定服务器返回的数据类型,例如:http://localhost:8080/user?format=xml(指定服务器数据以xml形式返回)

3、遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)

4、找到支持操作Person的converter,把converter支持的媒体类型统计出来。

5、客户端需要【application/xml】。服务端能力【10种、json、xml】

   

image.png

6、进行内容协商的最佳匹配类型

7、用 支持 将对象转为 最佳匹配类型 的converter。调用它进行转化 。

image.png

导入了jackson处理xml的包,xml的converter就会自动进来

WebMvcConfigurationSupport
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);

if (jackson2XmlPresent) {
            Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
            if (this.applicationContext != null) {
                builder.applicationContext(this.applicationContext);
            }
            messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
        }

 

5、自定义 MessageConverter

  • 实现多协议数据兼容。json、xml、x-wust(自定义的协议)
  1. @ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理
  2. Processor 处理方法返回值。通过 MessageConverter 处理
  3. 所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)
  4. 内容协商找到最终的 messageConverter

image.png

 

 

 

image.png

 

 

有可能我们添加的自定义的功能会覆盖默认很多功能,导致一些默认的功能失效。

  • 编写User实体类
@Data
public class User {
    private int id;
    private String name;
    private int age;
}
  • 编写Controller
@Controller
public class MyController {

    @RequestMapping("/user")
    @ResponseBody
    public User user(){
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(22);
        return user;
    }
}
  • 编写MyConfig配置类,增加自定义内容协商策略以及消息转换器
@Configuration
public class MyConfig {
    @Bean
    public WebMvcConfigurer myConfigurer(){
        return new WebMvcConfigurer() {
            //增加自定义内容协商策略
            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                Map<String,MediaType> map = new HashMap<>();
                map.put("wust",MediaType.parseMediaType("application/x-wust"));
                //因为这个配置默认会覆盖springboot默认的配置,所以我们需要对参数内容协商策略加上原有的
                // springboot默认的对json以及xml的处理策略
                map.put("json",MediaType.APPLICATION_JSON);
                map.put("xml",MediaType.APPLICATION_ATOM_XML);
                ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(map);
                strategy.setParameterName("f");//设置format,默认为format
                configurer.strategies(Arrays.asList(strategy));
            }
            //配置这个会默认全面覆盖springboot默认的MessageConverter,只保留当前的
//            @Override
//            public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//
//            }
            //配置这个是在springboot的基础上进行扩展的MessageConverter
            @Override
            public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(new HttpMessageConverter<User>() {
                    @Override
                    public boolean canRead(Class<?> aClass, MediaType mediaType) {
                        return false;
                    }
                    //判断是否可写
                    @Override
                    public boolean canWrite(Class<?> aClass, MediaType mediaType) {
                        return aClass.isAssignableFrom(User.class);
                    }
                    //返回消息转换器支持的类型
                    @Override
                    public List<MediaType> getSupportedMediaTypes() {
                        //返回自定义的类型
                        return MediaType.parseMediaTypes("application/x-wust");
                    }

                    @Override
                    public User read(Class<? extends User> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
                        return null;
                    }
                    //将数据通过输出流以指定的方式返回给客户端
                    @Override
                    public void write(User user, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
                        OutputStream body = httpOutputMessage.getBody();
                        //自定义返回的样式
                        String res = user.getId()+";"+user.getName()+";"+user.getAge();
                        body.write(res.getBytes());
                    }
                });
            }
        };
    }
}
  • 测试

方式1:http://localhost:8080/user?f=json

结果:{"id":1,"name":"张三","age":22}

方式2:http://localhost:8080/user?f=xml

结果:<User><id>1</id><name>张三</name><age>22</age></User>

方式3:http://localhost:8080/user?f=wust

结果:1;张三;22

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值