十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)
十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)
@
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博客

package com.rainbowsea.bean;
import lombok.Data;
@Data
public class Car {
private String name;
private Double price;
}
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 控制器,处理相关的请求路径映射

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")
@ResponseBody
public 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;
}
}
项目的/应用程序的启动场景

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 依赖当中包含了 json 数据格式的
jar依赖。
而没有 xml 的数据格式的
jar依赖,自然就是优先为 json 你有的数据格式的jar依赖为准了。我们可以 Debug 看看。
我们在 AbstractJackson2HttpMessageConverter.java 类当中的
writeInternal()的方法当中打上 断点。
直到走到这里,我们查看 generator的值:发现是 JSON。这就没错了,我们仅仅是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. 内容协商:注意事项和使用细节
- Postman 可以通过修改 Accept 的值,来返回不同的数据格式。感兴趣的大家可以自行去下载,试试。官网地址:https://www.postman.com/

对于浏览器,我们无法修改其 Accept的值,怎么办?解决方案:开启支持基于请求参数的内容协商功能
修改
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可以
处理的才行,不能乱写。 也注意是英文的?


其实这个
format的值是:ParameterContentNegotiationStrategy 类当中的 parameterName 属性值。
这个我们也可以修改这个值,指定一个内容协商的参数名,就不再是默认的 format而是我们自己定义的一个参数名了。
还是在
application.yaml文件当中配置,增加上一个属性。这里我们指定**内容协商的参数名为,
rainbowsea。
spring:
mvc:
contentnegotiation:
favor-parameter: true # 开启基于请求参数的内容协商功能
#?format=json
parameter-name: rainbowsea # 指定一个内容协商的参数名,就不再是默认的 format而是
# ?rainbowsea=json ,默认的失效了
重新启动程序,浏览器运行测试:
需要注意的是: 我们自己指定一个内容协商的参数名,修改掉了默认的 format 的参数了,就不再是默认的 format而是,rainbowsea=json ,默认的(format 就不可以再用了,已经失效了)失效了。
默认的 format 已经失效了, 无论我们配置=json,还是 xml ,都返回的是 xml 格式类型的数据
。因为 xml 优先级是0.9 比较高的,所以返回的就是默认优先级高的 xml 的格式的了。
5. 总结:
内容协商就是:根据客户端接收能力不同,SpringBoot返回不同媒体类型的数据。
比如:客户端 Http请求
Accept:application/xml则返回xml数据,客户端 Http 请求Accept:application/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 稍微低一点。
- 参数format是规定好的,在开启请求参数的内容协商功能后,SpringBoot底层 ParameterContentNegotiationStrategy 会通过 format 来接收参数,然后返回对应的媒体类型/数据格式,当然format=xxx,这个xxx媒体类型/数据格式是SpringBoot可以
处理的才行,不能乱写。也注意是英文的? - 我们自己指定一个内容协商的参数名,修改掉了默认的 format 的参数了,就不再是默认的 format而是,rainbowsea=json ,默认的(format 就不可以再用了,已经失效了)失效了。
6. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)的更多相关文章
- 07.深入浅出 Spring Boot - 数据访问之Mybatis(附代码下载)
MyBatis 在Spring Boot应用非常广,非常强大的一个半自动的ORM框架. 代码下载:https://github.com/Jackson0714/study-spring-boot.gi ...
- Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源
多数据源配置也算是一个常见的开发需求,Spring 和 SpringBoot 中,对此都有相应的解决方案,不过一般来说,如果有多数据源的需求,我还是建议首选分布式数据库中间件 MyCat 去解决相关问 ...
- 【转】Spring Boot 日志配置(超详细)
更新日志: 20170810 更新通过 application.yml传递参数到 logback 中. [toc] 简书不支持目录,截图一张. image.png 默认日志 Logback: 默认情况 ...
- Spring Boot2 系列教程(三十)Spring Boot 整合 Ehcache
用惯了 Redis ,很多人已经忘记了还有另一个缓存方案 Ehcache ,是的,在 Redis 一统江湖的时代,Ehcache 渐渐有点没落了,不过,我们还是有必要了解下 Ehcache ,在有的场 ...
- Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker
今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...
- 花时三月 终于Spring Boot 微信点餐开源系统! 附源码
架构 前后端分离: Nginx与Tomcat的关系在这篇文章,几分钟可以快速了解: https://www.jianshu.com/p/22dcb7ef9172 补充: set ...
- spring boot 常见三十四问
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...
- Spring Boot面试题
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...
- spring boot常见问题
1.什么是springboot 用来简化spring应用的初始搭建以及开发过程 使用特定的方式来进行配置(properties或yml文件) 创建独立的spring引用程序 main方法运行 嵌入的T ...
- Spring Boot基础知识
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...
随机推荐
- 【干货】顶级 Java 源码教程项目大汇总!
大家好,我是鱼皮,今天分享几个 GitHub 上顶级的 Java 源码教程项目. 区别于书籍.文档.视频等形式的教程,这些项目几乎都是由 精简的代码片段 和 Demo 组成的,能够轻松地在本地执行,非 ...
- PHP7新特性之类型声明
今天我在这里总结下PHP7主要的新特性. 1.类型声明 做过php开发的小伙伴们都知道,php7以前的版本变量是不需要声明类型的,函数返回值也是不需要声明类型的,总之,在我们的脑海中就没有这么回事.可 ...
- PointNet笔记
可能遇到的问题 在windows上运行pointnet的代码时,可能会遇到一些问题: 1.比如提示OSError: no file with expected extension, 这是因为可视化的s ...
- JDBC第二天:防sql攻击
1 什么是SQL攻击 在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语 ...
- Vue 修改网页标题和图标
Vue 修改网页标题和图标 by:授客 QQ:1033553122 开发环境 Win 10 Vue 2.5.2 需求描述 如下,想更改网页的标题和图标 解决方法 编辑项目根目录下的in ...
- 空间反演对称性 (Spatial Inversion Symmetry) 和非线性响应 (Non-linear Response)
我们定义一次宇称变换 (parity transformation) 为反转所有坐标: \[\mathcal{P}: \begin{pmatrix} x \\ y \\ z \end{pmatrix} ...
- .NET 权限工作流框架 TOP 榜
前言 .NET权限管理及快速开发框架.最好用的权限工作流系统. 基于经典领域驱动设计的权限管理及快速开发框架,源于Martin Fowler企业级应用开发思想及最新技术组合(SqlSugar.EF.Q ...
- 【FastDFS】环境搭建 01 跟踪器和存储节点
FastDFS:分布式文件系统 它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题. 特别适合以文件为载体的在线服务,如相册网站.视频网 ...
- AI的发展需要有应用和落地场景 —— 李开复:传统公司看不懂技术,大模型落地B端阻碍多
引自:https://baijiahao.baidu.com/s?id=1801826206644007472&wfr=spider&for=pc "我们投了七八家机器人企业 ...
- OneFlow计算框架的OneAgent是不是一个子虚乌有的东西?
自己是搞强化学习的,今天看了些OneFlow计算框架的一些资料,发现OneFlow官方一直有宣传自己的强化学习框架--OneAgent,但是十分诡异的是从了OneFlow的官方宣传可以看到这个词,但是 ...








