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請求