一.前言
1.介绍
- 上篇文章从spring-boot中引申出了jackson这个杰出的json解析框架,详细的分析了Jackson提供的注解功能,以及它们在controller中的使用,在这篇将介绍Jackson对外提供的API类ObjectMapper,以及Jackson在sping-boot配置文件中的各项配置
2.项目例子
- 此文章用到的例子在spring-boot项目中,传送门
- 此篇文章用到项目模块:
- 还有更多:spring-cloud项目
3.进阶文档
- spring-boot-json这是spring-boot官方介绍,寥寥数笔,所以我们还需要查看jackson的分项目jackson-annotations来了解具体用法
二.使用Jackson的ObjectMapper序列化和反序列化Json
- 注意,Jackson反序列化json为对象的时候,使用的是对象空参构造器,在我们自定义构造器的时候,需要覆写空参构造器
-
测试类中所使用的实体
public class Apartment { private String roommate; private String payRentMan; public Apartment() { } public Apartment(String roommate, String payRentMan) { this.roommate = roommate; this.payRentMan = payRentMan; } public String getRoommate() { return roommate; } public void setRoommate(String roommate) { this.roommate = roommate; } public String getPayRentMan() { return payRentMan; } public void setPayRentMan(String payRentMan) { this.payRentMan = payRentMan; } }
-
writeValue
:对象序列化的时候可以直接将需要序列化的数据,格式化成文件,也可以使用重载方法格式化流输出@Test public void testWriteValueAsFile() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); Apartment apartment = new Apartment("Joey", "Chandler"); objectMapper.writeValue(new File("target/apartment.json"), apartment); }
运行返回,在target文件夹下输出了apartment.json文件
-
writeValueAsString
和writeValueAsBytes
,对象可以直接序列化为字符串和字节@Test public void testWriteValueAsStringAndByte() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); Apartment apartment = new Apartment("Joey", "Chandler"); String result = objectMapper.writeValueAsString(apartment); System.out.println(result); byte[] bytes = objectMapper.writeValueAsBytes(apartment); System.out.println(new String(bytes)); assertEquals(result,new String(bytes)); }
运行返回
{"roommate":"Joey","payRentMan":"Chandler"} {"roommate":"Joey","payRentMan":"Chandler"}
-
readValue
,将json串反序列化为对象@Test public void testReadValueAsBeanFromJson() throws IOException { String json = "{ \"roommate\" : \"Joey\", \"payRentMan\" : \"Chandler\" }"; Apartment apartment = new ObjectMapper().readValue(json, Apartment.class); assertEquals(apartment.getPayRentMan(),"Chandler"); }
-
readValue
,将json串反序列化为对象,可以将file文件作为数据源也可以读取网络URL流中数据@Test public void testReadValueAsBeanFromFileAndURL() throws IOException { Apartment apartment = new ObjectMapper().readValue(new File("target/apartment.json"), Apartment.class); //Apartment apartment = new ObjectMapper().readValue(new URL("target/apartment.json"), Apartment.class); assertEquals(apartment.getPayRentMan(),"Chandler"); }
-
readTree
,将Json解析为Jackson JsonNode对象,从特定的节点中检索数据@Test public void testReadTree() throws IOException { String json = "{ \"roommate\" : \"Joey\", \"payRentMan\" : \"Chandler\" }"; JsonNode jsonNode = new ObjectMapper().readTree(json); assertEquals(jsonNode.get("payRentMan").asText(),"Chandler"); }
-
解析
json数组到list
中,这里需要注意的是,我们需要创建一个带有泛型的模板类对象传入到readValue中用于类型的识别,从而规避泛型的类型擦除@Test public void testReadValueAsListBean() throws IOException { String jsonApartmentArray = "[{ \"roommate\" : \"Joey\", \"payRentMan\" : \"Chandler\" }, { \"roommate\" : \"Rachel\", \"payRentMan\" : \"Monica\" }]"; List<Apartment> apartments= new ObjectMapper().readValue(jsonApartmentArray,new TypeReference<List<Apartment>>(){}); assertEquals(apartments.size(),2); }
-
将数据
映射到Map对象
中,同list一样,传入map的类型模板@Test public void testReadValueAsMap() throws IOException { String json = "{ \"roommate\" : \"Joey\", \"payRentMan\" : \"Chandler\" }"; Map<String, Object> map = new ObjectMapper().readValue(json, new TypeReference<Map<String,Object>>(){}); assertEquals(map.size(),2); }
-
解决反序列化为bean时json多出字段导致
UnrecognizedPropertyException
异常
第一种方式使用readTree反序列化为JsonNode
第二种方式使用configure方式忽略多余字段@Test public void testMoreProperty() throws IOException { String json = "{ \"roommate\" : \"Joey\", \"animal\" : \"dark\"}"; JsonNode jsonNode = new ObjectMapper().readTree(json); assertEquals(jsonNode.get("animal").asText(),"dark"); ObjectMapper objectMapper= new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); Apartment apartment = objectMapper.readValue(json, Apartment.class); assertEquals(apartment.getRoommate(),"Joey"); }
-
处理日期
有很多种方式,着重介绍2种
第一种实体类中使用注解@JsonFormat
第二种将日期格式化规则写入到ObjectMapper中@Test public void testDateFormat() throws IOException { Request request = new Request(); Apartment apartment = new Apartment("Joey", "Chandler"); request.setApartment(apartment); request.setBillingDate(new Date()); ObjectMapper objectMapper = new ObjectMapper(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z"); objectMapper.setDateFormat(df); String string = objectMapper.writeValueAsString(request); System.out.println(string); } class Request { private Apartment apartment; private Date billingDate; public Apartment getApartment() { return apartment; } public void setApartment(Apartment apartment) { this.apartment = apartment; } public Date getBillingDate() { return billingDate; } public void setBillingDate(Date billingDate) { this.billingDate = billingDate; } }
-
序列化和反序列化
嵌套list
,如下@Test public void testDateFormat2() throws IOException { ArrayList<RequestList> requestLists = Lists.newArrayList(new RequestList(Lists.newArrayList(new Apartment("Joey", "Chandler")),1), new RequestList(Lists.newArrayList(new Apartment("Joey", "Chandler")),2)); ObjectMapper objectMapper = new ObjectMapper(); String string = objectMapper.writeValueAsString(requestLists); System.out.println(string); List<RequestList> m = new ObjectMapper().readValue(string, new TypeReference<List<RequestList>>(){}); assertEquals(m.size(),2); } class RequestList { private List<Apartment> apartment; private Integer id; public RequestList() { } public RequestList(List<Apartment> apartment, Integer id) { this.apartment = apartment; this.id = id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public List<Apartment> getApartment() { return apartment; } public void setApartment(List<Apartment> apartment) { this.apartment = apartment; } }
三.spring boot中Jackson配置详解
- spring.jackson.date-format= 配置日期序列化和反序列化格式,
yyyy-MM-dd HH:mm:ss
. - spring.jackson.default-property-inclusion= 控制序列化期间包含的属性。配置了Jackson的JsonInclude.Include枚举中的一个值,若配置一般配置
non_null
表示序列化时忽略属性为null的值,always, non_null, non_absent, non_default, non_empty
- spring.jackson.deserialization.*= Jackson反序列化的开关,取值
true, false
- spring.jackson.generator.*= 开启关闭jackson的生成器,取值
true, false
- spring.jackson.joda-date-time-format= # 配置日期格式序列化为string的格式,不配置默认使用date-format配置
- spring.jackson.locale= 本地化配置
- spring.jackson.mapper.*= 开启或者关闭jackson,取值
true, false
- spring.jackson.parser.*= 开启关闭jsonson的解析器 ,取值
true, false
- spring.jackson.property-naming-strategy=配置json的key值和实体属性名称之间的转换关系,值一般为PropertyNamingStrategy类中常数或者实现PropertyNamingStrategy子类的全限定名
- spring.jackson.serialization.*= Jackson序列化的开关,取值
true, false
- spring.jackson.time-zone= 格式化日期时使用的时区。例如,“America / Los_Angeles”或“GMT + 10”
- spring.jackson.visibility.*= 修改实体类属性域的可见性
四.结尾
- 上篇文章从spring-boot中引申出了jackson这个杰出的json解析框架,详细的分析了Jackson提供的注解功能,以及它们在controller中的使用
- 这篇文章,介绍了ObjectMapper是如何序列化和反序列化json,以及Jackson在spring boot中的各项配置