ToB企服应用市场:ToB评测及商务社交产业平台

标题: 十,Spring Boot 的内容协商的具体分析(附+Debug调试说明) [打印本页]

作者: 火影    时间: 2024-9-14 09:40
标题: 十,Spring Boot 的内容协商的具体分析(附+Debug调试说明)
十,Spring Boot 的内容协商的具体分析(附+Debug调试说明)

@
目录

1. 根本介绍

根据客户端接收能力不同,SpringBoot返回不同媒体类型的数据。
比如:客户端 Http请求 Accept:application/xml 则返回xml数据,客户端 Http 请求 Accept:application/json 则返回json数据。
关于 内容协商的 类是:AbstractJackson2HttpMessageConverter.java 这个类


2. 准备工作

导入相关的 jar 依赖。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.rainbowsea</groupId>
  7.     <artifactId>springboot_jsonxml</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.    
  10.     <parent>
  11.         <groupId>org.springframework.boot</groupId>
  12.         <artifactId>spring-boot-starter-parent</artifactId>
  13.         <version>2.5.3</version>
  14.     </parent>
  15.    
  16.    
  17.     <dependencies>
  18.         <dependency>
  19.             <groupId>org.springframework.boot</groupId>
  20.             <artifactId>spring-boot-starter-web</artifactId>
  21.         </dependency>
  22.         
  23.         <dependency>
  24.             <groupId>org.projectlombok</groupId>
  25.             <artifactId>lombok</artifactId>
  26.         </dependency>
  27.     </dependencies>
  28. </project>
复制代码
准备好,测试的 Bean 类,两个,分别为 Car,Monster 类,这里我利用了 lombok 插件自动生成 set和 get方法。关于这部分的内容大家可以移步至:✏️✏️✏️ 六,Spring Boot 容器中 Lombok 插件的具体利用,简化设置,提高开发效率_lombok的getter和setter怎么用-CSDN博客
  1. package com.rainbowsea.bean;
  2. import lombok.Data;
  3. @Data
  4. public class Car {
  5.     private String name;
  6.     private Double price;
  7. }
复制代码
  1. package com.rainbowsea.bean;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. import lombok.NoArgsConstructor;
  5. import lombok.Setter;
  6. import lombok.ToString;
  7. import org.springframework.boot.context.properties.ConfigurationProperties;
  8. import org.springframework.stereotype.Component;
  9. import java.util.Date;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.Set;
  13. @Component
  14. @Setter
  15. @Getter
  16. @ToString
  17. @AllArgsConstructor
  18. @NoArgsConstructor
  19. public class Monster {
  20.     private Integer id;
  21.     private String name;
  22.     private Boolean isMarried;
  23.     private Integer age;
  24.     private Date birth;
  25.     private Car car;
  26.     private String[] skill;
  27.     private List<String> hobby;
  28.     private Map<String,Object> wife;
  29.     private Set<Double> salaries;
  30.     private Map<String,List<Car>> cars;
  31. }
复制代码
相关的 Controller 控制器,处理相关的请求路径映射
  1. package com.rainbowsea.controller;
  2. import com.rainbowsea.bean.Car;
  3. import com.rainbowsea.bean.Monster;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.ResponseBody;
  7. import java.util.Date;
  8. @Controller
  9. public class ResponseController {
  10.     // 返回 Monster 数据-要求以JSON格式返回
  11.     @GetMapping("/get/monster")
  12.     @ResponseBody
  13.     public Monster getMonster() {
  14.         // monster 对象是从DB数据库获取-这里老师模拟一个monster对象
  15.         Monster monster = new Monster();
  16.         monster.setId(100);
  17.         monster.setName("奔波霸");
  18.         monster.setAge(200);
  19.         monster.setIsMarried(false);
  20.         monster.setBirth(new Date());
  21.         Car car = new Car();
  22.         car.setName("奔驰");
  23.         car.setPrice(222.2);
  24.         monster.setCar(car);
  25.         return monster;
  26.     }
  27. }
复制代码
项目标/应用程序的启动场景
  1. package com.rainbowsea;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication  // 标注项目的启动场景
  5. public class Application {
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(Application.class,args);
  8.     }
  9. }
复制代码
运行程序,打开浏览器输入:http://localhost:8080/get/monster 。运行测试

3. 内容协商的本质

从上述运行结果的返回来看,显示的是 JSON格式的数据。
为什么显示的是 JSON格式的数据。显示返回的是什么样的格式的数据是由:
请求头当中的 Accept 属性的值所决定的。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8

  1. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
  2. xml 为 0.9 优先级更高
  3. */*(其它的数据类型,包括 json格式的字符) 为 0.8 稍微低一点。
复制代码
而这里之以是显示的 JSON 格式的数据,是因为在我们pom.xml 文件中导入的 spring boot 依赖当中包含了 json 数据格式的 jar 依赖。

而没有 xml 的数据格式的 jar 依赖,自然就是优先为 json 你有的数据格式的jar依赖为准了。
我们可以 Debug 看看。
我们在 AbstractJackson2HttpMessageConverter.java 类当中的 writeInternal() 的方法当中打上 断点


直到走到这里,我们查看 generator的值:发现是 JSON。这就没错了,我们仅仅是spring boot 框架种自行设置了 json 数据格式的依赖,而没有其它的数据格式的依赖,自然就利用我们有的数据格式的了。
下面我们导入xml 数据格式的依赖,再进行一个测试
  1.         <dependency>
  2.             <groupId>com.fasterxml.jackson.dataformat</groupId>
  3.             <artifactId>jackson-dataformat-xml</artifactId>
  4.         </dependency>
复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.rainbowsea</groupId>
  7.     <artifactId>springboot_jsonxml</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.    
  10.     <parent>
  11.         <groupId>org.springframework.boot</groupId>
  12.         <artifactId>spring-boot-starter-parent</artifactId>
  13.         <version>2.5.3</version>
  14.     </parent>
  15.    
  16.    
  17.     <dependencies>
  18.         <dependency>
  19.             <groupId>org.springframework.boot</groupId>
  20.             <artifactId>spring-boot-starter-web</artifactId>
  21.         </dependency>
  22.         
  23.         <dependency>
  24.             <groupId>org.projectlombok</groupId>
  25.             <artifactId>lombok</artifactId>
  26.         </dependency>
  27.     </dependencies>
  28. </project>            <dependency>
  29.             <groupId>com.fasterxml.jackson.dataformat</groupId>
  30.             <artifactId>jackson-dataformat-xml</artifactId>
  31.         </dependency>   
复制代码
重新运行程序,打开浏览器输入:http://localhost:8080/get/monster 。运行测试

这回返回的就是 xml 格式的数据了,因为我们这里设置了 json和 xml 两种格式的依赖,但是,xml数据格式的优先级为0.9比 json 的优先级更高,以是显示的是 xml 格式的数据类型。
同样我们也进行一个 Debug 断点调试。照旧一样的。


我们前端显示的也是 xml 格式的数据。

4. 内容协商:留意事项和利用细节


  1. spring:
  2.   mvc:
  3.     contentnegotiation:
  4.       favor-parameter: true # 开启基于请求参数的内容协商功能
  5.       #?format=json
复制代码
实在修改的就是:WebMvcProperties类当中的 内部类 Contentnegotiation的 favorParameter 的值。


设置好以后,重新启动程序,打开浏览器,留意需要在我们地址后面加上 ?format=xxx ,xxx 就是你要转换显示为什么样格式的数据的值。比如:
留意:参数format是规定好的,在开启请求参数的内容协商功能后,SpringBoot底层 ParameterContentNegotiationStrategy 会通过 format 来接收参数,然后返回对应的媒体类型/数据格式,当然format=xxx,这个xxx媒体类型/数据格式是SpringBoot可以
处理的才行,不能乱写。
也留意是英文的 ?



实在这个 format 的值是:ParameterContentNegotiationStrategy 类当中的 parameterName 属性值。

这个我们也可以修改这个值,指定一个内容协商的参数名,就不再是默认的 format而是我们本身定义的一个参数名了。
照旧在 application.yaml 文件当中设置,增加上一个属性。
这里我们指定**内容协商的参数名为,rainbowsea 。

  1. spring:
  2.   mvc:
  3.     contentnegotiation:
  4.       favor-parameter: true # 开启基于请求参数的内容协商功能
  5.       #?format=json      parameter-name: rainbowsea # 指定一个内容协商的参数名,就不再是默认的 format而是      # ?rainbowsea=json ,默认的失效了
复制代码
重新启动程序,浏览器运行测试:

需要留意的是: 我们本身指定一个内容协商的参数名,修改掉了默认的 format 的参数了,就不再是默认的 format而是,rainbowsea=json ,默认的(format 就不可以再用了,已经失效了)失效了。

默认的 format  已经失效了, 无论我们设置=json,照旧 xml ,都返回的是 xml 格式类型的数据
。因为 xml 优先级是0.9 比较高的,以是返回的就是默认优先级高的 xml 的格式的了。
5. 总结:

  1. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
  2. xml 为 0.9 优先级更高
  3. */*(其它的数据类型,包括 json格式的字符) 为 0.8 稍微低一点。
复制代码
6. 末了:

“在这个末了的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4