找人做ps的網(wǎng)站廈門人才網(wǎng)唯一官方網(wǎng)站
文章目錄
- 自定義轉換器
- 基本介紹
- 應用實例
- 查看源碼
- 注意事項和細節(jié)
- 處理JSON
- 需求說明
- 應用實例
- 內(nèi)容協(xié)商
- 基本介紹
- 應用實例
- debug源碼
- 優(yōu)先返回xml
- 注意事項和細節(jié)
?? 上一篇: springboot系列九: 接收參數(shù)相關注解
🎉 歡迎來到 springboot系列十: 自定義轉換器,處理JSON,內(nèi)容協(xié)商 🎉
在本篇文章中,我們將探討如何在 Spring Boot 中實現(xiàn)自定義轉換器、處理 JSON 數(shù)據(jù)以及進行內(nèi)容協(xié)商。通過掌握這些技術,您可以更靈活地處理不同格式的數(shù)據(jù),提高應用程序的兼容性和用戶體驗。
🔧 本篇需要用到的項目:
自定義轉換器
基本介紹
1.SpringBoot在響應客戶端請求時, 將提交的數(shù)據(jù)封裝成對象時, 使用了內(nèi)置轉換器
2.SpringBoot也支持自定義轉換器, 這個內(nèi)置轉換器在debug
的時候, 可以看到, 提供了124
個內(nèi)置轉換器, 看下源碼. GenericConverter類-ConvertiblePair(內(nèi)部類)
]
應用實例
需求說明: 演示自定義轉換器使用
1.修改save.html
<!--使用自定義轉換器關聯(lián)car, 字符串整體提交, 使用,號間隔-->
坐騎: <input name="name" value="碧水金睛獸,666.6"><br/
2.創(chuàng)建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接口的匿名內(nèi)部類return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解讀* 1.在addFormatters方法中, 增加一個自定義轉換器* 2.增加自定義轉換器 String -> Car* 3.增加的自定義轉換器會注冊到 converters 容器中* 4.converters 底層結構是 ConcurrentHashMap, 內(nèi)置有124個轉換器[不同版本個數(shù)不一樣~]* 5.一會我們debug查看這些轉換器*/registry.addConverter(new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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
快捷鍵查看有多少元素
注意事項和細節(jié)
1.注冊轉換器換種寫法, 方便理解
/*** @Configuration(proxyBeanMethods = false)* 1.表示 WebConfig 是一個配置類* 2.proxyBeanMethods = false 表示使用Lite模式*/
@Configuration(proxyBeanMethods = false)
public class WebConfig {//注入bean WebMvcConfiger@Beanpublic WebMvcConfigurer webMvcConfigurer() {//整個是WebMvcConfigurer接口的匿名內(nèi)部類return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解讀* 1.在addFormatters方法中, 增加一個自定義轉換器* 2.增加自定義轉換器 String -> Car* 3.增加的自定義轉換器會注冊到 converters 容器中* 4.converters 底層結構是 ConcurrentHashMap, 內(nèi)置有124個轉換器[不同版本個數(shù)不一樣~]* 5.一會我們debug查看這些轉換器*//*registry.addConverter(new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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.先創(chuàng)建一個自定義的轉換器Converter<String, Car> zzwConverter = new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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 開發(fā)通信協(xié)議(HTTP協(xié)議)
3.創(chuàng)建兩個自定義轉換器
/*** @Configuration(proxyBeanMethods = false)* 1.表示 WebConfig 是一個配置類* 2.proxyBeanMethods = false 表示使用Lite模式*/
@Configuration(proxyBeanMethods = false)
public class WebConfig {//注入bean WebMvcConfiger@Beanpublic WebMvcConfigurer webMvcConfigurer() {//整個是WebMvcConfigurer接口的匿名內(nèi)部類return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 解讀* 1.在addFormatters方法中, 增加一個自定義轉換器* 2.增加自定義轉換器 String -> Car* 3.增加的自定義轉換器會注冊到 converters 容器中* 4.converters 底層結構是 ConcurrentHashMap, 內(nèi)置有124個轉換器[不同版本個數(shù)不一樣~]* 5.一會我們debug查看這些轉換器*//*registry.addConverter(new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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.先創(chuàng)建一個自定義的轉換器Converter<String, Car> zzwConverter = new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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.創(chuàng)建三個自定義轉換器, 由于key是[源類型->目標類型], 所以會覆蓋掉一個.
//1.先創(chuàng)建一個自定義的轉換器
Converter<String, Car> zzwConverter = new Converter<String, Car>() {//傳入Converter接口的匿名內(nèi)部類@Overridepublic Car convert(String source) {//source就是 傳入的字符串 碧水金睛獸,666.6//這里加入自定義的轉換業(yè)務代碼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格式的數(shù)據(jù)
應用實例
1.SpringBoot
支持返回 JSON
格式數(shù)據(jù), 在啟用WEB
開發(fā)場景時, 已經(jīng)引入了相關依賴.
springboot系列二: sprintboot依賴管理
2.新建src/main/java/com/zzw/springboot/controller/ResponseController.java
@Controller
public class ResponseController {//編寫方法, 返回monster數(shù)據(jù) 要求以json格式返回@GetMapping(value = "/getMonster")@ResponseBodypublic Monster getMonster() {//說明//開發(fā)中 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
用工廠模式創(chuàng)建了個 generator.
generator
是 UTF8JsonGenerator
object
就是 monster對象
這條語句一旦執(zhí)行完畢, 瀏覽器就拿到數(shù)據(jù).
內(nèi)容協(xié)商
基本介紹
1.根據(jù)客戶端接收能力不同, SpringBoot返回不同媒體類型的數(shù)據(jù).
JavaWeb系列八: WEB 開發(fā)通信協(xié)議(HTTP協(xié)議)
2.比如:
客戶端Http
請求, 攜帶 Accept aaplication/xml
請求頭, 要求服務端返回xml
數(shù)據(jù);
客戶端Http
請求, 攜帶 Accept aaplication/json
請求頭, 則要求服務端返回json
數(shù)據(jù)
3.效果如下
如果Accept
, 我設置的是 application/json
, 那么返回的數(shù)據(jù)就是 json
格式.
如果Accept
, 我設置的是 application/xml
, 那么返回的數(shù)據(jù)就是 xml
格式.
應用實例
需求說明: 使用Postman
發(fā)送Http
請求, 根據(jù)請求頭不同, 返回對應的json
數(shù)據(jù), 或者xml
數(shù)據(jù), 如圖
注意: 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
進行內(nèi)容協(xié)商
2.返回xml
類型
優(yōu)先返回xml
加入xml
依賴以后, 使用瀏覽器請求,為什么會返回xml
數(shù)據(jù), 而不是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
注意事項和細節(jié)
1.Postman
可以通過修改Accept
的值, 來訪會不同的數(shù)據(jù)格式.
2.對于瀏覽器, 我們無法修改其Accept
的值, 怎么辦? 解決方案: 開啟基于請求參數(shù)的內(nèi)容協(xié)商功能.
1)修改application.yml
, 開啟基于請求參數(shù)的內(nèi)容協(xié)商功能.
spring:mvc:contentnegotiation:favor-parameter: true #開啟基于請求參數(shù)的內(nèi)容協(xié)商功能
2)瀏覽器測試
3)注意, 參數(shù)format
是規(guī)定好的, 在開啟請求參數(shù)的內(nèi)容協(xié)商功能后, SpringBoot
底層ParameterContentNegotiationStrategy
會通過format
來接收參數(shù), 然后返回對應的媒體類型/數(shù)據(jù)格式
, 當然format=xx
這個xx
媒體類型/數(shù)據(jù)格式 是SpringBoot
可以處理的才行, 不能亂寫.
4)修改parameterName
spring:mvc:contentnegotiation:favor-parameter: true #開啟基于請求參數(shù)的內(nèi)容協(xié)商功能parameter-name: helloFormat #指定一個內(nèi)容協(xié)商的參數(shù)名
5)測試
🔜 下一篇預告: [即將更新,敬請期待]
📚 目錄導航 📚
- springboot系列一: springboot初步入門
- springboot系列二: sprintboot依賴管理
- springboot系列三: sprintboot自動配置
- springboot系列四: sprintboot容器功能
- springboot系列五: springboot底層機制實現(xiàn) 上
- springboot系列六: springboot底層機制實現(xiàn) 下
- springboot系列七: Lombok注解,Spring Initializr,yaml語法
- springboot系列八: springboot靜態(tài)資源訪問,Rest風格請求處理
- springboot系列九: 接收參數(shù)相關注解
- springboot系列十: 自定義轉換器,處理JSON,內(nèi)容協(xié)商
💬 讀者互動 💬
在學習 Spring Boot 自定義轉換器、處理 JSON 及內(nèi)容協(xié)商的過程中,您有哪些新的發(fā)現(xiàn)或疑問?歡迎在評論區(qū)留言,讓我們一起討論吧!😊