自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot 優(yōu)雅處理 JSON動態(tài)屬性

開發(fā) 前端
有時我們需要處理具有未知屬性的動態(tài) JSON 對象,這些對象的結構可能在運行時有所不同,超出了預定義數(shù)據結構的范圍。在這種情況下,我們就需要采用一些特殊的技術或策略來靈活地處理這些動態(tài) JSON 對象。

環(huán)境:SpringBoot3.4.0

1. 簡介

使用 Jackson 處理預定義的 JSON 數(shù)據結構非常簡單。Spring Boot 默認使用 Jackson 作為其 JSON 處理庫,因此,在默認情況下,我們無需進行任何額外的配置即可輕松地在 Spring Boot 應用中序列化和反序列化 JSON 數(shù)據。

然而,有時我們需要處理具有未知屬性的動態(tài) JSON 對象,這些對象的結構可能在運行時有所不同,超出了預定義數(shù)據結構的范圍。在這種情況下,我們就需要采用一些特殊的技術或策略來靈活地處理這些動態(tài) JSON 對象。

1.1 什么是動態(tài)屬性?

首先,我們有如下的實體類:

public class Product {
  private String name;
  private String category;
  // getters, setters
}

對應的JSON字符串如下:

{
  "name": "SpringBoot實戰(zhàn)案例100例",
  "category": "book",
  "details": {
    "price": "70",
    "author": "XGPack"
  }
}

這里的 "details" 代表的是動態(tài)屬性,它在 Product 實體對象中并沒有預先定義的對應屬性。

接下來,本篇文章將介紹4種方式處理這種JSON對象中包含動態(tài)屬性的情況。

2. 實戰(zhàn)案例

2.1 使用JsonNode屬性

我們可以在 Product 類中添加一個類型為 com.fasterxml.jackson.databind.JsonNode 的屬性,用來接收和處理上述的 details 動態(tài)屬性,如下示例:

public class Product {


  // other properties
  private JsonNode details;
  // getters, setters
}

測試代碼

ObjectMapper objectMapper = new ObjectMapper() ;
String json = """
    {
      "name": "SpringBoot實戰(zhàn)案例100例",
      "category": "book",
      "details": {
        "price": "70",
        "author": "XGPack"
      }
    }
  """ ;
Product product = objectMapper.readValue(json, Product.class) ;
System.err.printf("name: %s, category: %s%n", product.getName(), product.getCategory()) ;
System.out.println("--------------------------------") ;
System.err.printf("price: %s, auther: %s%n", 
  product.getDetails().get("price").asText(),
  product.getDetails().get("author").asText()) ;

輸出結果

圖片圖片

問題得到了解決,但這個解決方案存在一個問題;由于我們有一個 JsonNode 字段,我們的類依賴于 Jackson 庫。

2.2 使用Map集合

我們還可以使用Map集合來接收這些動態(tài)屬性,如下示例:

public class Product_Map {
  // other properties
  private Map<String, Object> details;
  // getters, setters
}

測試代碼

ObjectMapper objectMapper = ... ;
String json = ... ;
Product product = objectMapper.readValue(json, Product.class) ;
System.err.printf("name: %s, category: %s%n", product.getName(), product.getCategory()) ;
System.out.println("--------------------------------") ;
System.err.printf("price: %s, author: %s%n", 
    product.getDetails().get("price"),
    product.getDetails().get("author")) ;

此種方式有通過JsonNode差不多,只是這種方式不依賴于jackson包。

2.3 使用@JsonAnySetter注解

當對象只包含動態(tài)屬性時(details),上面的2個解決方案是很好的選擇。然而,有時我們在一個 JSON 對象中混合了固定屬性和動態(tài)屬性。也就是如下數(shù)據格式時:

{
  "name": "SpringBoot實戰(zhàn)案例100例",
  "category": "book",
  "price": "70",
  "author": "XGPack"
}

動態(tài)屬性與固定的屬性是平級混合在一起,這種情況我們可以使用 @JsonAnySetter 注解來標記一個方法,以處理額外的、未知的屬性。這樣的方法應該接受兩個參數(shù):屬性的key和value。

public class Product {


  // other properties
  private Map<String, Object> details = new LinkedHashMap<>() ;
  @JsonAnySetter
  public void setDetail(String key, Object value) {
      details.put(key, value) ;
  }
  // getters, setters
}

這里,我們在 setter 方法上使用 @JsonAnySetter 注解,以便該方法能夠處理那些動態(tài)的屬性。

測試代碼

ObjectMapper objectMapper = ... ;
String json = ... ;
Product product = objectMapper.readValue(json, Product.class) ;
System.err.printf("name: %s, category: %s%n", product.getName(), product.getCategory()) ;
System.out.println("--------------------------------") ;
System.err.printf("price: %s, author: %s%n", 
    product.getDetails().get("price"),
    product.getDetails().get("author")) ;

輸出結果

圖片圖片

2.4 自定義反序列化器

在大多數(shù)情況下,這些解決方案都能很好地工作;然而,當我們需要更多的控制時,我們可以使用自定義反序列化器來處理。

public class ProductDeserializer extends StdDeserializer<Product> {
  public ProductDeserializer() {
    this(null);
  }
  public ProductDeserializer(Class<?> vc) {
    super(vc);
  }
  @Override
  public Product_CustomDeserializer deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    JsonNode node = jp.getCodec().readTree(jp) ;
    // 獲取通用字段
    String name = node.get("name").asText() ;
    String category = node.get("category").asText() ;
    // 獲取動態(tài)屬性
    JsonNode detailsNode = node.get("details");
    String price = detailsNode.get("price").asText() ;
    String author = detailsNode.get("author").asText() ;
    Map<String, Object> details = new HashMap<>() ;
    details.put("price", displayAspectRatio) ;
    details.put("author", audioConnector) ;
    return new Product(name, category, details) ;
  }
}

測試代碼:

ObjectMapper objectMapper = new ObjectMapper() ;
// 注冊反序列獲器
SimpleModule module = new SimpleModule();
module.addDeserializer(Product.class, new ProductDeserializer());
objectMapper.registerModule(module) ;
String json = ... ;
// ...

這里通過編程的方式注冊自定義反序列化器,其它代碼都是一樣的。

我們還可以通過更簡單的方式進行處理,直接通過注解的方式注冊自定義的反序列化器:

@JsonDeserialize(using = ProductDeserializer.class)
public class Product {
  // ...
}

在Spring Boot環(huán)境下,那么還可以通過如下方式定義和注冊反序列化器。

@JsonComponent
public class PackJsonComponent {


  // 自定義反序列化
  public static class Deserializer extends JsonDeserializer<Product> {
    @Override
    public Product deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
      JsonNode node = jp.getCodec().readTree(jp) ;
      String name = node.get("name").asText() ;
      String category = node.get("category").asText() ;
      
      // ...
      return new Product(name, category, details) ;
    }
  }
}

使用@JsonComponent注解即可。

責任編輯:武曉燕 來源: Spring全家桶實戰(zhàn)案例源碼
相關推薦

2021-04-20 10:50:38

Spring Boot代碼Java

2022-10-26 07:14:25

Spring 6Spring業(yè)務

2024-09-27 12:27:31

2014-07-22 09:01:53

SwiftJSON

2024-08-02 09:15:22

Spring捕捉格式

2025-03-11 00:55:00

Spring停機安全

2020-03-16 17:20:02

異常處理Spring Boot

2025-01-13 12:46:31

SpringBootJacksonJSON

2024-12-06 09:27:28

2023-04-17 23:49:09

開發(fā)代碼Java

2024-10-16 12:23:55

技巧Spring驗證

2023-09-13 08:56:51

2022-04-08 16:27:48

SpringBoot異常處理

2021-01-07 14:06:30

Spring BootJUnit5Java

2021-03-09 13:18:53

加密解密參數(shù)

2023-11-01 08:58:10

2024-10-11 11:46:40

2022-06-04 12:25:10

解密加密過濾器

2022-05-18 12:04:19

Mybatis數(shù)據源Spring

2025-04-17 03:33:00

SpringSQL動態(tài)查詢
點贊
收藏

51CTO技術棧公眾號