如何在ftp给网站做百度自动推送超云seo优化
文章目录
- 自定义转换器
- 基本介绍
- 应用实例
- 查看源码
- 注意事项和细节
- 处理JSON
- 需求说明
- 应用实例
- 内容协商
- 基本介绍
- 应用实例
- debug源码
- 优先返回xml
- 注意事项和细节

⬅️ 上一篇: springboot系列九: 接收参数相关注解
🎉 欢迎来到 springboot系列十: 自定义转换器,处理JSON,内容协商 🎉
在本篇文章中,我们将探讨如何在 Spring Boot 中实现自定义转换器、处理 JSON 数据以及进行内容协商。通过掌握这些技术,您可以更灵活地处理不同格式的数据,提高应用程序的兼容性和用户体验。
🔧 本篇需要用到的项目:
自定义转换器
基本介绍
1.SpringBoot在响应客户端请求时, 将提交的数据封装成对象时, 使用了内置转换器
2.SpringBoot也支持自定义转换器, 这个内置转换器在debug的时候, 可以看到, 提供了124个内置转换器, 看下源码. GenericConverter类-ConvertiblePair(内部类)

]
应用实例
需求说明: 演示自定义转换器使用
1.修改save.html
<!--使用自定义转换器关联car, 字符串整体提交, 使用,号间隔-->
坐骑: <input name="name" value="碧水金睛兽,666.6"><br/
2.创建src/main/java/com/zzw/springboot/config/WebConfig.java, 增加自定义转换器
springboot系列四: sprintboot容器功能
/*** @Configuration(proxyBeanMethods = false)* 1.表示 WebConfig 是一个配置类* 2.proxyBeanMethods = false 表示使用Lite模式*/
@Configuration(proxyBeanMethods = false)
public class WebConfig {//注入bean WebMvcConfiger@Beanpublic WebMvcConfigurer webMvcConfigurer() {//整个是WebMvcConfigurer接口的匿名内部类return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解读* 1.在addFormatters方法中, 增加一个自定义转换器* 2.增加自定义转换器 String -> Car* 3.增加的自定义转换器会注册到 converters 容器中* 4.converters 底层结构是 ConcurrentHashMap, 内置有124个转换器[不同版本个数不一样~]* 5.一会我们debug查看这些转换器*/registry.addConverter(new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}});}};}
}
3.测试
monster = Monster(id=100, name=张三, age=30, maritalStatus=false, birthday=Sat Jan 01 00:00:00 CST 1994, car=Car(vehicleName=碧水金睛兽, vehiclePrice=666.6))
查看源码
1.debug, 可以看到我们新增的Converter


快捷键查看有多少元素



注意事项和细节
1.注册转换器换种写法, 方便理解
/*** @Configuration(proxyBeanMethods = false)* 1.表示 WebConfig 是一个配置类* 2.proxyBeanMethods = false 表示使用Lite模式*/
@Configuration(proxyBeanMethods = false)
public class WebConfig {//注入bean WebMvcConfiger@Beanpublic WebMvcConfigurer webMvcConfigurer() {//整个是WebMvcConfigurer接口的匿名内部类return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解读* 1.在addFormatters方法中, 增加一个自定义转换器* 2.增加自定义转换器 String -> Car* 3.增加的自定义转换器会注册到 converters 容器中* 4.converters 底层结构是 ConcurrentHashMap, 内置有124个转换器[不同版本个数不一样~]* 5.一会我们debug查看这些转换器*//*registry.addConverter(new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}});*///换种写法注册自定义转换器, 方便理解//1.先创建一个自定义的转换器Converter<String, Car> zzwConverter = new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}};//添加转换器到converters容器registry.addConverter(zzwConverter);//还可以增加更多的转换器....}};}
}
2.假如我们不添加自定义转换器, 会报typeMismatch错误, 报400错误. 而400错误是客户端的错误, 请求包含语法错误.
JavaWeb系列八: WEB 开发通信协议(HTTP协议)

3.创建两个自定义转换器
/*** @Configuration(proxyBeanMethods = false)* 1.表示 WebConfig 是一个配置类* 2.proxyBeanMethods = false 表示使用Lite模式*/
@Configuration(proxyBeanMethods = false)
public class WebConfig {//注入bean WebMvcConfiger@Beanpublic WebMvcConfigurer webMvcConfigurer() {//整个是WebMvcConfigurer接口的匿名内部类return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解读* 1.在addFormatters方法中, 增加一个自定义转换器* 2.增加自定义转换器 String -> Car* 3.增加的自定义转换器会注册到 converters 容器中* 4.converters 底层结构是 ConcurrentHashMap, 内置有124个转换器[不同版本个数不一样~]* 5.一会我们debug查看这些转换器*//*registry.addConverter(new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}});*///换种写法注册自定义转换器, 方便理解//1.先创建一个自定义的转换器Converter<String, Car> zzwConverter = new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}};//还可以增加更多的转换器....//第2个自定义的转换器Converter<String, Monster> zzwConverter2 = new Converter<String, Monster>() {@Overridepublic Monster convert(String source) {return null;}};//添加转换器到converters容器registry.addConverter(zzwConverter);registry.addConverter(zzwConverter2);}};}
}
debug, 看一看 converters容器 是不是变成了 126 个.


4.创建三个自定义转换器, 由于key是[源类型->目标类型], 所以会覆盖掉一个.
//1.先创建一个自定义的转换器
Converter<String, Car> zzwConverter = new Converter<String, Car>() {//传入Converter接口的匿名内部类@Overridepublic Car convert(String source) {//source就是 传入的字符串 碧水金睛兽,666.6//这里加入自定义的转换业务代码if (!ObjectUtils.isEmpty(source)) {String[] split = source.split(",");Car car = new Car();car.setVehicleName(split[0]);car.setVehiclePrice(Double.parseDouble(split[1]));return car;}return null;}
};//还可以增加更多的转换器....
//第2个自定义的转换器
Converter<String, Monster> zzwConverter2 = new Converter<String, Monster>() {@Overridepublic Monster convert(String source) {return null;}
};
//第3个自定义的转换器
Converter<String, Car> zzwConverter3 = new Converter<String, Car>() {@Overridepublic Car convert(String source) {return null;}
};//添加转换器到converters容器
registry.addConverter(zzwConverter);
registry.addConverter(zzwConverter2);
registry.addConverter(zzwConverter3);
1)测试, 是否覆盖.


2)查看 converters 容器. 因为第三个转换器和第一个转换器 key 是相同的, 所以覆盖掉了.

处理JSON
需求说明
演示返回JSON格式的数据
应用实例
1.SpringBoot 支持返回 JSON 格式数据, 在启用WEB开发场景时, 已经引入了相关依赖.
springboot系列二: sprintboot依赖管理


2.新建src/main/java/com/zzw/springboot/controller/ResponseController.java
@Controller
public class ResponseController {//编写方法, 返回monster数据 要求以json格式返回@GetMapping(value = "/getMonster")@ResponseBodypublic Monster getMonster() {//说明//开发中 monster对象是从db获取,这里我们模拟一个mosnter对象Monster monster = new Monster();monster.setId(100);monster.setName("张三");monster.setAge(18);monster.setBirthday(new Date());monster.setMaritalStatus(false);Car car = new Car();car.setVehicleName("奔驰");car.setVehiclePrice(100000.0);monster.setCar(car);return monster;}
}
3.Postman测试.

4.Debug一下 monster对象如何以Json格式返回.
浏览器/Postman 请求, 第一个断点

第二个断点, 找到 AbstractJackson2HttpMessageConverter.class


用工厂模式创建了个 generator.

generator是 UTF8JsonGenerator

object 就是 monster对象

这条语句一旦执行完毕, 浏览器就拿到数据.

内容协商
基本介绍
1.根据客户端接收能力不同, SpringBoot返回不同媒体类型的数据.
JavaWeb系列八: WEB 开发通信协议(HTTP协议)
2.比如:
客户端Http请求, 携带 Accept aaplication/xml 请求头, 要求服务端返回xml数据;
客户端Http请求, 携带 Accept aaplication/json 请求头, 则要求服务端返回json数据
3.效果如下
如果Accept, 我设置的是 application/json, 那么返回的数据就是 json 格式.

如果Accept, 我设置的是 application/xml, 那么返回的数据就是 xml 格式.

应用实例
需求说明: 使用Postman发送Http请求, 根据请求头不同, 返回对应的json数据, 或者xml数据, 如图

注意: Accept: */* 默认返回 json 格式

在底层,generator生成的是xml格式的, 但是在进行转换的时候, 需要有一个jar包的依赖.
<!--引入处理xml的依赖-->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.12.4</version>
</dependency>
debug源码
Postman切换不同的Accept类型, 来Debug源码, 看看对应的JsonGenerator类型
1,返回json类型

靠contentType进行内容协商


2.返回xml类型



优先返回xml
加入xml依赖以后, 使用浏览器请求,为什么会返回xml数据, 而不是json?
分析
(1)浏览器请求后, 后端接收到的contentType值是 application/xhtml+xml, 为什么?
(2)因为请求头信息, 如下
1.Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
2.application/xhtml+xml 的权重比较高0.9, 后面的类型, 包括 */* 的权重是 0.8



注意事项和细节
1.Postman可以通过修改Accept的值, 来访会不同的数据格式.
2.对于浏览器, 我们无法修改其Accept的值, 怎么办? 解决方案: 开启基于请求参数的内容协商功能.
1)修改application.yml, 开启基于请求参数的内容协商功能.
spring:mvc:contentnegotiation:favor-parameter: true #开启基于请求参数的内容协商功能

2)浏览器测试

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

4)修改parameterName
spring:mvc:contentnegotiation:favor-parameter: true #开启基于请求参数的内容协商功能parameter-name: helloFormat #指定一个内容协商的参数名
5)测试

🔜 下一篇预告: [即将更新,敬请期待]
📚 目录导航 📚
- springboot系列一: springboot初步入门
- springboot系列二: sprintboot依赖管理
- springboot系列三: sprintboot自动配置
- springboot系列四: sprintboot容器功能
- springboot系列五: springboot底层机制实现 上
- springboot系列六: springboot底层机制实现 下
- springboot系列七: Lombok注解,Spring Initializr,yaml语法
- springboot系列八: springboot静态资源访问,Rest风格请求处理
- springboot系列九: 接收参数相关注解
- springboot系列十: 自定义转换器,处理JSON,内容协商
💬 读者互动 💬
在学习 Spring Boot 自定义转换器、处理 JSON 及内容协商的过程中,您有哪些新的发现或疑问?欢迎在评论区留言,让我们一起讨论吧!😊
