源码理解SpringBoot理解数据响应(总体第三篇)

上两篇笔记中已经学习到了请求参数相关的处理,文章地址,接下来学习数据响应的代码流程

1、ReturnValueHandler

1)复习一下响应JSON树

(1)过程

源码理解SpringBoot理解数据响应(总体第三篇)_第1张图片
源码理解SpringBoot理解数据响应(总体第三篇)_第2张图片

(2)响应JSON原理

  • 断点打在这里
    源码理解SpringBoot理解数据响应(总体第三篇)_第3张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第4张图片
  • 从这里始终会来到这里
    源码理解SpringBoot理解数据响应(总体第三篇)_第5张图片
  • 这里可以看到返回值参数解析器
    源码理解SpringBoot理解数据响应(总体第三篇)_第6张图片
  • 一直点这个会经过这一步
    源码理解SpringBoot理解数据响应(总体第三篇)_第7张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第8张图片
  • 继续点刚才标记的那个可以来到这一步


    来到了这里【利用返回值处理器进行后续的处理】



    这里返回了一个false,然后返回处理器判断是否支持这种数据类型
    源码理解SpringBoot理解数据响应(总体第三篇)_第9张图片
    如果它支持的话就会再调用返回值处理器

    在这里会有多次的循环遍历查找【直到找到能处理返回值的那个处理器为止】

    最后匹配到了这个处理器

(3)到底是如何写成JSON数据的呢?

上面的过程中我们找到了处理数据的处理器,接下里详细了解一下如何处理的:

  • 最后的返回值是由这个来处理的

  • 进入这方法看看【其实是利用MessageConverters这个进行处理,然后将数据写成JSON】

    来到了这里

  • 这里的MediaType媒体类型,和浏览器进行类型协商和浏览器会定义好【就是内容协商】
    源码理解SpringBoot理解数据响应(总体第三篇)_第10张图片
    浏览器会与服务器请求的方式告诉能接受什么的类。

  • 内容协商

    这里进入浏览器和我能发的进行

    这里就会找到到底能写和读


    既然往下面走会走到这里来
    源码理解SpringBoot理解数据响应(总体第三篇)_第11张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第12张图片
    这里的for循环会找到我们需要写操作的一个类型
    源码理解SpringBoot理解数据响应(总体第三篇)_第13张图片
    0 - 只支持Byte类型的
    1 - String
    2 - String
    3 - Resource
    4 - ResourceRegion
    5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class
    6 - MultiValueMap
    7 - true 【不管是什么我都支持】
    8 - true【不管是什么我都支持】
    9 - 支持注解方式xml处理的。
    源码理解SpringBoot理解数据响应(总体第三篇)_第14张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第15张图片
    它会添加点东西,然后再后续的以json方式写出去。
    源码理解SpringBoot理解数据响应(总体第三篇)_第16张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第17张图片
    最后的最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)

2)内容协商原理

内容协商就是客户端和服务器之间进行协商,到底返回什么样子的数据类型,已达到方便的显示。

(1)看一下使用XML来处理

  • 导入依赖
    源码理解SpringBoot理解数据响应(总体第三篇)_第18张图片

            com.fasterxml.jackson.dataformat
            jackson-dataformat-xml
        
  • 看响应状态
    源码理解SpringBoot理解数据响应(总体第三篇)_第19张图片
    这样响应的原因是为什么呢【它把xml排在了第二位】
    源码理解SpringBoot理解数据响应(总体第三篇)_第20张图片
    当使用postman测试的时候,就会发现响应的还是JSON,而修改Accept才可以响应XML。

(2)打断点来看

  • 打断点发现它根JSON也是一样的都由这个处理
    源码理解SpringBoot理解数据响应(总体第三篇)_第21张图片
  • 同样的走到这一步
    源码理解SpringBoot理解数据响应(总体第三篇)_第22张图片
    • 首先判断当前响应头中是否已经有确定的媒体类型,MediaType
      源码理解SpringBoot理解数据响应(总体第三篇)_第23张图片

    • 没有的话进行一个全新的媒体类型【这里就是通过前端的Accept字段支持的类型进行处理,找到全部的类型】
      源码理解SpringBoot理解数据响应(总体第三篇)_第24张图片
      包装对象,获取Accept字段
      源码理解SpringBoot理解数据响应(总体第三篇)_第25张图片

    • 获取能产生的类型
      源码理解SpringBoot理解数据响应(总体第三篇)_第26张图片
      这里获取到了比如我们刚刚导入的xml的,JSON的

    • 在这一步会找到支持xml,JSON的数据converter
      源码理解SpringBoot理解数据响应(总体第三篇)_第27张图片
      源码理解SpringBoot理解数据响应(总体第三篇)_第28张图片
      converter把支持的类型统计出来。
      源码理解SpringBoot理解数据响应(总体第三篇)_第29张图片

    • 以我们刚刚的xml的请求为例:最后统计出来,客户端能处理xml,而服务端可以处理上面的9种吧。

    • 这里做一个最佳匹配【嵌套for循环,应该都知道吧】
      源码理解SpringBoot理解数据响应(总体第三篇)_第30张图片

    • 这里就能相互匹配到
      源码理解SpringBoot理解数据响应(总体第三篇)_第31张图片

    • 这里又要进行进一步的判断到底哪个能将Car对象转换为xml对象
      源码理解SpringBoot理解数据响应(总体第三篇)_第32张图片
      上面是匹配到哪个能处理xml,下面一步又判断到哪个能转换。

    • 最后从这里来进行写【这里先不再详细说写的过程】

    • 最后返回到了这里
      源码理解SpringBoot理解数据响应(总体第三篇)_第33张图片

    • 具体匹配的要补充一点它是有优先级的
      源码理解SpringBoot理解数据响应(总体第三篇)_第34张图片

(3)小总结

源码理解SpringBoot理解数据响应(总体第三篇)_第35张图片

3)基于请求参数的内容协商原理

(1)开启浏览器参数方法内容协商功能

上面介绍的内容协商原理呢是默认采用的请求头进行对比响应的。
源码理解SpringBoot理解数据响应(总体第三篇)_第36张图片

(2)在浏览器通过formant设置

源码理解SpringBoot理解数据响应(总体第三篇)_第37张图片

(3)那上面面能开启的原理是什么呢

同样的这里你带上了那个参数后,会在后台动态的给你确定了你指定的那个参数类型了
源码理解SpringBoot理解数据响应(总体第三篇)_第38张图片
自然而然它内容协商的也会多一个
源码理解SpringBoot理解数据响应(总体第三篇)_第39张图片

3)自定义MessageConverter

(1)先看点概念

实现多协议数据兼容。json、xml、自定义数据类型、@ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理

  • Processor 处理方法返回值。通过 MessageConverter 处理。
  • 所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)。
  • 内容协商找到最终的 messageConverter;

(2)响应数据

  • 浏览器请求的话响应我们的JSON
  • 如果是AJAX的话,我们响应xml
  • 如果是自定义数据类型的话,我们响应自定义数据类型。
    源码理解SpringBoot理解数据响应(总体第三篇)_第40张图片
    源码理解SpringBoot理解数据响应(总体第三篇)_第41张图片

(3)为什么能有那么多的Converter呢

  • 先去找找为什么能启动就有那么多默认的Converter
    源码理解SpringBoot理解数据响应(总体第三篇)_第42张图片
    经过层层找下去,原来是在这里
    在这里插入图片描述
    源码理解SpringBoot理解数据响应(总体第三篇)_第43张图片
    只要导入了xml,JSON依赖就能自动启用的原因就是如下
    源码理解SpringBoot理解数据响应(总体第三篇)_第44张图片

只要我们想启动自用的Converter那我们就要自定义。

(4)自定义Converter

以后我们要记住,想要定制WEBMvc的功能,就在实现了WebMvcConfiguration的类里面扩展一些功能即可。

    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {

            }

            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

            }

            @Override
            public void configureAsyncSupport(AsyncSupportConfigurer configurer) {

            }

            @Override
            public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

            }

            @Override
            public void addFormatters(FormatterRegistry registry) {

            }

            @Override
            public void addInterceptors(InterceptorRegistry registry) {

            }

            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {

            }

            @Override
            public void addCorsMappings(CorsRegistry registry) {

            }

            @Override
            public void addViewControllers(ViewControllerRegistry registry) {

            }

            @Override
            public void configureViewResolvers(ViewResolverRegistry registry) {

            }

            @Override
            public void addArgumentResolvers(List resolvers) {

            }

            @Override
            public void addReturnValueHandlers(List handlers) {

            }

           /* @Override
            public void configureMessageConverters(List> converters) {

            }*/

            @Override
            public void extendMessageConverters(List> converters) {

            }

            @Override
            public void configureHandlerExceptionResolvers(List resolvers) {

            }

            @Override
            public void extendHandlerExceptionResolvers(List resolvers) {

            }

            @Override
            public Validator getValidator() {
                return null;
            }

            @Override
            public MessageCodesResolver getMessageCodesResolver() {
                return null;
            }
        };
    }

这里只能进行postman测试,原因和解决办法如下

(5)postman与浏览器协商完全匹配

  • 它浏览器默认就两种:xml和JSON当你写自己的format=x-car就会错误
    源码理解SpringBoot理解数据响应(总体第三篇)_第45张图片
    这些策略都已经添加好了,我们就只能自己指定了。

  • 自定义SpringMVC

@Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void extendMessageConverters(List> converters) {
                converters.add(new zidingyiMessageConverter());
            }

            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                //参数支持的媒体类型
                Map mediaTypeMap = new HashMap<>();
                mediaTypeMap.put("json",MediaType.APPLICATION_JSON);
                mediaTypeMap.put("xml",MediaType.APPLICATION_ATOM_XML);
                mediaTypeMap.put("car",MediaType.parseMediaType("application/x-car"));
                ParameterContentNegotiationStrategy parameter = new ParameterContentNegotiationStrategy(mediaTypeMap);

                configurer.strategies(Arrays.asList(parameter));
            }
        };
    }
  • 此时就可以:http://localhost:8888/car?format=car进行测试了

  • 我们还可以这样设置

@Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void extendMessageConverters(List> converters) {
                converters.add(new zidingyiMessageConverter());
            }

            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                //参数支持的媒体类型
                Map mediaTypeMap = new HashMap<>();
                mediaTypeMap.put("json",MediaType.APPLICATION_JSON);
                mediaTypeMap.put("xml",MediaType.APPLICATION_ATOM_XML);
                mediaTypeMap.put("car",MediaType.parseMediaType("application/x-car"));
                //设置如下的两种的匹配模式
                ParameterContentNegotiationStrategy parameter = new ParameterContentNegotiationStrategy(mediaTypeMap);

                HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();
                configurer.strategies(Arrays.asList(parameter,headerStrategy));
            }
        };
    }

有可能我们添加的自定义的功能会覆盖默认很多功能,导致一些默认的功能失效。
大家考虑,上述功能除了我们完全自定义外?SpringBoot有没有为我们提供基于配置文件的快速修改媒体类型功能?怎么配置呢?【提示:参照SpringBoot官方文档web开发内容协商章节】

你可能感兴趣的:(#,SpringBoot框架,SpringBoot,SpringBoot源代码,SpringBoot数据响应)