動態(tài)JSON怎么處理?Spring Boot五種強大的處理方式
環(huán)境:SpringBoot3.4.2
1. 簡介
在Web應用開發(fā)中,面對日益復雜的業(yè)務場景,客戶端傳遞的JSON數據可能并不是固定結構,如可變字段、嵌套對象或用戶自定義配置。
首先,我們來看如下的場景:
public class Person {
private String name ;
private Integer age ;
// getters, setters
}
@PostMapping("/create")
public Person queryUser(@RequestBody Person person) {
return person ;
}當我們通過如下的請求body訪問時:
圖片
控制臺輸出
圖片
未知的email字段。
注:該錯誤在當前我使用的Spring Boot下是需要開啟如下配置才會出現上面的錯誤
spring:
jackson:
deserialization:
fail-on-unknown-properties: true傳統(tǒng)固定DTO難以滿足此類需求,因此需要API具備處理動態(tài)JSON Body的能力。Spring Boot憑借其靈活的請求處理機制,為我們提供了多種應對方案,能夠有效支持結構不固定的請求數據,從而提升接口的靈活性和復用性。
本文將介紹在Spring Boot中處理動態(tài)JSON Body的5種常用方式。
2.實戰(zhàn)案例
2.1 使用Map集合
使用 Map<String, Object> 接收動態(tài)JSON Body,可靈活處理結構不確定的請求數據。Spring Boot自動將JSON鍵值對映射為Map條目,適用于字段可變、嵌套復雜或用戶自定義的場景,結合業(yè)務邏輯動態(tài)解析,提升接口適應性與擴展性。
@PostMapping("/way1")
public ResponseEntity<?> way1(@RequestBody Map<String, Object> body) {
return ResponseEntity.ok(body) ;
}
圖片
? 優(yōu)點:靈活,支持任意字段;無需預定義DTO;易于動態(tài)處理。
? 缺點:類型不安全;易出錯;缺乏結構校驗;代碼可讀性差。
2.2 使用JsonNode類型
使用 JsonNode 可精確解析任意結構的動態(tài)JSON Body。作為Jackson提供的樹模型,它支持遍歷、查詢和類型判斷,適合復雜嵌套或需深度操作的場景,結合ObjectMapper靈活處理,是處理不確定JSON的強力方案。
@PostMapping("/way2")
public ResponseEntity<?> createUser(@RequestBody JsonNode body) {
System.err.printf("解析email字段: %s%n", body.get("email").asText()) ;
return ResponseEntity.ok(body) ;
}輸出結果
圖片
解析email字段: pack@gmail.com? 優(yōu)點:結構靈活,支持復雜嵌套;可精確訪問任意節(jié)點;無需定義實體類。
? 缺點:處理深層結構時代碼冗長。
2.3 DTO + 動態(tài)字段(Map)
有時你已知 80% 的字段,但需要允許額外字段。這時候我們可以通過 Jackson 注解讓 Person 類更具靈活性。
修改實體Person:
public class Person {
private String name ;
private Integer age ;
private Map<String, Object> extra = new HashMap<>();
@JsonAnySetter
public void setExtra(String key, Object value) {
extra.put(key, value);
}
@JsonAnyGetter
public Map<String, Object> getExtra() {
return extra;
}
}Controller接口
@PostMapping("/way3")
public ResponseEntity<?> way3(@RequestBody Person person) {
System.err.println(person.getExtra()) ;
return ResponseEntity.ok(person) ;
}輸出結果
圖片
{email=pack@gmail.com}? 優(yōu)點:強類型 + 靈活性;Jackson自動捕獲未知字段
? 缺點:模型稍顯復雜
2.4 使用ObjectNode
ObjectNode 是 JsonNode 的可變子類,適合處理動態(tài)JSON Body。它提供增刪改查方法,可靈活構建和修改JSON結構,結合 ObjectMapper 使用,適用于需動態(tài)生成或修改JSON的場景,操作直觀且功能強大。
@PostMapping("/way4")
public ResponseEntity<?> way4(@RequestBody ObjectNode body) {
body.set("author", new TextNode("pack_xg")) ;
body.set("age", new IntNode(34)) ;
return ResponseEntity.ok(body) ;
}這里我們添加author字段,同時修改了age字段。
圖片
? 優(yōu)點:可動態(tài)增刪改JSON;操作靈活;適合構建和修改結構。
? 缺點:需要手動操作邏輯。
2.5 動態(tài)Json驗證
動態(tài)JSON Body因結構不固定,傳統(tǒng)基于DTO的注解驗證(如@NotNull)難以直接應用。當使用Map、JsonNode等接收數據時,字段名和層級不確定,導致無法在編解碼階段自動校驗。這時候我們可以通過JSON Schema驗證這種動態(tài)的JSON數據。
首先,引入如下依賴
<!--該依賴用來生成要驗證的json schema文件-->
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-generator</artifactId>
<version>4.38.0</version>
</dependency>
<!--該依賴用來校驗json數據-->
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.5.6</version>
</dependency>接下來,我們針對Person對象生成對應的Schema
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON) ;
// 設置必須的字段
configBuilder.forFields()
.withRequiredCheck(field -> "name".equals(field.getName()))
.withRequiredCheck(field -> "age".equals(field.getName())) ;
// 構建SchemaGeneratorConfig
SchemaGeneratorConfig config = configBuilder.build();
// 創(chuàng)建SchemaGenerator實例
SchemaGenerator generator = new SchemaGenerator(config);
// 根據User類生成Schema內容
JsonNode jsonSchema = generator.generateSchema(targetType);
// 將JsonNode轉換為ObjectNode以便修改
ObjectNode schemaObject = (ObjectNode) jsonSchema;
// 設置additionalProperties為false,禁止額外屬性
schemaObject.put("additionalProperties", true);
// 打印生成的JSON Schema
return jsonSchema.toPrettyString() ;內容如下:
圖片
最后,我們在Controller接口中進行驗證
@PostMapping("/validate")
public ResponseEntity<?> validate(@RequestBody ObjectNode body) throws Exception {
InputStream is;
try {
is = new ClassPathResource("schemas/person.json").getInputStream();
} catch (IOException e) {
throw new RuntimeException(e) ;
}
JsonSchema schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012).getSchema(is) ;
List<String> ret = schema.validate(body).stream().map(msg -> msg.getMessage()).toList() ;
return ResponseEntity.ok(ret) ;
}驗證結果

關于這里的錯誤提示內容,我們可以自定義 jsv-messages_zh_CN.properties國際化資源文件。




























