十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)

news/2024/11/14 11:54:15/

十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)

文章目录

  • 十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)
  • 1. 基本介绍
  • 2. 准备工作
  • 3. 内容协商的本质
  • 4. 内容协商:注意事项和使用细节
  • 5. 总结:
  • 6. 最后:


1. 基本介绍

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

比如:客户端 Http请求 Accept:application/xml 则返回xml数据,客户端 Http 请求 Accept:application/json 则返回json数据。

关于 内容协商的 类是:AbstractJackson2HttpMessageConverter.java 这个类

在这里插入图片描述

在这里插入图片描述

2. 准备工作

导入相关的 jar 依赖。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rainbowsea</groupId><artifactId>springboot_jsonxml</artifactId><version>1.0-SNAPSHOT</version><!--    导入SpringBoot 父工程-规定写法--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version></parent><!--    导入web项目场景启动器:会自动导入和web开发相关的jar包所有依赖【库/jar】--><!--    后面还会在说明spring-boot-starter-web 到底引入哪些相关依赖--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--引入lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>

准备好,测试的 Bean 类,两个,分别为 Car,Monster 类,这里我使用了 lombok 插件自动生成 set和 get方法。关于这部分的内容大家可以移步至:✏️✏️✏️ 六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率_lombok的getter和setter怎么用-CSDN博客

在这里插入图片描述

java">package com.rainbowsea.bean;import lombok.Data;@Data
public class Car {private String name;private Double price;}
java">package com.rainbowsea.bean;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;@Component
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Monster {private Integer id;private String name;private Boolean isMarried;private Integer age;private Date birth;private Car car;private String[] skill;private List<String> hobby;private Map<String,Object> wife;private Set<Double> salaries;private Map<String,List<Car>> cars;}

相关的 Controller 控制器,处理相关的请求路径映射

在这里插入图片描述

java">package com.rainbowsea.controller;import com.rainbowsea.bean.Car;
import com.rainbowsea.bean.Monster;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.Date;@Controller
public class ResponseController {// 返回 Monster 数据-要求以JSON格式返回@GetMapping("/get/monster")@ResponseBodypublic Monster getMonster() {// monster 对象是从DB数据库获取-这里老师模拟一个monster对象Monster monster = new Monster();monster.setId(100);monster.setName("奔波霸");monster.setAge(200);monster.setIsMarried(false);monster.setBirth(new Date());Car car = new Car();car.setName("奔驰");car.setPrice(222.2);monster.setCar(car);return monster;}}

项目的/应用程序的启动场景

在这里插入图片描述

java">package com.rainbowsea;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication  // 标注项目的启动场景
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class,args);}
}

运行程序,打开浏览器输入: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

在这里插入图片描述

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

而这里之所以显示的 JSON 格式的数据,是因为在我们pom.xml 文件中导入的 spring boot>spring boot 依赖当中包含了 json 数据格式的 jar 依赖。

在这里插入图片描述

而没有 xml 的数据格式的 jar 依赖,自然就是优先为 json 你有的数据格式的jar依赖为准了。

我们可以 Debug 看看。

我们在 AbstractJackson2HttpMessageConverter.java 类当中的 writeInternal() 的方法当中打上 断点

在这里插入图片描述

在这里插入图片描述

直到走到这里,我们查看 generator的值:发现是 JSON。这就没错了,我们仅仅是spring boot>spring boot 框架种自行配置了 json 数据格式的依赖,而没有其它的数据格式的依赖,自然就使用我们有的数据格式的了。

下面我们导入xml 数据格式的依赖,再进行一个测试

在这里插入图片描述

<!--        引入 处理xml 的依赖--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId></dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rainbowsea</groupId><artifactId>springboot_jsonxml</artifactId><version>1.0-SNAPSHOT</version><!--    导入SpringBoot 父工程-规定写法--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version></parent><!--    导入web项目场景启动器:会自动导入和web开发相关的jar包所有依赖【库/jar】--><!--    后面还会在说明spring-boot-starter-web 到底引入哪些相关依赖--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--引入lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--        引入 处理xml 的依赖--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId></dependency></dependencies></project>

重新运行程序,打开浏览器输入:http://localhost:8080/get/monster 。运行测试
在这里插入图片描述

这回返回的就是 xml 格式的数据了,因为我们这里配置了 json和 xml 两种格式的依赖,但是,xml数据格式的优先级为0.9比 json 的优先级更高,所以显示的是 xml 格式的数据类型。

同样我们也进行一个 Debug 断点调试。还是一样的。

在这里插入图片描述

在这里插入图片描述

我们前端显示的也是 xml 格式的数据。
在这里插入图片描述


4. 内容协商:注意事项和使用细节

  1. Postman 可以通过修改 Accept 的值,来返回不同的数据格式。感兴趣的大家可以自行去下载,试试。官网地址:https://www.postman.com/

在这里插入图片描述

  1. 对于浏览器,我们无法修改其 Accept的值,怎么办?解决方案:开启支持基于请求参数的内容协商功能

  2. 修改 application.yaml(必须在类路径"resources"下才行),开启基于请求参数的内容协商功能。

在这里插入图片描述

spring:mvc:contentnegotiation:favor-parameter: true # 开启基于请求参数的内容协商功能#?format=json

其实修改的就是:WebMvcProperties类当中的 内部类 Contentnegotiation的 favorParameter 的值。

在这里插入图片描述

在这里插入图片描述

配置好以后,重新启动程序,打开浏览器,注意需要在我们地址后面加上 ?format=xxx ,xxx 就是你要转换显示为什么样格式的数据的值。比如:

  • ?format=json 就是在前端以 json格式的数据展示。
  • ?format=xml 就是在前端以 xml 格式的数据展示。

注意:参数format是规定好的,在开启请求参数的内容协商功能后,SpringBoot底层 ParameterContentNegotiationStrategy 会通过 format 来接收参数,然后返回对应的媒体类型/数据格式,当然format=xxx,这个xxx媒体类型/数据格式是SpringBoot可以
处理的才行,不能乱写。
也注意是英文的 ?

  • http://localhost:8080/get/monster?format=json

在这里插入图片描述

  • http://localhost:8080/get/monster?format=xml

在这里插入图片描述

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

在这里插入图片描述

这个我们也可以修改这个值,指定一个内容协商的参数名,就不再是默认的 format而是我们自己定义的一个参数名了。

还是在 application.yaml 文件当中配置,增加上一个属性。

这里我们指定**内容协商的参数名为,rainbowsea

在这里插入图片描述

spring:mvc:contentnegotiation:favor-parameter: true # 开启基于请求参数的内容协商功能#?format=jsonparameter-name: rainbowsea # 指定一个内容协商的参数名,就不再是默认的 format而是# ?rainbowsea=json ,默认的失效了

重新启动程序,浏览器运行测试:

  • http://localhost:8080/get/monster?rainbowsea=json
  • http://localhost:8080/get/monster?rainbowsea=xml

在这里插入图片描述

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

在这里插入图片描述

默认的 format 已经失效了, 无论我们配置=json,还是 xml ,都返回的是 xml 格式类型的数据

。因为 xml 优先级是0.9 比较高的,所以返回的就是默认优先级高的 xml 的格式的了。

5. 总结:

  1. 内容协商就是:根据客户端接收能力不同,SpringBoot返回不同媒体类型的数据。

    比如:客户端 Http请求 Accept:application/xml 则返回xml数据,客户端 Http 请求 Accept:application/json 则返回json数据。

  2. 内容协商的返回值是由:

  3. 请求头当中的 Accept 属性的值所决定的。Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
xml 为 0.9 优先级更高
*/*(其它的数据类型,包括 json格式的字符) 为 0.8 稍微低一点。
  1. 参数format是规定好的,在开启请求参数的内容协商功能后,SpringBoot底层 ParameterContentNegotiationStrategy 会通过 format 来接收参数,然后返回对应的媒体类型/数据格式,当然format=xxx,这个xxx媒体类型/数据格式是SpringBoot可以
    处理的才行,不能乱写。也注意是英文的 ?
  2. 我们自己指定一个内容协商的参数名,修改掉了默认的 format 的参数了,就不再是默认的 format而是,rainbowsea=json ,默认的(format 就不可以再用了,已经失效了)失效了。

6. 最后:

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

在这里插入图片描述


http://www.ppmy.cn/news/1527581.html

相关文章

微信小程序中的模块化、组件化开发:完整指南

文章目录 前言一、模块化与组件化开发的优势1.1模块化开发的优势1.2 组件化开发的优势 二、组件的抽离标准及规范2.1 抽离组件的标准2.2 组件化开发规范 三、模块化规范的种类及优劣比较3.1 CommonJS3.2 ES6 Modules3.3 优劣对比 四、组件封装&#xff1a;全局组件、分包组件、…

PCIe扫盲(六)

系列文章目录 PCIe扫盲&#xff08;一&#xff09; PCIe扫盲&#xff08;二&#xff09; PCIe扫盲&#xff08;三&#xff09; PCIe扫盲&#xff08;四&#xff09; PCIe扫盲&#xff08;五&#xff09; PCIe扫盲&#xff08;六&#xff09; 文章目录 系列文章目录Flow Control…

【PHP】使用thinkphp5查询最大值时,把varchar类型字段转换成数字

有时候我们需要把carchar类型的字段进行聚合函数运运行&#xff08;max、min、avg&#xff09;&#xff0c;但是如果直接用聚合函数&#xff0c;得到的结果是错误的&#xff0c;因为varchar字段是字符串&#xff0c;无法直接使用聚合函数&#xff0c;所以需要把varchar字段转换…

apach httpd多后缀解析漏洞

漏洞详情&#xff1a; httpd支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。 那么&#xff0c;在有多个后缀的情况下&#xff0c;只要一个文件含有.php后缀的文件即将被识别成PHP文件&#xff0c;没必要是最后一个后缀。 利用这个特性&#xff0c;可以绕过…

[Linux]从零开始的泰山派系统安装与远程教程

一、前言 泰山派买回来也有一阵子了&#xff0c;最近慢慢开始研究。当然&#xff0c;学习这种Linux的开发板的第一步就是安装系统&#xff0c;对于RK系列的芯片系统安装有专门的软件&#xff0c;所有在系统安装方面比较简单。更多的还是我们应该怎么去编译系统&#xff0c;这一…

激光粉尘传感器:筑牢粮仓安全防线,有效应对粮食粉尘爆炸高危风险

随着我国农业的持续发展和粮食产量的稳步提升&#xff0c;2023年全国粮食总产量达到了13908.2亿斤&#xff0c;这一丰硕成果不仅保障了国家的粮食安全&#xff0c;也对粮食的储备、加工、运输等环节提出了更高的要求。然而&#xff0c;在粮食产业链的各个环节中&#xff0c;粮食…

[模板]树的最长路径

[模板]树的最长路径 题目描述 给定一棵树&#xff0c;树中包含 n 个结点&#xff08;编号1~n&#xff09;和 n-1 条无向边&#xff0c;每条边都有一个权值。 现在请你找到树中的一条最长路径。 换句话说&#xff0c;要找到一条路径&#xff0c;使得使得路径两端的点的距离最远…

Day04_JVM实战

文章目录 一、gc日志和dump快照GC日志是什么,要怎么看?dump快照是什么?要怎么看?二、gc日志和dump快照实战java.lang.OutOfMemoryError:Java heap space1、gc.log怎么看2、heapdump.hprof怎么看?①jvisualvm查看②使用MAT查看java.lang.OutOfMemoryError:Metaspace1、实时…