一篇Jackson入门教程奉上
前言
现在开发,基本上都离不开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或空字符串 |
总结
希望我的这篇文章对你有帮助。
人生是个圆,有的人走了一辈子也没有走出命运画出的圆圈,其实,圆上的每一个点都有一条腾飞的切线。
玩代码、玩技术
长按识别二维码,关注“果冻想”
如果觉得还不错,可以点个“在看”哦~