前言
現在開發,基本上都離不開JSON格式,也都會涉及到對象與JSON的序列化與反序列化。在Java的世界中,就不得不說fastjson和jackson了,這兩個庫基本上統治了Java世界中的JSON序列化和反序列化操作。前幾天組內評審代碼,發現一個項目中既在使用fastjson,又在使用jackson,出現亂用的行爲,開發人員也不知道誰是誰,反正就是抓起來用。後來經過評估,統一在項目中使用jackson,同時也總結這篇文章,針對jackson給大家掃盲一下。
Maven依賴
對於非Spring Boot項目,要使用Jackson,則需要添加以下三個依賴:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
</dependency>
對於Spring Boot項目,引入了web依賴,就引入了Jackson:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
上面的三個依賴,分別對應Jackson的三個核心模塊:
Streaming
:核心包,提供基於”流模式”解析的相關 API,它包括JsonPaser和JsonGenerator。Jackson內部實現正是通過高性能的流模式API的JsonGenerator和JsonParser來生成和解析 json;Annotations
:註解包,提供標準註解功能;Databind
:數據綁定包, 提供基於”對象綁定” 解析的相關 API(ObjectMapper )和”樹模型” 解析的相關 API(JsonNode);基於”對象綁定” 解析的API和”樹模型”解析的API依賴基於”流模式”解析的API。
實戰演示
所有的學習都需要落實到實戰上面,下面就把我們在實戰中常用的Jackson用戶進行演示。
下面的演示基於以下幾個Bean類,這幾個Bean類的結構如下所示:
+-weatherBean類
+--WeatherResultBean類
+-------WeatherSkInfoBean類
+-------WeatherInfoBean類
WeatherBean
類:
@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherBean {
@JsonProperty("resultcode")
private String resultcode;
@JsonProperty("reason")
private String reason;
@JsonProperty("result")
private WeatherResultBean result;
@JsonProperty("error_code")
private int errorCode;
@Override
public String toString() {
return "resultcode:" + this.resultcode + ";reason:" + this.reason +
";error_code:" + this.errorCode;
}
public String getResultcode() {
return resultcode;
}
public void setResultcode(String resultcode) {
this.resultcode = resultcode;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public WeatherResultBean getResult() {
return result;
}
public void setResult(WeatherResultBean result) {
this.result = result;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
}
WeatherResultBean
類:
@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherResultBean {
@JsonProperty("sk")
private WeatherSkInfoBean weatherSkInfoBean;
@JsonProperty("today")
private WeatherInfoBean weatherInfoBean;
public WeatherInfoBean getWeatherInfoBean() {
return weatherInfoBean;
}
public void setWeatherInfoBean(WeatherInfoBean weatherInfoBean) {
this.weatherInfoBean = weatherInfoBean;
}
public WeatherSkInfoBean getWeatherSkInfoBean() {
return weatherSkInfoBean;
}
public void setWeatherSkInfoBean(WeatherSkInfoBean weatherSkInfoBean) {
this.weatherSkInfoBean = weatherSkInfoBean;
}
}
WeatherSkInfoBean
類:
@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherSkInfoBean {
@JsonProperty("temp")
private String temp;
@JsonProperty("wind_direction")
private String windDirection;
@JsonProperty("humidity")
private String humidity;
@JsonProperty("time")
private String time;
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getWindDirection() {
return windDirection;
}
public void setWindDirection(String windDirection) {
this.windDirection = windDirection;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
WeatherInfoBean
類:
@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherInfoBean {
@JsonProperty("temperature")
private String temperature;
@JsonProperty("weather")
private String weather;
@JsonProperty("weather_id")
private Map<String, String> weatherId;
@JsonProperty("wind")
private String wind;
@JsonProperty("week")
private String week;
@JsonProperty("city")
private String city;
@JsonProperty("date_y")
private String currDate;
@JsonProperty("dressing_index")
private String dressingIndex;
@JsonProperty("dressing_advice")
private String dressingAdvice;
@JsonProperty("uv_index")
private String uvIndex;
@JsonProperty("comfort_index")
private String comfortIndex;
@JsonProperty("wash_index")
private String washIndex;
@JsonProperty("travel_index")
private String travelIndex;
@JsonProperty("exercise_index")
private String exerciseIndex;
@JsonProperty("drying_index")
private String dryingIndex;
// 省略setter和getter代碼
}
這是一個相對複雜的結構,我也是把主要貼出來了,爭取給大家一個完整的體驗。下面就結合我們實際常用的幾種場景開始總結。
Bean轉JSON
後端開發的接口在給前端返回數據時,都是要求返回JSON串,所以,我們在返回時,都會涉及Bean轉JSON的操作,這個在我們的後端開發中肯定會遇到的。
對於上面的結構,我們通過構建Bean類結構,然後調用ObjectMapper
的writeValueAsString
方法即可完成轉換。代碼如下:
ObjectMapper mapper = new ObjectMapper();
WeatherInfoBean weatherInfoBean = new WeatherInfoBean();
WeatherSkInfoBean weatherSkInfoBean = new WeatherSkInfoBean();
WeatherResultBean weatherResultBean = new WeatherResultBean();
WeatherBean weatherBean = new WeatherBean();
weatherInfoBean.setCity("呼和浩特");
weatherInfoBean.setComfortIndex("");
weatherInfoBean.setCurrDate("2020年11月1日");
weatherInfoBean.setDressingAdvice("建議着厚外套加毛衣等服裝。年老體弱者宜着大衣、呢外套加羊毛衫。");
weatherInfoBean.setDressingIndex("較冷");
weatherInfoBean.setDryingIndex("");
weatherInfoBean.setExerciseIndex("不適宜");
weatherInfoBean.setTemperature("-3℃~10℃");
weatherInfoBean.setTravelIndex("不適宜");
weatherInfoBean.setUvIndex("高等");
weatherInfoBean.setWashIndex("不適宜");
weatherInfoBean.setWeather("晴轉陰");
Map<String, String> weatherId = new HashMap<>();
weatherId.put("fa", "00");
weatherId.put("fb", "00");
weatherInfoBean.setWeatherId(weatherId);
weatherInfoBean.setWeek("星期日");
weatherInfoBean.setWind("西北風3-5級");
weatherSkInfoBean.setTemp("2");
weatherSkInfoBean.setWindDirection("西南風");
weatherSkInfoBean.setHumidity("39%");
weatherSkInfoBean.setTime("23:20");
weatherResultBean.setWeatherSkInfoBean(weatherSkInfoBean);
weatherResultBean.setWeatherInfoBean(weatherInfoBean);
weatherBean.setResultcode("200");
weatherBean.setReason("請求成功");
weatherBean.setResult(weatherResultBean);
weatherBean.setErrorCode(0);
String json = mapper.writeValueAsString(weatherBean);
System.out.println(json);
JSON轉Bean
在客戶端請求後端的接口時,入參基本都是JSON格式的數據,這個時候就需要我們將JSON格式數據轉成Bean,以便我們取數據進行對應的處理。現在假設客戶端傳過來的數據是這樣的:
{"resultcode":"200","reason":"successed!","result":{"sk":{"temp":"1","wind_direction":"西北風","wind_strength":"2級","humidity":"38%","time":"23:20"},"today":{"temperature":"-3℃~10℃","weather":"晴","weather_id":{"fa":"00","fb":"00"},"wind":"西北風3-5級","week":"星期六","city":"呼和浩特","date_y":"2020年10月31日","dressing_index":"較冷","dressing_advice":"建議着厚外套加毛衣等服裝。年老體弱者宜着大衣、呢外套加羊毛衫。","uv_index":"中等","comfort_index":"","wash_index":"較適宜","travel_index":"較不宜","exercise_index":"較不宜","drying_index":""}},"error_code":0}
對於Jackson來說,我們只需要以下這樣幾行代碼就可以搞定:
ObjectMapper mapper = new ObjectMapper();
String strJson = "{\"resultcode\":\"200\",\"reason\":\"successed!\"," +
"\"result\":{\"sk\":{\"temp\":\"1\",\"wind_direction\":\"西北風\",\"wind_strength\":\"2級\",\"humidity\":\"38%\",\"time\":\"23:20\"},\"today\":{\"temperature\":\"-3℃~10℃\",\"weather\":\"晴\",\"weather_id\":{\"fa\":\"00\",\"fb\":\"00\"},\"wind\":\"西北風3-5級\",\"week\":\"星期六\",\"city\":\"呼和浩特\",\"date_y\":\"2020年10月31日\",\"dressing_index\":\"較冷\",\"dressing_advice\":\"建議着厚外套加毛衣等服裝。年老體弱者宜着大衣、呢外套加羊毛衫。\",\"uv_index\":\"中等\",\"comfort_index\":\"\",\"wash_index\":\"較適宜\",\"travel_index\":\"較不宜\",\"exercise_index\":\"較不宜\",\"drying_index\":\"\"}},\"error_code\":0}";
Map<String, Object> result = mapper.readValue(strJson, HashMap.class);
WeatherBean weatherBean = mapper.readValue(strJson,
WeatherBean.class);
Map轉JSON
上面都是通過Bean來和JSON互轉,後來開發不喜歡構建Bean類了,覺的構建Bean類太麻煩,直接通過Map和List來搞定一切,但是在我的團隊內部,我是不建議直接使用Map和List來搞定一切的,這樣對於後期的運維不是很友好,但是,在一些簡單結構的JSON情況下,還是直接使用Map來搞定是比較方便的。
對於上面同樣的結構,我們使用Map來實現一下。
Map<String, Object> weatherSkInfoMap = new HashMap<>();
Map<String, Object> weatherInfoMap = new HashMap<>();
Map<String, Object> weatherResultMap = new HashMap<>();
Map<String, Object> weatherMap = new HashMap<>();
weatherSkInfoMap.put("temp", "1");
weatherSkInfoMap.put("wind_direction", "西北風");
weatherSkInfoMap.put("humidity", "39%");
weatherSkInfoMap.put("time", "23:20");
weatherInfoMap.put("temperature", "-3℃~10℃");
weatherInfoMap.put("weather", "晴");
Map<String, String> weatherIdMap = new HashMap<>();
weatherIdMap.put("fa", "00");
weatherIdMap.put("fb", "00");
weatherInfoMap.put("weather_id", weatherIdMap);
weatherInfoMap.put("wind", "西北風3-5級");
weatherInfoMap.put("week", "星期日");
weatherInfoMap.put("city", "呼和浩特");
weatherInfoMap.put("date_y", "2020年11月1日");
weatherInfoMap.put("dressing_index", "較冷");
weatherResultMap.put("sk", weatherSkInfoMap);
weatherResultMap.put("today", weatherInfoMap);
weatherMap.put("resultcode", "200");
weatherMap.put("reason", "請求成功");
weatherMap.put("result", weatherResultMap);
weatherMap.put("error_code", 0);
String json = mapper.writeValueAsString(weatherMap);
System.out.println(json);
JSON轉Map
同樣,也就存在JSON直接轉成Map的情況,也是很簡單:
ObjectMapper mapper = new ObjectMapper();
String strJson = "{\"resultcode\":\"200\",\"reason\":\"successed!\"," +
"\"result\":{\"sk\":{\"temp\":\"1\",\"wind_direction\":\"西北風\",\"wind_strength\":\"2級\",\"humidity\":\"38%\",\"time\":\"23:20\"},\"today\":{\"temperature\":\"-3℃~10℃\",\"weather\":\"晴\",\"weather_id\":{\"fa\":\"00\",\"fb\":\"00\"},\"wind\":\"西北風3-5級\",\"week\":\"星期六\",\"city\":\"呼和浩特\",\"date_y\":\"2020年10月31日\",\"dressing_index\":\"較冷\",\"dressing_advice\":\"建議着厚外套加毛衣等服裝。年老體弱者宜着大衣、呢外套加羊毛衫。\",\"uv_index\":\"中等\",\"comfort_index\":\"\",\"wash_index\":\"較適宜\",\"travel_index\":\"較不宜\",\"exercise_index\":\"較不宜\",\"drying_index\":\"\"}},\"error_code\":0}";
MapType javaType =
mapper.getTypeFactory().constructMapType(HashMap.class,
String.class, Object.class);
Map<String, Object> result = mapper.readValue(strJson, javaType);
System.out.println(result.toString());
List轉JSON
對於List直接轉JSON的情況,和上面的Map方式類似,示例代碼如下:
List<String> list = new ArrayList<>();
list.add("呼和浩特");
list.add("深圳");
list.add("大連");
list.add("北京");
String json = mapper.writeValueAsString(list);
System.out.println(json);
JSON轉List
對於JSON直接轉List的情況,和上面的Map方式類似,示例代碼如下:
String json = "[\"呼和浩特\",\"深圳\",\"大連\",\"北京\"]";
CollectionType javaType = mapper.getTypeFactory()
.constructCollectionType(List.class, String.class);
List<String> cityLst = mapper.readValue(json, javaType);
System.out.println(cityLst);
註解說明
在使用Bean的情況下(也是我經常用的情況),我們經常需要配合註解一起使用,這就需要我們對Jackson中的註解有所瞭解。Jackson中的註解有很多,但是我們常用的也就那麼幾個,我們最這幾個常用的重點註解進行一番總結。
註解 | 用法 |
---|---|
@JsonProperty | 用於屬性,把屬性的名稱序列化時轉換爲另外一個名稱 |
@JsonFormat | 用於屬性或者方法,把屬性的格式序列化時轉換成指定的格式。示例:@JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm”) private Date date; |
@JsonAnySetter | 用來在序列化和反序列化的時候多餘字段可以通過Map來回轉換。也就是JSON中的字段比對應的JavaBean中的字段多,可以在JavaBean中使用一個Map字段來接收多餘的JSON字段 |
@JsonAnyGetter | 同上 |
@JsonIgnore | 可用於字段、getter/setter、構造函數參數上,作用相同,都會對相應的字段產生影響。使相應字段不參與序列化和反序列化 |
@JsonIgnoreProperties(ignoreUnknown = true) | 該註解是類註解。該註解在Java類和JSON不完全匹配的時候使用。在從JSON反序列化爲Java類的時候,@JsonIgnoreProperties(ignoreUnknown=true) 會忽略所有沒有Getter和Setter的屬性,也就是忽略類中不存在的字段 |
@JsonIgnoreProperties({"internalId", "secretKey"}) | 該註解是類註解。該註解在Java類和JSON不完全匹配的時候使用。在序列化爲JSON的時候,@JsonIgnoreProperties({"internalId", "secretKey"}) 會忽略internalId和secretKey兩個屬性 |
@JsonRootName | 類註解。用於指定JSON根屬性的名稱 |
@JsonInclude | 用於定義在序列化時是否不應包含某些“非值”(null值或空值)的註解。可以用於每個字段上,也可以用於類上(表示用於類的所有屬性)。@JsonInclude(value = JsonInclude.Include.NON_NULL) 表示忽略類中值爲null的字段;@JsonInclude(Include.NON_EMPTY) 忽略類中值爲空的字段,對於字符串,即忽略null或空字符串 |
總結
希望我的這篇文章對你有幫助。
人生是個圓,有的人走了一輩子也沒有走出命運畫出的圓圈,其實,圓上的每一個點都有一條騰飛的切線。
玩代碼、玩技術
長按識別二維碼,關注“果凍想”
如果覺得還不錯,可以點個“在看”哦~