一文精通Spring Boot序列化與反序列化(告別數(shù)據(jù)混亂)
大家好,我是加洛斯 ????。作為一名程序員,我深深信奉費(fèi)曼學(xué)習(xí)法——教,是最好的學(xué) ??。這里是我的知識筆記與分享,旨在把復(fù)雜的東西講明白。如果發(fā)現(xiàn)有誤,萬分歡迎你幫我指出來 ??!廢話不多說,正文開始 ??
在開發(fā)中我們經(jīng)常能聽到的兩個詞,序列化與反序列化。很多萌新小白聽到這個概念肯定是滿腦門問號,接下來我將用通俗易懂的語言和妙趣橫生的比喻,深入淺出的將序列化與反序列的基礎(chǔ)以及原理給大家講述出來。
一、基礎(chǔ)概念
簡單來說,序列化 和 反序列化 就是 將數(shù)據(jù)在不同格式之間進(jìn)行轉(zhuǎn)換 的過程,目的是為了在不同的系統(tǒng)或不同的上下文之間傳輸和存儲數(shù)據(jù)。
- 序列化 (
Serialization): 將 對象 轉(zhuǎn)換為 可傳輸或可存儲的格式(通常是 JSON、XML 等)。- 在 Spring Boot 中的場景: 當(dāng)你的 Controller 方法返回一個 Java 對象時,Spring Boot 會自動將它序列化成 JSON 字符串,然后通過 HTTP 響應(yīng)發(fā)送給前端(如瀏覽器、手機(jī) App)。
- 反序列化 (
Deserialization): 將 可傳輸或可存儲的格式(如 JSON、XML)轉(zhuǎn)換回 對象。- 在 Spring Boot 中的場景: 當(dāng)前端通過 HTTP 請求(如 POST、PUT)發(fā)送一個 JSON 數(shù)據(jù)到你的服務(wù)器時,Spring Boot 會自動將這個 JSON 字符串反序列化成你 Controller 方法參數(shù)中定義的 Java 對象。
那么簡單來講就是,序列化是將對象轉(zhuǎn)化為JSON等格式,反序列化就是將JSON等格式轉(zhuǎn)化為對象。
二、具體應(yīng)用
Spring Boot 通過Spring MVC模塊和默認(rèn)集成的Jackson庫,讓這個過程變得極為簡單,但是其背后的原理卻是相當(dāng)復(fù)雜,我們先從簡單的開始來,看看怎么用以及干了什么。
2.1 反序列
假設(shè)前端要創(chuàng)建一個用戶,它發(fā)送了一個 POST 請求,請求體是 JSON:
{
"name": "張三",
"age": 25,
"email": "zhangsan@example.com"
}對應(yīng)的 User 類(Java Bean):
// 必須有無參構(gòu)造函數(shù)
// 必須有為所有屬性生成的 Getter 和 Setter 方法
// lombok注解 自動生成getter與setter方法與無參構(gòu)造函數(shù)
@Data
public class User {
private String name;
private Integer age;
private String email;
}在你的 Spring Boot Controller 中,你會這樣寫:
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<String> createUser(@RequestBody User user) {
// 在這個方法內(nèi)部,User 對象已經(jīng)是一個可以直接使用的 Java 對象了
System.out.println("用戶名:" + user.getName());
System.out.println("年齡:" + user.getage());
// ... 保存用戶到數(shù)據(jù)庫等操作
return ResponseEntity.ok("用戶創(chuàng)建成功");
}
}這里發(fā)生了什么?
- 前端發(fā)送 JSON 數(shù)據(jù)。
- Spring Boot 看到
@RequestBody注解和User這個參數(shù)類型。 - Spring Boot 使用 Jackson 庫 反序列化 JSON 字符串,根據(jù) JSON 的 key 匹配
User類的屬性(如name匹配name),并創(chuàng)建一個User對象。 - 這個創(chuàng)建好的
User對象被傳入你的createUser方法中。
這樣我們就從前端發(fā)送的JSON中解析了我們需要的數(shù)據(jù),是不是很簡單,現(xiàn)在沒有配置任何文件,緊靠SpringBoot自帶的Jackson庫就完成了反序列化。
2.2 序列化
同樣一個 Controller,我們寫一個查詢用戶的方法:
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// 假設(shè)從數(shù)據(jù)庫或其他地方查詢到了一個用戶
User user = new User();
user.setName("李四");
user.setAge(30);
user.setEmail("lisi@example.com");
// 直接返回這個對象
return user;
}
}這里發(fā)生了什么?
- 你的方法返回了一個
User對象。 - Spring Boot 看到返回值后,使用 Jackson 庫 序列化 這個
User對象。 - 最終,前端收到的 HTTP 響應(yīng)體就是這樣的 JSON 字符串:
{
"name": "李四",
"age": 30,
"email": "lisi@example.com"
}三、Jackson
SpringBoot通過自動配置和默認(rèn)的 Jackson 集成,極大地簡化了 Web 開發(fā)中數(shù)據(jù)格式轉(zhuǎn)換的復(fù)雜性。開發(fā)者幾乎不需要編寫轉(zhuǎn)換代碼,只需關(guān)注業(yè)務(wù)邏輯(定義對象、編寫 Controller),就能輕松實(shí)現(xiàn) RESTful API 的數(shù)據(jù)交互。我們來學(xué)習(xí)幾個常用的 Jackson 注解。
@JsonIgnore:在序列化時忽略某個屬性。
public class User {
private String name;
@JsonIgnore // 返回給前端的 JSON 中不會包含 password 字段,保障安全
private String password;
}
@JsonProperty:為屬性指定一個別名。
public class User {
@JsonProperty("full_name") // 序列化后 JSON 中的 key 是 "full_name"
private String name;
}@JsonFormat:格式化日期字段。
public class User {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
@JsonInclude:控制序列化時包含哪些屬性。
@JsonInclude(JsonInclude.Include.NON_NULL) // 只包含非 null 字段
public class User {
private String name;
private Integer age; // 如果 age 為 null,則序列化結(jié)果中無此字段
}
@JsonView:定義視圖,實(shí)現(xiàn)不同接口返回不同字段。
public class Views {
public static class Public {} // 公共視圖
public static class Internal extends Public {} // 內(nèi)部視圖,繼承公共視圖
}
public class User {
@JsonView(Views.Public.class)
private String name;
@JsonView(Views.Internal.class)
private String email;
}
@RestController
public class UserController {
@GetMapping("/user/public")
@JsonView(Views.Public.class) // 只序列化 Public 視圖的字段
public User getPublicUser() { ... }
@GetMapping("/user/internal")
@JsonView(Views.Internal.class) // 序列化 Internal 和 Public 視圖的字段
public User getInternalUser() { ... }
}| 過程 | 方向 | 動作 | 比喻 | Spring Boot 中的關(guān)鍵注解 |
|---|---|---|---|---|
| 序列化 | 對象 -> JSON | 將Java對象轉(zhuǎn)換為傳輸/存儲格式 | 打包 | (默認(rèn)行為,無需注解) |
| 反序列化 | JSON -> 對象 | 將傳輸/存儲格式轉(zhuǎn)換為Java對象 | 拆包組裝 | @RequestBody |
四、原理
Spring Boot 的序列化與反序列化其背后是一套名為 HttpMessageConverter 的可插拔策略接口。
- 工作原理: 當(dāng) Spring MVC 處理一個 HTTP 請求時,它會根據(jù)請求的
Content-Type(反序列化)和Accept(序列化)頭,以及目標(biāo)方法的參數(shù)/返回類型,來選擇一個合適的HttpMessageConverter實(shí)現(xiàn)。 - 可插拔性: 你可以自定義或替換這些轉(zhuǎn)換器,從而支持不同的數(shù)據(jù)格式(如 JSON、XML、Protobuf 等)。
Spring Boot 通過自動配置,默認(rèn)為我們注冊了以下常用的轉(zhuǎn)換器:
| 轉(zhuǎn)換器類 | 支持格式 | 說明 |
|---|---|---|
MappingJackson2HttpMessageConverter | JSON | 默認(rèn),使用 Jackson 庫 |
GsonHttpMessageConverter | JSON | 使用 Google 的 Gson 庫 |
Jaxb2RootElementHttpMessageConverter | XML | 處理 XML 格式 |
如何切換? 例如,如果你想用 Gson 替代 Jackson,只需在
pom.xml中排除 Jackson 并引入 Gson 依賴,Spring Boot 會自動切換默認(rèn)的 JSON 轉(zhuǎn)換器。
五、自定義序列化與反序列化器
當(dāng)默認(rèn)行為無法滿足復(fù)雜需求時,可以編寫自定義的 JsonSerializer 和 JsonDeserializer。 我們希望將 Money 對象序列化為 "100.00元" 的格式。
// 1. 自定義序列化器
public class MoneySerializer extends JsonSerializer<Money> {
@Override
public void serialize(Money value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 將 Money 對象轉(zhuǎn)換為字符串
String moneyStr = value.getAmount() + "元";
gen.writeString(moneyStr);
}
}
// 2. 自定義反序列化器
public class MoneyDeserializer extends JsonDeserializer<Money> {
@Override
public Money deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText(); // 例如 "100.00元"
// 解析字符串,創(chuàng)建 Money 對象
String amountStr = text.replace("元", "");
BigDecimal amount = new BigDecimal(amountStr);
return new Money(amount);
}
}
// 3. 在 Money 類上使用注解綁定
public class Money {
private BigDecimal amount;
@JsonSerialize(using = MoneySerializer.class)
@JsonDeserialize(using = MoneyDeserializer.class)
public BigDecimal getAmount() {
return amount;
}
}在 application.properties 或通過配置類 Jackson2ObjectMapperBuilderCustomizer 可以進(jìn)行全局配置,避免在每個類上重復(fù)注解。
配置文件方式:
# 縮進(jìn)輸出,便于閱讀 spring.jackson.serialization.indent-output=true # 忽略未知屬性,反序列化時如果JSON有類中沒有的字段不報(bào)錯 spring.jackson.deserialization.fail-on-unknown-properties=false # 日期全局格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss # 忽略值為 null 的字段 spring.jackson.default-property-inclusion=non_null
配置類方式(Configuration):
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.featuresToEnable(SerializationFeature.INDENT_OUTPUT);
builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
};
}
}到此這篇關(guān)于一文精通Spring Boot序列化與反序列化(告別數(shù)據(jù)混亂)的文章就介紹到這了,更多相關(guān)Spring Boot序列化與反序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java源碼解析CopyOnWriteArrayList的講解
今天小編就為大家分享一篇關(guān)于Java源碼解析CopyOnWriteArrayList的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01
springboot如何開啟一個監(jiān)聽線程執(zhí)行任務(wù)
這篇文章主要介紹了springboot如何開啟一個監(jiān)聽線程執(zhí)行任務(wù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02
用Maven插件生成Mybatis代碼的實(shí)現(xiàn)方法
本文主要介紹 Maven插件生成Mybatis代碼,現(xiàn)在做開發(fā)的朋友有好多用Maven 來管理代碼,這里給大家舉個例子,有需要的同學(xué)可以看下2016-07-07
Servlet注解之@WebInitParam多個InitParam的使用
這篇文章主要介紹了Servlet注解之@WebInitParam多個InitParam的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04

