当前位置: 首页 > news >正文

SpringBoot-Web开发-内容协商——多端内容适配内容协商原理HttpMessageConverter

其它篇章:
一:SpringBoot3-日志——日志原理&日志格式&日志级别&日志分组&文件输出&文件归档&滚动切割
二:SpringBoot3-Web开发-静态资源——WebMvcAutoConfiguration原理&资源映射&资源缓存&欢迎页&Favicon&自定义

一、多端内容适配

一套系统适配多端数据返回。

假设:
  • 主体:写好一个接口GET /person
  • 部署:部署到服务器,暴露给外界访问。
  • 外界
    1. 一个移动端应用:希望接口返回一个JSON文件;
    2. 一个第三方应用:希望接口返回一个XML文件;
    3. 一个IoT(物联网设备):希望接口返回一个自定义协议数据文件。
提问:
  • 以以上假设为例,如何让一个接口做到多端的数据反馈?
思考:
  • ,可以写三个请求路径,分别为/person.json/person.xml/person.diy(应用指定后缀),这三个不同应用分别访问指定的请求路径:
    • 缺点:这种方法只能用在内部接口少的情况下。如果,内部接口很多,那么每个接口都得拆分成三个接口,对应三个外部应用。若需要返回更多种类型数据文件,这个数量还得上升。
  • SpringBoot可以解决这个问题,详细看接下来的内容。

默认规则

a.主要内容

内容协商功能是SpringMVC自带的功能,SpringBoot对其进行了整合,快速实现一套系统适配多端数据返回。

SpringBoot多端内容适配
  1. 基于请求头内容协商(默认开启)
  • 客户端服务端 发送请求时,携带HTTP标准的Accept请求头。
    • 客户端:外界应用
    • 服务端:接口
    • accept:是http协议里规定的一个标准
  • 客户端服务端 发送请求时,带上Accept,让 服务端 知道该返回什么类型的数据,SpringBoot 就把数据自动格式化成对应类型,再返回。
    • 举例
      • Accept:application/json
      • Accept:text\xml
      • Accept:text\yaml
  1. 基于请求参数内容协商(需要手动开启)
  • 举例
    • ?format=json:
      • 发送请求: GET /projects/spring-boot?format=json
      • 匹配:匹配到 GetMapping("/projects/spring-boot")
      • 返回:根据参数协商,优先返回json类型数据
    • 同理,发送请求 GET /projects/spring-boot?format=xml,则优先返回xml类型数据

b.演示验证

  1. 创建一个接口,其内容如下:
    • 先绑定地址:@GetMapping("/person")
    • 再定义一个 Person类。
    • 创建的接口代码如下:
      package com.atwyb.web.controller;import com.atwyb.web.bean.Person;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;@RestController
      public class HelloController {@GetMapping("/person")public Person person(){Person person = new Person();person.setId("1");person.setUserName("zhangsan");return person;}
      }
      
    • person的javabean如下:
      package com.atwyb.web.bean;public class Person {private String id;private String userName;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}
      }
      

点进@RestController,发现标注了@ResponseBody。说明@RestController返回的数据都标注了@ResponseBody,而所有标注了@ResponseBody的对象,都会以json传输。
在这里插入图片描述

  1. 启动项目,在浏览器中验证:

    • 浏览器中访问:http://localhost:8080/person
    • 发现数据的类型为json,如下图所示:在这里插入图片描述
  2. 思考:要想让数据适配xml,该怎么做?

    • SpringBoot默认支持把对象写为json。因为默认web场景导入了jackson处理json的包:jackson-core。
    • jackson是一个库,也支持把数据写为xml,但要导入xml相关依赖:
      • 引入支持xml内容依赖:
         <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
        </dependency>
        
      • 标注xml注解:在Person这个JavaBean下标注xml注解
        @JacksonXmlRootElement
        public class person{(省略……)}
        
    • 开启基于请求参数的内容协商(默认关闭)
      • 开启基于请求参数的内容协商功能,默认参数名为format
        spring.mvc.contentnegotiation.favor-parameter=true
        
      • 指定内容协商时使用的参数名,默认为format
      • 在application.propertise中添加以下内容:
        在这里插入图片描述
  3. 验证:

    • 在浏览器中访问http://localhost:8080/person?format=xml
      在这里插入图片描述
    • 在浏览器中访问http://localhost:8080/person?type=json在这里插入图片描述

二、内容协商原理-HttpMessageConverter

学习逻辑链:

  1. 目的:想要自定义接口的返回内容
  2. 分析:要想自定义接口的返回内容,就要先理解内容协商的底层原理;而要理解内容协商的底层原理,只要知道HttpMessageConverter怎么工作,什么时候工作就行了;知道HttpMessageConverter工作原理后,就能通过定制HttpMessageConverter来实现多端内容协商,以达到自定义接口返回内容的目的。
  3. 步骤:
    a. 了解HttpMessageConverter怎么工作,什么时候工作。
    b. 这样就能,理解内容协商的底层原理
    c. 接下来就能,通过定制HttpMessageConverter来实现多端内容协商。
    d. 这样就,达到了想要自定义接口的返回内容的目的。
  4. 总结:要想知道怎么自定义接口的返回内容,其实就是要知道怎么通过定制HttpMessageConverter来实现多端内容协商。

WebMvcConfigurer接口里,能够配置很多底层的东西,其中就包含了一个configureMessageConverters,如下图。
在这里插入图片描述
只需要编写WebMvcConfigurer接口提供的configureMessageConverters底层,修改底层的MessageConverters就可以了。
思考:只要修改以上的MessageConverters就可以了,但为什么这样做就可以了?这就是接下来要说的内容了。

1、@ResponseBody由HttpMessageConverter处理

a.主要内容

在向浏览器返回内容的controller里,有一个@RestController注解,而这个注解里又包含一个@ResponseBody,而注解标注在类上面,就表示标注在每一个方法上。

  1. 如果controller方法的返回值标注了@ResponseBody注解,
    按照SpringMVC的原理,我们从DispatcherServlet.class开始,所有请求来到DispatcherServlet,都是从doDispatch()开始的。
    ctlr+n搜索DispatcherServlet.class,进入后继续ctlr+n搜索doDispatch(),在其内容第一行设置一个断点,找到以下界面:
    在这里插入图片描述
    往下翻找到HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
    在这里插入图片描述
  2. 如果根据/person这个请求路径找到了某个方法要处理,那就要找到这个适配器,最终利用这个适配器处理方法。往下翻找到mv = ha.handle(processedRequest, response, mappedHandler.getHandler());,如图。这是正真执行handler的语句。
    在这里插入图片描述
  3. 给person()第一行打个断点,并以debug启动,看看是怎么处理的。
    在这里插入图片描述
    浏览器访问http://localhost:8080/person?format=json,先来到doDispatch,它来接第一个请求。在这里插入图片描述
    放行。
    在这里插入图片描述
    再放行,来到正真执行handler的语句的位置。
    在这里插入图片描述
  4. 这个时候点击step into,进到这个目标执行方法,来到以下界面:
    在这里插入图片描述
    再点进handleInternal,往下翻,看到invokeHandlerMethod方法。
    在这里插入图片描述
    点进去,在第一行设置一个断点:
    在这里插入图片描述
    一直放行到这,目标方法还没进行到,只进行到invokeHandlerMethod
    RequestMappingHandlerAdapter.class中往下找到invocableMethod.invokeAndHandle,意思是执行并处理,把这一放行,就会去到person()并执行。在这里插入图片描述
    这样就会得到结论:
    RequestMappingHandlerAdapter.class里面的invokeAndHandle()才是正真执行目标方法的。

b. 总结:

  • 如果controller方法的返回值标注了@ResponseBody注解:
    1. 请求进来先来到DispatcherServletdoDispatch()进行处理
    2. 找到一个HandlerAdapter适配器,利用适配器执行目标方法
    3. RequestMappingHandlerAdapter来执行,调用invokeHandlerMethod()来执行目标方法
    4. 目标方法执行之前,准备好两个东西:
      • HandlerMethodArgumentResolver:参数解析器,确定目标方法每个参数值
      • HandlerMethodReturnValueHandler:返回值处理器,确定目标方法的返回值该怎么处理。
    5. 目标方法执行完成,会返回返回值对象
    6. 找到一个合适的返回值处理器
    7. 最终找到RequestResponseBodyMethodProcessor中能处理 标注了@ResponseBody注解 的方法
    8. RequestResponseBodyMethodReturnValueHandler调用writeWithMessageConverters,利用MessageConverter把返回值写出去。

看到@GetMapping,要知道这个注解都是由invokeHandlerMethod所在的RequestMappingHandlerAdapter.class

其它篇章:
一:SpringBoot3-日志——日志原理&日志格式&日志级别&日志分组&文件输出&文件归档&滚动切割
二:SpringBoot3-Web开发-静态资源——WebMvcAutoConfiguration原理&资源映射&资源缓存&欢迎页&Favicon&自定义


文章转载自:

http://jmyoiZdz.kkrnm.cn
http://U7ZkAiEE.kkrnm.cn
http://U5q6Cqb3.kkrnm.cn
http://xaVVTInA.kkrnm.cn
http://Vt3fjyKo.kkrnm.cn
http://qCLRzz5L.kkrnm.cn
http://ji5U6RD9.kkrnm.cn
http://twZqSzlg.kkrnm.cn
http://WXuA1qDY.kkrnm.cn
http://PojG6dju.kkrnm.cn
http://4nbfia2D.kkrnm.cn
http://aPntSpP2.kkrnm.cn
http://mnOYqwZy.kkrnm.cn
http://4zyyh0FO.kkrnm.cn
http://q4dJNGAn.kkrnm.cn
http://CkhUBgQv.kkrnm.cn
http://leO0AyQx.kkrnm.cn
http://bVfv3j2K.kkrnm.cn
http://WmKyFQUO.kkrnm.cn
http://D6qtUqcC.kkrnm.cn
http://l7WQII8K.kkrnm.cn
http://yWKKMyop.kkrnm.cn
http://CjPkKmG4.kkrnm.cn
http://dFe01gsx.kkrnm.cn
http://OJHdvA6L.kkrnm.cn
http://Ilh8gLaf.kkrnm.cn
http://ZtzFKfyc.kkrnm.cn
http://QO1VZHcD.kkrnm.cn
http://RLSWvUrn.kkrnm.cn
http://vkNQPmlR.kkrnm.cn
http://www.dtcms.com/a/372528.html

相关文章:

  • ESWA修改后投稿流程
  • 可能断更说明
  • Batch Normalization:深度学习中的“加速器”与“稳定器”
  • 【Docker-Day 25】深入理解 Kubernetes Namespace:实现多租户与环境隔离的利器
  • Java工业通信实战(三):Modbus RTU串口通信实现
  • Referential Integrity 引用完整性
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(27):文法+单词第8回4+考え方7
  • Verilog三段式FSM,实现十字路口红绿灯
  • Java-面试八股文-JVM篇
  • Android开发-Activity附加信息
  • linux内核 - 获取单调计时时间戳的方法
  • 文献阅读 250907-Humans have depleted global terrestrial carbon stocks by a quarter
  • 装饰(Decorator)模式可以在不修改对象外观和功能的情况下添加或者删除对象功能
  • Java-Spring入门指南(三)深入剖析IoC容器与Bean核心机制
  • JavaScript 创建型设计模式详解
  • 【深度学习】CNN 卷积层
  • 洛谷 B4071 [GESP202412 五级] 武器强化
  • 0. 系统架构设计师考试大纲核心内容速览
  • [C/C++学习] 6.弹跳小球(B)
  • Easysearch 证书:Windows 上创建自签名证书的 7 种方法
  • Kafka基础理论
  • JavaScript 设计模式概览
  • Jenkins与Kubernetes集成部署流水线
  • arduino uno小车开发接线与程序记录
  • 【LeetCode 热题 100】128. 最长连续序列
  • 在object-c中方法多个参数怎么接收?
  • 蓓韵安禧DHA高含量好吸收特性深度解析
  • Pandas 合并数据集:merge 和 join
  • DINOv3 新颖角度解释
  • leetcode219.存在重复元素