Spring Boot中HTTP請求參數(shù)轉(zhuǎn)換和請求體JSON反序列化的區(qū)別解析
Spring Boot中HTTP請求參數(shù)轉(zhuǎn)換和請求體JSON反序列化的區(qū)別
問題
假設如下方法和對象
@Operation(summary = "新增或修改標簽信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateLabel(@RequestBody LabelInfo labelInfo) {
service.saveOrUpdate(labelInfo);
return Result.ok();
}
@Schema(description = "標簽信息表")
@TableName(value = "label_info")
@Data
public class LabelInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@Schema(description = "類型")
@TableField(value = "type")
private ItemType type;
@Schema(description = "標簽名稱")
@TableField(value = "name")
private String name;
}
@Getter
@AllArgsConstructor
public enum ItemType implements BaseEnum {
APARTMENT(1, "公寓"),
ROOM(2, "房間");
@EnumValue
@JsonValue
private Integer code;
private String name;
}在saveOrUpdateLabel方法中,如果不對ItemType對象的code變量添加@JsonValue注解,若前端發(fā)送{ "type": "2", "name": "兩室一廳" }會報錯
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.sense.lease.model.enums.ItemType` from String "2": not one of the values accepted for Enum class: [APARTMENT, ROOM]]
此時ItemType的反序列化流程是什么樣的?以及為什么是通過Jackson的@JsonValue實現(xiàn)反序列化而不是WebDataBinder的Converter?
1. 兩種不同的轉(zhuǎn)換場景
首先,我們需要區(qū)分兩種不同的轉(zhuǎn)換場景:
- HTTP請求參數(shù)轉(zhuǎn)換:
- 場景:URL查詢參數(shù)或表單數(shù)據(jù),如
?type=2 - 處理器:Spring MVC的
WebDataBinder和Converter接口 - 轉(zhuǎn)換方向:String → Java對象
- 場景:URL查詢參數(shù)或表單數(shù)據(jù),如
- JSON反序列化:
- 場景:請求體中的JSON數(shù)據(jù),如
{"type": "2", "name": "兩室一廳"} - 處理器:Jackson庫的
ObjectMapper - 轉(zhuǎn)換方向:JSON字符串 → Java對象
- 場景:請求體中的JSON數(shù)據(jù),如
2. JSON反序列化流程詳解
當Spring Boot接收到包含JSON的請求體時,會發(fā)生以下過程:
HTTP請求到達:
POST /admin/label/saveOrUpdate
Content-Type: application/json
{
"type": "2",
"name": "兩室一廳"
}- Jackson處理JSON:
- Spring Boot使用Jackson的
ObjectMapper來解析JSON - 當遇到
"type": "2"時,Jackson需要將其轉(zhuǎn)換為ItemType枚舉
- Spring Boot使用Jackson的
- 默認枚舉反序列化:
- Jackson默認使用枚舉的名稱進行反序列化
- 它會嘗試匹配"2"與枚舉常量名稱:[APARTMENT, ROOM]
- 由于沒有名為"2"的枚舉常量,所以拋出異常
3. @JsonValue注解的作用
@JsonValue注解告訴Jackson在進行序列化和反序列化時,應該使用哪個字段作為枚舉的值:
public enum ItemType implements BaseEnum {
APARTMENT(1, "公寓"),
ROOM(2, "房間");
@EnumValue // MyBatis-Plus使用此注解確定存儲到數(shù)據(jù)庫的值
@JsonValue // Jackson使用此注解確定序列化/反序列化的值
private Integer code;
// ...
}當添加了@JsonValue注解后:
- 序列化:將
ItemType.ROOM轉(zhuǎn)換為JSON時,輸出2而不是"ROOM" - 反序列化:將JSON中的字符串
"2"或者數(shù)字2轉(zhuǎn)換為ItemType.ROOM對象
4. 為什么Converter不適用于JSON反序列化
Converter接口(如StringToItemTypeConverter)是為Spring MVC的WebDataBinder設計的,專門用于處理HTTP請求參數(shù)的轉(zhuǎn)換,而不是JSON數(shù)據(jù)的反序列化。
兩者的工作層面不同:
- Converter:
- 工作在Spring MVC層面
- 處理HTTP請求參數(shù)(查詢參數(shù)、表單數(shù)據(jù))
- 在控制器方法參數(shù)綁定之前執(zhí)行
- Jackson的反序列化:
- 工作在JSON處理層面
- 處理請求體中的JSON數(shù)據(jù)
- 在控制器方法參數(shù)綁定之前執(zhí)行,但獨立于Spring MVC的轉(zhuǎn)換機制
5. 驗證這個區(qū)別
可以通過以下方式驗證這個區(qū)別:
測試請求參數(shù)(使用Converter):
GET /admin/label/list?type=2
這個請求會使用StringToItemTypeConverter進行轉(zhuǎn)換
測試JSON請求體(使用@JsonValue):
POST /admin/label/saveOrUpdate
Content-Type: application/json
{
"type": "2",
"name": "兩室一廳"
}這個請求會使用Jackson的反序列化機制,依賴于@JsonValue注解
6. 替代方案:@JsonCreator注解
除了使用@JsonValue,您還可以使用@JsonCreator注解提供自定義的反序列化方法:
// @JsonCreator注解指定自定義反序列化方法,靜態(tài)工廠函數(shù),根據(jù)code屬性值返回對應的枚舉對象實例
// 參數(shù)類型需與Json數(shù)據(jù)中code屬性的數(shù)據(jù)類型一致,或者聲明為Object類型,否則無法將json數(shù)據(jù)與參數(shù)綁定
// 參數(shù)名可直接使用Json數(shù)據(jù)中的屬性名,否則需使用@JsonProperty注解指定屬性名。
@JsonCreator
public static ItemType forValue(@JsonProperty("code") String c) {
for (ItemType type : ItemType.values()) {
if (type.getCode().equals(Integer.valueOf(c))) {
return type;
}
}
throw new IllegalArgumentException("code: " + c + "非法");
}優(yōu)點:靈活,可進行額外的處理流程
缺點:
- 繁瑣,需要為每個枚舉類單獨實現(xiàn)
- 需要注意參數(shù)的變量類型和變量名與JSON數(shù)據(jù)是否對應,否則無法觸發(fā);而
@JsonValue注解時,JSON數(shù)據(jù)既可以是字符串也可以是數(shù)字
總結(jié)
- HTTP請求參數(shù)轉(zhuǎn)換:使用
Converter接口,由Spring MVC的WebDataBinder處理 - JSON反序列化:使用Jackson的機制,依賴于
@JsonValue或@JsonCreator注解,不僅是請求體中的JSON數(shù)據(jù)反序列化,任何時候涉及到JSON數(shù)據(jù)反序列化,只要使用的是Spring Boot默認的ObejctMapper或配置了相同Jackson設置的ObejctMapper,相關注解都會生效。 - 兩者是獨立的機制,解決不同場景下的類型轉(zhuǎn)換問題
- 為了完整支持兩種場景,需要同時提供
Converter和適當?shù)腏ackson注解
到此這篇關于Spring Boot中HTTP請求參數(shù)轉(zhuǎn)換和請求體JSON反序列化的區(qū)別的文章就介紹到這了,更多相關Java線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- SpringBoot項目中HTTP請求對響應體進行壓縮的方法
- 基于SpringBoot實現(xiàn)HTTP請求簽名驗證機制
- SpringBoot使用OkHttp完成高效網(wǎng)絡請求詳解
- SpringBoot中HTTP請求不通的原因級解決方法
- SpringBoot使用RestTemplate如何通過http請求將文件下載到本地
- springboot配置請求超時時間(Http會話和接口訪問)
- SpringBoot中如何打印Http請求日志
- SpringBoot處理HTTP請求的詳細流程
- SpringBoot中fastjson自定義序列化和反序列化的實戰(zhàn)分享
- SpringBoot之Json的序列化和反序列化問題
- SpringBoot Redis配置Fastjson進行序列化和反序列化實現(xiàn)
相關文章
IDEA設置maven修改settings.xml配置文件無法加載倉庫的解決方案
這篇文章主要介紹了IDEA設置maven修改settings.xml配置文件無法加載倉庫的解決方案,幫助大家更好的利用IDEA進行JAVA的開發(fā)學習,感興趣的朋友可以了解下2021-01-01
Java集合框架實戰(zhàn)HashMap與HashSet的使用案例
本文通過兩個案例詳細介紹了HashMap和HashSet在Java中的應用,通過這些案例,我們學習了如何選擇合適的集合類型、重寫equals和hashCode方法、利用泛型和并發(fā)集合等最佳實踐,感興趣的朋友跟隨小編一起看看吧2025-11-11
SpringBoot多模塊打包部署Docker的項目實戰(zhàn)
本文通過介紹最常見的Maven管理的Spring Boot項目多模塊打包部署Docker來介紹一下項目部署過程中操作流程和幾個需要注意的點,具有一定的參加價值,感興趣的可以了解一下2023-08-08
spring boot異步(Async)任務調(diào)度實現(xiàn)方法
在沒有使用spring boot之前,我們的做法是在配置文件中定義一個任務池,然后將@Async注解的任務丟到任務池中去執(zhí)行,那么在spring boot中,怎么來實現(xiàn)異步任務的調(diào)用了,下面通過本文給大家講解,需要的朋友參考下2018-02-02
Java Swing JCheckBox復選框的實現(xiàn)方法
這篇文章主要介紹了Java Swing JCheckBox復選框的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12
springCloud gateWay 統(tǒng)一鑒權(quán)的實現(xiàn)代碼
這篇文章主要介紹了springCloud gateWay 統(tǒng)一鑒權(quán)的實現(xiàn)代碼,統(tǒng)一鑒權(quán)包括鑒權(quán)邏輯和代碼實現(xiàn),本文給大家介紹的非常詳細,需要的朋友可以參考下2022-02-02

