1.拼接復雜嵌套json
FastJson工具包中有兩主要的類: JSONObject和JSONArray ,前者表示json對象,后者表示json數組。他們兩者都能添加Object類型的對象,但是JSONArray沒有put()方法,只有add()方法。這與json數組的定義有關,json數組只能添加元素,而不能添加鍵值對。而JSONObject因為是一個對象,不能容納其他對象,不能添加對象,沒有add() 方法,它就只有put()方法來添加鍵值對。JSONObject和JSONArray 似乎只能兩選一,要么用JSONObject的put()方法添加一個鍵值對,或使用JSONArray的add()方法添加一個元素。實際上是可以兩者兼顧的,JSONObect的put(String key,Object value)方法中值參數value是Object類型,那么這個數據類型也就可以是JSONArray類型。這樣的話,就可以在json對象中添加json數組中,從而輕松地拼接復雜的嵌套型的son數據。
如果要返回如下格式的json數據,常規的手工拼接將非常難以實現,且容易出錯。

1).首先從最內層開始分析,最內層是兩個json對象,{item": "目錄管理","url": "/system/menu/toMain"},這個json對象有相應的實體類AdminMenu,而外層是一個json數組將這兩個對象包含進去。
AdminMenu menu1 = new AdminMenu(); menu1.setUrl("/system/menu/toMain"); menu1.setName("目錄管理");//通過"getItem(){ return name}",所以只設置setName即可 AdminMenu menu2 = new AdminMenu(); menu2.setUrl("/system/user/toMain"); menu2.setName("用戶管理"); JSONArray level2Array = new JSONArray(); //將兩個實體類添加一json數據中,FastJson會將實體類自動轉為json對象 level2Array.add(menu1); level2Array.add(menu2);
2).然后分析Level2(json數據)和Level1(鍵值對)又是一個匿名json對象的兩個屬性,把這兩個屬性添加到json對象中。
JSONObject menuInfoElement = new JSONObject(); menuInfoElement.put("Level2", level2Array); menuInfoElement.put("Level1", "系統管理");
3)再然后分析那個匿名json對象menuInfoElement是json數組menuInfo的唯一的一個元素,那么將匿名json對象menuInfoElement添加到menuInfo數組中。
JSONArray menuInfoArray = new JSONArray(); menuInfoArray.add(menuInfoElement);
4)再分析,menuInfo是json對象content的一個屬性
JSONObject contentObj = new JSONObject(); contentObj.put("menuInfo", menuInfoArray);
5)最終,將'status' 'content' 'message'作為最終返回的json對象的屬性
JSONObject jsonMainObj = new JSONObject(); jsonMainObj.put("status", "success"); jsonMainObj.put("message", "查詢成功"); jsonMainObj.put("content", contentObj);
測試代碼
@Test public void testJson1() { AdminMenu menu1 = new AdminMenu(); menu1.setUrl("/system/menu/toMain"); menu1.setName("目錄管理");//通過"getItem(){ return name}",所以只設置setName即可 AdminMenu menu2 = new AdminMenu(); menu2.setUrl("/system/user/toMain"); menu2.setName("用戶管理"); JSONArray level2Array = new JSONArray(); //將兩個實體類添加一json數據中,FastJson會將實體類自動轉為json對象 level2Array.add(menu1); level2Array.add(menu2); JSONObject menuInfoElement = new JSONObject(); menuInfoElement.put("Level2", level2Array); menuInfoElement.put("Level1", "系統管理"); JSONArray menuInfoArray = new JSONArray(); menuInfoArray.add(menuInfoElement); JSONObject contentObj = new JSONObject(); contentObj.put("menuInfo", menuInfoArray); JSONObject jsonMainObj = new JSONObject(); jsonMainObj.put("status", "success"); jsonMainObj.put("message", "查詢成功"); jsonMainObj.put("content", contentObj); System.out.println(jsonMainObj.toJSONString()); }
輸出的字符串
{"message":"查詢成功",
"content":{"menuInfo":[{"Level2":[{"item":"目錄管理","name":"目錄管理","url":"/system/menu/toMain"},
{"item":"用戶管理","name":"用戶管理","url":"/system/user/toMain"}],
"Level1":"系統管理"}]},
"status":"success"}
2.不依賴實體類,直接從json格式字符串中解析出鍵值對
JSONObject 有 parseObject(String text, Class<T> clazz) 靜態方法,將json字符串解析成T類型的java對象;而 JSONArray也有parseArray(String text, Class<T> clazz) 將json字符串解析成List<T>的集合對象。
但它們都需要傳入一個Class對象作為參數,換句話說,必須先有一個Class對應的實體類,而很多時候我們只會將其中的鍵值對解析出來用一次,只臨時使用它一次就去創建一個新的實體類,將會導致類爆炸。
換種思路,JSONArray.parseArray(String text)將返回一個JSONArray對象。根據其add(Object obj)的方法入參類型是Object,那么其元素類型可能是一個實體類也可能是一個普通的json對象JSONObject,。但當前我們調用parseArray(String text)靜態方法傳入了的一個json字符串,以此構建出一個json數組,那么可以肯定其內部的元素類型一定是JSONObject,因此將其中的每個元素從Object強制轉換為JSONObject類型,然后再從每個JSONObject取出鍵值對。
@Test public void parseJsonText() { String menuList = "[{'id':1,'locked':false,'loginedTime':'2014-01-21'}," + "{'id':2,'locked':true,'loginedTime':'2015-03-22'},]"; /* * 有屬性名與之對應的User類,則可以寫成這種形式,但目前並不存在User類, * 所以無法實現 List<User> uList=JSONArray.parseArray(menuList, User.class); */ JSONArray jUsers = JSONArray.parseArray(menuList); /** * 這個for循環也可以 * for(int i=0;i<jUsers.size();i++){ JSONObject user=jUsers.getJSONObject(i); } */ for (Object userObj : jUsers) { JSONObject jUser = (JSONObject)userObj; // 強制類型轉換,因為知道其元素的具體類型是JSONObject,那么就不會出錯 /** * {'id':1}鍵值對的值1沒加引號,FastJson認為它是數字, * 如果是{'id':'1'}格式,FastJson認為它是字符串,轉換為Integer將出錯 */ Integer id = (Integer)jUser.get("id"); /* * {'locked':false}鍵值對的值沒加引號,FastJson視作boolean類型, * 如果是{'locked':'false'}格式,FastJson視作String類型,強制轉換為boolean將運行時出錯 * */ boolean locked = (boolean)jUser.get("locked"); String loginTime = (String)jUser.get("loginedTime"); System.out.println("用戶id:" + id + " ,鎖定了嗎? " + locked + " 登錄時間:" + loginTime); } }
結果輸出

另外需要注意,前端語言JavaScript是弱類型語言,它可以根據變量具體的值去推斷其類型,而JAVA是強類型語言,對字符串和數字有着明確的區分。
前端的{'id',23}和{'id','23'}沒有區別,但FastJson解析對這兩種格式有明顯的不同,前者鍵值對沒有引號的值(23)視為數字,后者鍵值對有引號的值('23')視作字符串。
@Test public void parseJsonError() { String menuList = "[{'id':1,'locked':false,'loginedTime':'2014-01-21'}," + "{'id':2,'locked':true,'loginedTime':'2015-03-22'},]"; JSONArray jUsers = JSONArray.parseArray(menuList); try{ for (Object userObj : jUsers) { JSONObject jUser = (JSONObject)userObj; // 強制類型轉換,因為知道其元素的具體類型是JSONObject,那么就不會出錯 String id = (String)jUser.get("id");//將出錯 String locked = (String)jUser.get("locked");//將出錯 String loginTime = (String)jUser.get("loginedTime"); System.out.println("用戶id:" + id + " ,鎖定了嗎? " + locked + " 登錄時間:" + loginTime); } }catch(Exception e){ e.printStackTrace(); } }
控制台提示類型轉換異常

