目前处理json的方法有很多,这里主要总结四种方法

1. Gson方式处理json 【json的处理】一、Gson处理

2. FastJson方式处理json 【json的处理】三、FastJson的处理

3. Jackson方式处理json 【json的处理】二、Jackson的处理

4. json-flattener方式处理json 【json的处理】四、json-flattener的处理

本文主要介绍FastJson的方式

下面主要通过几个方面来介绍fastjson:

1. JsonObject

2. JsonArray

3. JsonObject+JsonArray

首先先介绍一下两个容易混淆的概念:

json对象:用 { } 表示的

例:{ "id":"123", "name":"张三", "age":"11"}

json数组:由多个json对象组成,用 [ ] 表示的

例:[{ "id":"123", "name":"张三", "age":"11"},{ "id":"321", "name":"李四", "age":"21"}]

需要引入依赖

<!-- fastjson的依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.44</version>
</dependency>

一、JsonObject

这里先提及两个概念:

序列化:json对象转字符串

反序列化:字符串转json对象

1. 基本用法

//定义一个json对象用来演示
String str = "{ \"id\":\"123\", \"name\":\"张三\", \"age\":\"11\"}";
//【字符串转json对象】
JSONObject jsonObject = JSONObject.parseObject(str);
//【json对象转字符串】
String strTemp = jsonObject.toJSONString();
//【json对象中是否包含某个key】
boolean isHasKey = jsonObject.containsKey("na");
//【json对象中是否包含某个值】
boolean isHasValue = jsonObject.containsValue("123");
//【获取json对象中某个键对应的值】
Object id = jsonObject.get("id");
//【json对象转set】
Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
//【json对象转Map】
Map<String, String> params = JSONObject.parseObject(jsonObject.toJSONString(), new TypeReference<Map<String, String>>(){});
//【Map转json对象】
String jsonStr_Map = JSONUtils.toJSONString(params);
JSONObject jsonObjectTemp = JSONObject.parseObject(jsonStr_Map);
//【遍历json对象中的所有键值对】
for (Map.Entry<String,Object> entry : jsonObject.entrySet()){
    String key = entry.getKey();
    Object value = entry.getValue();
    System.out.println("key="+key+" value="+value);

2. 高级用法

2.1 实体类与json之间的转换

//实体类
@Data
@AllArgsConstructor
public class TestUser {
    private String name;
    private Integer age;
    private Integer sex;
//测试类
//定义一个实体类对象用来演示
TestUser testUser = new TestUser("111",11,1);
//【实体类转json】
JSONObject jsonObj = (JSONObject)JSONObject.toJSON(testUser);
//结果:{"sex":1,"name":"111","age":11}
System.out.println(jsonObj);
//【json转实体类】 反序列化
TestUser testUserTemp = JSONObject.parseObject(jsonObj.toJSONString(), TestUser.class);
//结果:TestUser(name=111, age=11, sex=1)
System.out.println(testUserTemp);
//这里补充一个  list对象转json 
//如果有值为null,会导致这个key都被默认去掉,需要加上SerializerFeature.WriteMapNullValue 
List<User> list = new ArrayList<>();
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(list,SerializerFeature.WriteMapNullValue))
名称含义 QuoteFieldNames 输出key时是否使用双引号,默认为true UseSingleQuotes 使用单引号而不是双引号,默认为false WriteMapNullValue 是否输出值为null的字段,默认为false WriteEnumUsingToString Enum输出name()或者original,默认为false UseISO8601DateFormat Date使用ISO8601格式输出,默认为false WriteNullListAsEmpty List字段如果为null,输出为[],而非null WriteNullStringAsEmpty 字符类型字段如果为null,输出为”“,而非null WriteNullNumberAsZero 数值字段如果为null,输出为0,而非null WriteNullBooleanAsFalse Boolean字段如果为null,输出为false,而非null SkipTransientField 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true SortField 按字段名称排序后输出。默认为false WriteTabAsSpecial 把\t做转义输出,默认为false 不推荐 PrettyFormat 结果是否格式化,默认为false WriteClassName 序列化时写入类型信息,默认为false。反序列化是需用到 DisableCircularReferenceDetect 消除对同一对象循环引用的问题,默认为false WriteSlashAsSpecial 对斜杠’/’进行转义 BrowserCompatible 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE6,默认为false WriteDateUseDateFormat 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj,SerializerFeature.WriteDateUseDateFormat); DisableCheckSpecialChar 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false NotWriteRootClassName BeanToArray 将对象转为array输出 WriteNonStringKeyAsString NotWriteDefaultValue BrowserSecure IgnoreNonFieldGetter WriteEnumUsingName

2.2 JSONField注解

那么如果我想要在实体类转json的时候,排除掉某些字段该怎么做呢?

使用@JSONField(serialize = false) 注解。

(是否参与序列化,false代表该字段不输出,但是如果加了final,这个字段就无法被过滤)

修改后的效果如下:

@Data
@AllArgsConstructor
public class TestUser {
    @JSONField(serialize = false)
    private String name;
    private Integer age;
    private Integer sex;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser("111",11,1);
//【实体类转json】
JSONObject jsonObj = (JSONObject)JSONObject.toJSON(testUser);
//结果:{"sex":1,"age":11}
System.out.println(jsonObj);
//【json转实体类】 反序列化
TestUser testUserTemp = JSONObject.parseObject(jsonObj.toJSONString(), TestUser.class);
//结果:TestUser(name=null, age=11, sex=1)
System.out.println(testUserTemp);

那么如果我想要在实体类转json的时候,不使用实体类中的名称该如何做呢?

使用@JSONField(name = "别名") 注解。

使用字段别名,效果如下:

@Data
@AllArgsConstructor
public class TestUser {
    @JSONField(name = "t_name")
    private String name;
    private Integer age;
    private Integer sex;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser("111",11,1);
//【实体类转json】
JSONObject jsonObj = (JSONObject)JSONObject.toJSON(testUser);
//结果:{"t_name":"111","sex":1,"age":11}
System.out.println(jsonObj);
//【json转实体类】 反序列化
TestUser testUserTemp = JSONObject.parseObject(jsonObj.toJSONString(), TestUser.class);
//结果:TestUser(name=111, age=11, sex=1)
System.out.println(testUserTemp);

那么如果现在有个时间类型的字段,我想要以固定的格式输出,该怎么办呢?

使用@JSONField(format="yyyy-MM-dd HH:mm:ss") 注解。

下面先添加一个时间字段date,看看添加前后的效果:

@Data
@AllArgsConstructor
public class TestUser {
    private String name;
    private Integer age;
    private Integer sex;
    @JSONField(format="yyyy-MM-dd HH:mm:ss")
    private Date date;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser("111",11,1,new Date());
//【实体类转json】
JSONObject jsonObj = (JSONObject)JSONObject.toJSON(testUser);
//添加前结果:{"date":1600485884579,"sex":1,"name":"111","age":11}
//添加后结果:{"date":"2020-09-19 11:25:46","sex":1,"name":"111","age":11}
System.out.println(jsonObj);
//【json转实体类】 反序列化
TestUser testUserTemp = JSONObject.parseObject(jsonObj.toJSONString(), TestUser.class);
//添加前结果:TestUser(name=111, age=11, sex=1, date=Sat Sep 19 11:24:44 CST 2020)
//添加后结果:TestUser(name=111, age=11, sex=1, date=Sat Sep 19 11:25:46 CST 2020)
System.out.println(testUserTemp);

那么如果某个字段的值是null,在序列化的时候,可以看到生成的字符串中没有对应的key,那么我想要实现,如果值为空,给其一个默认值:

这里要提及一个知识:SerializerFeature属性,下面列举几个,详细的可以去查api

参考:https://www.cnblogs.com/wbxk/p/10064737.html

字符类型字段如果为null,输出为"",而非null WriteNullStringAsEmpty

数值字段如果为null,输出为0,而非null WriteNullNumberAsZero

Boolean字段如果为null,输出为false,而非null WriteNullBooleanAsFalse

List字段如果为null,输出为[],而非null WriteNullListAsEmpty

@Data
@AllArgsConstructor
public class TestUser {
    @JSONField(serialzeFeatures=SerializerFeature.WriteNullStringAsEmpty)
    private String name;
    private Integer age;
    private Integer sex;
    @JSONField(format="yyyy-MM-dd HH:mm:ss")
    private Date date;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser(null,11,1,new Date());
String jsonStr = JSON.toJSONString(testUser);
//加注解前:{"age":11,"date":"2020-09-19 12:49:07","sex":1}
//加注解后:{"age":11,"date":"2020-09-19 12:48:28","name":"","sex":1}
System.out.println(jsonStr);

现在想要将json对象转换成实体类对象,方法如下:

@Data
public class TestUser {
    private String name;
    private Integer age;
    private Integer sex;
    private Date date;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser();
testUser.setName("11");
testUser.setAge(11);
testUser.setSex(1);
String jsonStr = JSON.toJSONString(testUser);
//实体类转成json对象
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
//【json对象转成实体类】
TestUser testUserTemp = JSON.toJavaObject(jsonObject, TestUser.class);
//结果:TestUser(name=11, age=11, sex=1, date=null)
System.out.println(testUserTemp);

这里要注意:上面的例子里我都是用的@AllArgsConstructor来方便我创建实体类数据,但是我发现如果加上了这个注解,在使用toJavaObject方法的时候会报错。不使用这个注解没有问题。报错信息如下:

网上搜的结果为:

实体类中存在内嵌的其它类,将内部类修改为静态内部类即可,但是我这里也没有发现有内部类的字段,于是我尝试将Date类型的屏蔽,结果成功了,暂时还没有想清楚是什么问题

//报错代码如下
@Data
@AllArgsConstructor
public class TestUser {
    private String name;
    private Integer age;
    private Integer sex;
    private Date date;
//定义一个实体类对象用来演示
TestUser testUser = new TestUser("111",11,1,new Date());
String jsonStr = JSON.toJSONString(testUser);
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
TestUser testUserTemp = JSON.toJavaObject(jsonObject, TestUser.class);

二、 JsonArray

JsonArray:即json数组,由多个json对象(jsonObject)组成

//定义一个json数组类型的字符串用来演示
String jsonstr = "[{\"sex\":\"1\",\"name\":\"111\",\"age\":\"11\"},{\"sex\":\"0\", \"name\":\"222\",\"age\":\"21\"}]";
//【String转jsonArray】
JSONArray jsonArray = JSONArray.parseArray(jsonstr);
//【jsonArray转String】
String jsonstrTemp = JSON.toJSONString(jsonArray);
//【jsonArray转list】
List list = JSONObject.parseArray(jsonArray.toJSONString());
//【jsonArray转list-->对象】
List<TestUser> testUsers = JSONObject.parseArray(jsonArray.toJSONString(), TestUser.class);
//【list转jsonArray】
List listTemp = new ArrayList();
JSONArray array = JSONArray.parseArray(JSON.toJSONString(listTemp));
//【list转jsonArray--->对象】
List<TestUser> testUserList = new ArrayList<>();
JSONArray array1 = JSONArray.parseArray(JSON.toJSONString(listTemp));
//【String转List】
List<TestUser> testUserList1 = JSONObject.parseArray(jsonstr, TestUser.class);
//【循环获取jsonArray中所有的jsonObject】
for (int i = 0; i < jsonArray.size(); i++) {
    JSONObject jsonObject = jsonArray.getJSONObject(i);
    String id = jsonObject.getString("sex");
    String name = jsonObject.getString("name");
    //这里要注意:age字段也可以用getString方法来获取
    Integer age = jsonObject.getInteger("age");

三、JsonObject+JsonArray

如何判断一个不确定格式的json串,每个key对应的类型呢?

//【判断json类型】
String text0 = "11";
String text2 = "{ \"sex\":\"1\", \"name\":\"张三\", \"age\":\"11\"}";
String text3 = "[{ \"sex\":\"1\", \"name\":\"张三\", \"age\":\"11\"},{ \"sex\":\"0\", \"name\":\"李四\", \"age\":\"21\"}]";
Object parse0 = JSON.parse(text0);
System.out.println(parse0 instanceof java.lang.Integer);//true
Object parse2 = JSON.parse(text2);
System.out.println(parse2 instanceof JSONObject);//true
Object parse3 = JSON.parse(text3);
System.out.println(parse3 instanceof JSONArray);//true