Spring Boot 2.0 讀書筆記_06:Jackson

4. Jackson

寫在開頭,在MVC框架中,Spring Boot 內置了 Jackson 來完成JSON的序列化和反序列化。

  • @ResponseBody 在Controller對應請求方法上就好了,自動將方法返回的對象序列化成JSON。

  • 序列化、反序列化方式
    Jackson是一個流行的高性能JavaBean到JSON的綁定工具,Jackson使用ObjectMapper類將POJO對象序列化成JSON字符串,也能將JSON字符串反序列化成POJO對象。

    方式 說明
    JsonParser 採用JsonParser來解析JSON,解析結果是一串Tokens。
    採用JSONGenerator來生成JSON,最底層方式。
    樹遍歷 (Tree Traversing) JSON被讀入到JsonNode對象中,可以像操作XML DOM那樣讀取JSON
    DataBind 數據綁定方式,最簡單直接的一種方式。
    有時候需要相關注解或序列化實現類來進行個性化序列化等操作

    對應用程序來講,最常用的方式是DataBind,也就是將POJO對象轉換成JSON字符串,或者解析JSON字符串並映射到POJO對象上。
    那麼,如果沒有現成的POJO對象做數據綁定的時候,也可以通過樹遍歷的方式來獲取JSON數據。

  • Jackson 樹遍歷(Tree Traversing)
    樹遍歷方式通常適合沒有POJO對象的JSON。

      @Autowired ObjectMapper mapper;
    
      @GetMapping("/readtree.json")
      public @ResponseBody String readtree() throws JsonProcessingException, IOException {
      	String json = "{\"name\":\"zhangsan\", \"id\":10}";
      	// JSON序列化
      	JsonNode node = mapper.readTree(json);
      	// 獲取序列化結果
      	String name = node.get("name").asText();
      	int id = node.get("id").asInt();
      	return "name" + name + ",id" + id;
      }
    

    readTree 方法可以接受一個字符串或者字節數組、文件、inputStream等,返回JsonNode作爲根結點。
    關於讀取數據,JsonNode支持以下方法讀取序列化後的JSON數據:

    • axXXX:for example,asText、asBoolean、asInt etc… 讀取JsonNode對應的值。
    • isArray:判斷JsonNode是否是數組,如果是數組,則可以調用 get(i) 來進行遍歷。
    • get(“key”):獲取當前節點的子節點,返回JsonNode。
      注:JSON規範要求key是字符串,且要使用雙引號。
  • ObjectMapper 序列化和反序列化

    • 序列化 POJO to JSON

        User user = mapper.readValue(json, User.class);
      
    • 反序列化 JSON to POJO

        String json = mapper.writeValueAsString(user);
      
    • 樹模型和數據綁定都是基於流失操作完成的,即通過JsonParser類解析JSON,形成JsonToken流。

    • JsonParser 的解析結果包含了一些列JsonToken,JsonToken是一個枚舉類型。列舉常用的常量:

    枚舉常量 說明
    START_OBJECT {
    END_OBJECT }
    START_ARRAY [
    END_ARRAY ]
    FIELD_NAME JSON key
    VALUE_STRING JSON value 字符串類型
    VALUE_NUMBER_INT JSON value 整型

    序列化簡易流程:

      // 模擬JSON數據,Map形式 
      String json = "{\"name\":\"zhangsan\"}";
      // 定義暫存數據變量
      String key = null, value = null;
      /**
      * 開始解析JSON
      */ 	
      JsonFactory f = mapper.getFactory();
      JsonParser parser = f.createParser(json);
      // { -> START_OBJECT,忽略第一個Token
      JsonToken token = parser.nextToken();
      token = parser.nextToken();
      // JSON key  -> FIELD_NAME 保存至暫存數據變量key中
      if(token == JsonToken.FIELD_NAME) {
      	key = parser.getCurrentName();
      }
      token = parser.nextToken();
      // JSON value -> VALUE_STRING 保存至暫存數據變量value中
      value = parser.getValueAsString();
      // 關閉 parser
      parser.close();
      return key + " : " + value;
    

    判斷Token類型後,通過getValueAsXXX獲取其值,XXX是其值的類型。
    反序列化簡易流程:

      JsonFactory f = mapper.getFactory();
      // 輸出到 StringWriter
      StringWriter sw = new StringWriter();
      JsonGenerator g = f.createGenerator(sw);
      // 輸出 {
      g.writeStartObject();
      // 輸出數據
      g.writeStringField(key, value);
      // 輸出 }
      g.writeEndObject();
      // 關閉 StringWriter
      g.colse();
      retrun sw.toString();
    
  • Jackson 常用註解

註解 說明 實例
@JsonProperty 作用在屬性上,爲JSON Key指定別名 @JsonProperty(“userName”)
private String name;
@JsonIgnore 作用在屬性上,用來忽略此屬性 @JsonIgnore
private String password;
@JsonIgnoreProperties 作用於類上,忽略一組屬性 @JsonIgnoreProperties({“id”, “phone”})
public static class SamplePojo{…}
@JsonFormat 日期格式化 @JsonFormat(pattern = “yyyy-MM-dd”)
private Date date;

補充不常用註解:
@JsonSerialize 指定一個實現類來自定義序列化,類必須繼承JsonSerializer

public static class UserSerializer extends JsonSerializer<User> {
  @Override
  public void serialize(User user, JsonGenerator jsonGenerator,
                        SerializerProvider serializerProvider) throws IOException {
    jsonGenerator.writeStartObject();
    jsonGenerator.writeStringField("user_name", user.getName());
    jsonGenerator.writeEndObject();
  }
}

JsonGenerator 對象是 Jackson 底層的序列化實現,上述代碼中對name屬性做了序列化,輸出key形式上變更爲:user_name。
使用@JsonSerialize註解需要制定對象的序列化方式,例如:

@JsonSerialize(using = UserSerializer.class)
public class User {
  ...
}

同樣的,自定義反序列化,需要通過反序列化實現類繼承JsonDeserializer,使用@JsonDeserialize註解制定對象反序列化方式。
@JsonView,作用在類或者屬性上,用來序列化組。Spring MVC的Controller方法可以使用同樣的@JsonView來序列化屬於本組的設置。
對於User對象,有些情況下只需要返回id屬性,有些情況需要返回id和name,因此User對象可以定義爲如下:

public class User {
  public interface IdView {};
  public interface IdNameView extends IdView {};
  
  @JsonView(IdView.class)
  private Integer id;
  @JsonView(IdNameView.class)
  private String name;
  @JsonIgnore
  BigDecimal salary;
}

User定義了兩個接口類,IdView、IdNameView(繼承IDView接口)。這兩個接口代表了兩個序列化組的名稱。
Spring MVC 的Controller方法運行使用@JsonView()指定一個序列化組名,被序列化的對象只有在該序列組中的屬性纔會被序列化。

@JsonView(User.IdView.class)
@RequestMapping("/id.json")
public @ResponseBody User queryIds() {
  User user = new User();
  user.setId(1);
  user.setName("hello");
  return user;
}

上述代碼,只會輸出id屬性內容。更換成@JsonView(User.IdNameView.class)將輸出id和name,因爲組名IdView是IdNameView的父類。

  • 集合的反序列化
    Spring MVC的Controller方法中,可以對參數列表使用@RequestBody註解,將提交的JSON自動映射到方法參數上。
    注意是@RequestBody,是@RequestBody,是@RequestBody,不是@ResponseBody

    @RequestMapping("/addUser.json")
    public @ResponseBody String addUser(@RequestBody User user) {
      ...
      return user.toString();
    }
    

    通過Postman進行接口調用的時候需要注意:接收的是JSON請求

    在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章