1. 程式人生 > 實用技巧 >【json的處理】(FastJson)

【json的處理】(FastJson)

目錄:

首先先介紹一下兩個容易混淆的概念:

  1. json物件:用 { } 表示的

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

  2. json陣列:由多個json物件組成,用 [ ] 表示的

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

FastJson的依賴

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

1. JsonObject

這裡先提及兩個概念:

序列化:json物件轉字串

反序列化:字串轉json物件

1.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); }

1.2 高階用法

1.2.1 實體類和json之間的轉換

首先建立一個實體類TestUser用做測試,內容如下:

@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 含義

1.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

  1. 字元型別欄位如果為null,輸出為"",而非nullWriteNullStringAsEmpty

  2. 數值欄位如果為null,輸出為0,而非null WriteNullNumberAsZero

  3. Boolean欄位如果為null,輸出為false,而非null WriteNullBooleanAsFalse

  4. 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);

2. 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");
}

3. 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

持續更新!!!