前言:JSON 是輕量級的數據交換格式,很經常使用,尤爲是在使用 Ajax 時,在後臺將數據封裝爲 JSON 字符串更是常見。以前在作項目的時候用過幾種方式在後端將數組或 List 集合轉換爲 JSON 字符串,如今回想起來居然又有些遺忘。如今來一個彙總,把這幾種構建 JSON 字符串的方式完全回憶起來。html
----------------------------------------------------------------------------------------------------------------------------------------------------------java
筆記中提供了大量的代碼示例,須要說明的是,大部分代碼示例都是本人所敲代碼並進行測試,不足之處,請你們指正~ajax
如有疑惑或者須要本系列分享中的資料工具,敬請聯繫 qingqing_crawl@163.comjson
-----------------------------------------------------------------------------------------------------------------------------------------------------------後端
1.Fastjson 是一個以 Java 語言編寫的 JSON 處理器,由阿里巴巴公司開發,功能強大。數組
要使用第三方的工具固然要導入 jar 包了,只需導入 fastjson-1.2.8.jar 便可,jar 包的獲取,你們能夠直接去網上下載 ,也能夠聯繫本人。app
先來一個 fastjson 的簡單實例吧,以下代碼構造了一個 Customer 的實例,並將此實例轉化成爲 JSON 字符串,調用了 com.alibaba.fastjson.JSON 的 toJSONString() 方法,將 Customer 實例傳入ssh
@Test public void test1() { Customer customer = new Customer(); customer.setId(1); customer.setCustName("Tom"); customer.setAddress("BeiJing"); String jsonStr = JSON.toJSONString(customer); System.out.println(jsonStr); }
打印結果:{"address":"BeiJing","custName":"Tom","id":1}工具
再來一個小測試,將一個 List 的 Customer 的集合轉換爲 JSON 字符串,22 行仍是直接調用 JSON 的 toJSONString() 方法,將 List 集合傳入便可測試
1 /** 2 * 將 List 集合轉換爲 JSON 字符串 3 */ 4 @Test 5 public void test2() { 6 List<Customer> lists = new ArrayList<>(); 7 8 Customer customer = new Customer(); 9 customer.setId(1); 10 customer.setCustName("Tom"); 11 customer.setAddress("BeiJing"); 12 13 lists.add(customer); 14 15 Customer customer2 = new Customer(); 16 customer2.setId(1); 17 customer2.setCustName("Bob"); 18 customer2.setAddress("ShangHai"); 19 20 lists.add(customer2); 21 22 String jsonStr = JSON.toJSONString(lists); 23 System.out.println(jsonStr); 24 }
打印結果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}]
2. 深刻研究一下,咱們看下面這種狀況:3 行建立了一個 List 的 Customer 集合,10 和 11 行進行了一個重複的 add 操做,那麼打印結果是什麼樣的呢?
1 @Test 2 public void test3() { 3 List<Customer> lists = new ArrayList<>(); 4 5 Customer customer = new Customer(); 6 customer.setId(1); 7 customer.setCustName("Tom"); 8 customer.setAddress("BeiJing"); 9 10 lists.add(customer); 11 lists.add(customer); 12 13 String jsonStr = JSON.toJSONString(lists); 14 System.out.println(jsonStr); 15 16 }
打印結果:[{"address":"BeiJing","custName":"Tom","id":1},{"$ref":"$[0]"}],你們看,第二個 Customer 實例沒有打印出,這就證實了 fastjson 默認禁止循環的引用,若是想改變這種狀況,須要在 JSON 的 toJSONString() 方法中傳遞第二個參數 SerializerFeature.DisableCircularReferenceDetect 便可解決,以下:
1 @Test 2 public void test3() { 3 List<Customer> lists = new ArrayList<>(); 4 5 Customer customer = new Customer(); 6 customer.setId(1); 7 customer.setCustName("Tom"); 8 customer.setAddress("BeiJing"); 9 10 lists.add(customer); 11 lists.add(customer); 12 13 String jsonStr = JSON.toJSONString(lists, SerializerFeature.DisableCircularReferenceDetect); 14 System.out.println(jsonStr); 15 16 }
此時的打印結果爲:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"BeiJing","custName":"Tom","id":1}],建議之後再使用 JSON 的 toJSONString() 方法時將第二個參數添加上
3.再深刻一點,來看一個常見的問題,Department 和 Manager 類維護雙向一對一的關聯關係,Department 類中有 Manager 類的引用,Manager 類中有 Department 類的引用,來看以下代碼:在 11 和 12 行設置了關聯關係,14 行和 15 行進行 JSON 字符串的轉換,結果會怎樣呢?
1 @Test 2 public void test4() { 3 Manager mgr = new Manager(); 4 mgr.setMgrId(1); 5 mgr.setMgrName("Tom"); 6 7 Department dept = new Department(); 8 dept.setDeptId(2); 9 dept.setDeptName("DEV"); 10 11 mgr.setDept(dept); 12 dept.setManager(mgr); 13 14 String jsonStr = JSON.toJSONString(dept, SerializerFeature.DisableCircularReferenceDetect); 15 // String jsonStr = JSON.toJSONString(mgr, SerializerFeature.DisableCircularReferenceDetect); 16 System.out.println(jsonStr); 17 }
答案是,拋出了異常,常見的 java.lang.StackOverflowError,拋異常的緣由是雙方都維護關聯關係進入了死循環,那麼如何解決這個問題呢?能夠在一方添加 @JSONField(serialize=false) 註解,7 行所示,便可解決
1 public class Department { 2 3 private Integer deptId; 4 5 private String deptName; 6 7 @JSONField(serialize=false) 8 private Manager manager; 9 10 public Integer getDeptId() { 11 return deptId; 12 } 13 14 public void setDeptId(Integer deptId) { 15 this.deptId = deptId; 16 } 17 18 public String getDeptName() { 19 return deptName; 20 } 21 22 public void setDeptName(String deptName) { 23 this.deptName = deptName; 24 } 25 26 public Manager getManager() { 27 return manager; 28 } 29 30 public void setManager(Manager manager) { 31 this.manager = manager; 32 } 33 34 }
打印結果爲:{"dept":{"deptId":2,"deptName":"DEV"},"mgrId":1,"mgrName":"Tom"},結果也很使人滿意。
4.最後提供一個 fastjson 的工具類,開發時能夠直接使用,供你們參考
1 package qi.ssh.utils; 2 3 import java.io.IOException; 4 import java.util.Date; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import javax.servlet.http.HttpServletResponse; 9 10 import com.alibaba.fastjson.JSON; 11 import com.alibaba.fastjson.serializer.SerializerFeature; 12 13 public class FastJsonUtil { 14 15 /** 16 * 將對象轉成json串 17 * @param object 18 * @return 19 */ 20 public static String toJSONString(Object object){ 21 //DisableCircularReferenceDetect來禁止循環引用檢測 22 return JSON.toJSONString(object,SerializerFeature.DisableCircularReferenceDetect); 23 } 24 25 //輸出json 26 public static void write_json(HttpServletResponse response,String jsonString) 27 { 28 response.setContentType("application/json;utf-8"); 29 response.setCharacterEncoding("UTF-8"); 30 try { 31 response.getWriter().print(jsonString); 32 } catch (IOException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } 36 } 37 /** 38 * ajax提交後回調的json字符串 39 * @return 40 */ 41 public static String ajaxResult(boolean success,String message) 42 { 43 Map map=new HashMap(); 44 map.put("success", success);//是否成功 45 map.put("message", message);//文本消息 46 String json= JSON.toJSONString(map); 47 return json; 48 } 49 50 51 /** 52 * JSON串自動加前綴 53 * @param json 原json字符串 54 * @param prefix 前綴 55 * @return 加前綴後的字符串 56 */ 57 58 public static String JsonFormatterAddPrefix(String json,String prefix,Map<String,Object> newmap) 59 { 60 if(newmap == null){ 61 newmap = new HashMap(); 62 } 63 Map<String,Object> map = (Map) JSON.parse(json); 64 65 for(String key:map.keySet()) 66 { 67 Object object=map.get(key); 68 if(isEntity(object)){ 69 String jsonString = JSON.toJSONString(object); 70 JsonFormatterAddPrefix(jsonString,prefix+key+".",newmap); 71 72 }else{ 73 newmap.put(prefix+key, object); 74 } 75 76 } 77 return JSON.toJSONString(newmap); 78 } 79 /** 80 * 判斷某對象是否是實體 81 * @param object 82 * @return 83 */ 84 private static boolean isEntity(Object object) 85 { 86 if(object instanceof String ) 87 { 88 return false; 89 } 90 if(object instanceof Integer ) 91 { 92 return false; 93 } 94 if(object instanceof Long ) 95 { 96 return false; 97 } 98 if(object instanceof java.math.BigDecimal ) 99 { 100 return false; 101 } 102 if(object instanceof Date ) 103 { 104 return false; 105 } 106 if(object instanceof java.util.Collection ) 107 { 108 return false; 109 } 110 return true; 111 112 } 113 }
1.一樣也須要導入 jar 包,Jackson 導入的 jar 包有三個
具體使用也經過一個小例子說明:
1 package com.software.jackson; 2 3 import java.util.Arrays; 4 import java.util.List; 5 6 import com.fasterxml.jackson.annotation.JsonIgnore; 7 import com.fasterxml.jackson.core.JsonProcessingException; 8 import com.fasterxml.jackson.databind.ObjectMapper; 9 10 public class Customer { 11 12 private int id; 13 14 private String name; 15 16 public Customer(int id, String name) { 17 super(); 18 this.id = id; 19 this.name = name; 20 } 21 22 public int getId() { 23 return id; 24 } 25 26 public void setId(int id) { 27 this.id = id; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 38 public String getCity(){ 39 return "BeiJing"; 40 } 41 42 @JsonIgnore 43 public String getSchool(){ 44 return "School"; 45 } 46 47 public static void main(String[] args) throws JsonProcessingException { 48 //建立ObjectMapper對象 49 ObjectMapper mapper = new ObjectMapper(); 50 51 Customer customer = new Customer(1, "Tom"); 52 List<Customer> lists = Arrays.asList(customer, new Customer(2, "Bob")); 53 54 //調用 ObjectMapper 的 writeValueAsString(xxx) 方法,把一個對象或幾個傳入,轉爲一個 JSON 字符串 55 String jsonStr = mapper.writeValueAsString(lists); 56 System.out.println(jsonStr); 57 58 } 59 60 }
定義了一個 Customer 類,38 行和 43 行定義了兩個額外的 get 方法並直接賦值,main 方法中建立 ObjectMapper 的對象,調用其 writeValueAsString() 方法,傳入單個對象或對象的集合,便會返回對應的 JSON 字符串,打印結果爲:[{"id":1,"name":"Tom","city":"BeiJing"},{"id":2,"name":"Bob","city":"BeiJing"}],你們可能會發現,咱們 43 行定義的 getSchool() 方法中的 School 沒有被打印出,這是由於咱們在此方法上添加了 @JsonIgnore 註解,添加了此註解,在構造 JSON 字符串時便忽略此屬性,細想一下 ,此註解添加到 get 方法上,這也說明 Jackson 構造 JSON 字符串時基於 getter 方法的。
2.與以前同樣,咱們想看一看 Jackson 有沒有禁止循環的引用,相似的代碼:
1 @Test 2 public void test2() throws JsonProcessingException { 3 List<Customer> lists = new ArrayList<>(); 4 5 Customer customer = new Customer(); 6 customer.setId(1); 7 customer.setCustName("Tom"); 8 customer.setAddress("BeiJing"); 9 10 lists.add(customer); 11 lists.add(customer); 12 13 ObjectMapper mapper = new ObjectMapper(); 14 String jsonStr = mapper.writeValueAsString(lists); 15 System.out.println(jsonStr); 16 }
來看一下輸出結果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],結果顯而易見。
3.咱們再來看一看若是像 Fastjson 中測試的 Department 和 Manager 雙向一對一映射的例子,Jackson 會表現的怎麼樣:
1 @Test 2 public void test1() throws JsonProcessingException { 3 Manager mgr = new Manager(); 4 mgr.setMgrId(1); 5 mgr.setMgrName("Tom"); 6 7 Department dept = new Department(); 8 dept.setDeptId(2); 9 dept.setDeptName("DEV"); 10 11 mgr.setDept(dept); 12 dept.setManager(mgr); 13 14 ObjectMapper mapper = new ObjectMapper(); 15 String jsonStr = mapper.writeValueAsString(dept); 16 System.out.println(jsonStr); 17 }
直接運行仍是會出相同的異常 Caused by: java.lang.StackOverflowError,咱們的思路與測試 Fastjson 同樣,爲 Department 中的 Manager 引用添加 @JsonIgnore 註解,異常解決了,但打印結果是很滿意,結果爲:{"deptId":2,"deptName":"DEV"} ,遠不如 Fastjson 的輸出結果。由此能夠看出 Fastjson 功能之強大。
1.看看如何使用:jar 包呢只須要一個 gson-2.2.4.jar ,普通對象與集合轉爲 JSON 沒有什麼可說的,簡單演示一下將 List 集合轉爲 JSON 字符串吧,直接 new 出 Gson 的對象,調用其 toJson() 方法傳入須要轉換的對象便可。
1 @Test 2 public void test2() { 3 List<Customer> lists = new ArrayList<>(); 4 5 Customer customer = new Customer(); 6 customer.setId(1); 7 customer.setCustName("Tom"); 8 customer.setAddress("BeiJing"); 9 10 lists.add(customer); 11 12 Customer customer2 = new Customer(); 13 customer2.setId(1); 14 customer2.setCustName("Bob"); 15 customer2.setAddress("ShangHai"); 16 17 lists.add(customer2); 18 19 Gson gson = new Gson(); 20 String jsonStr = gson.toJson(lists); 21 System.out.println(jsonStr); 22 }
打印結果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}]
2. 那有沒有禁止循環引用呢?
1 @Test 2 public void test3() { 3 List<Customer> lists = new ArrayList<>(); 4 5 Customer customer = new Customer(); 6 customer.setId(1); 7 customer.setCustName("Tom"); 8 customer.setAddress("BeiJing"); 9 10 lists.add(customer); 11 lists.add(customer); 12 13 Gson gson = new Gson(); 14 String jsonStr = gson.toJson(lists); 15 System.out.println(jsonStr); 16 17 }
輸出結果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],顯而易見是沒有的。
3.如有雙向一對一的關聯關係映射的話,Google Gson 也是會有死循環問題形成 java.lang.StackOverflowError 異常,可是 Gson 並無爲咱們提供一個註解,要解決此問題樓主提供一個解決方案的思路,Google Gson 使用的是 ExclusionStrategy 策略進行某個字段或某個域的序列化,能夠經過此接口自定義一個 註解來解決此問題。可是建議你們若是涉及到雙向關聯關係的對象轉換爲 JSON 的需求是,使用 Fastjson。
樓主從如下幾個方面來比較構造 JSON 字符串的三種方式:
1. jar 包方面:顯然是 Fastjson 和 Google Gson 勝出,Jackson 須要加入 3 個 jar 包。
2. 簡單對象或集合轉爲 JSON:如果普通的簡單對象或集合進行轉換,可能 Jackson 和 Google Gson 要勝出一些了,起碼構造比較方便。
3. 涉及到雙向關聯關係的轉換:毫無疑問阿里巴巴的 Fastjson 將勝出。
建議你們在實際的開發中根據本身的需求合理選擇某一方式。