【json的處理】(FastJson)
目錄:
首先先介紹一下兩個容易混淆的概念:
json物件:用 { } 表示的
例:{ "id":"123", "name":"張三", "age":"11"}
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
字元型別欄位如果為null,輸出為"",而非nullWriteNullStringAsEmpty
數值欄位如果為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);
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
持續更新!!!