gpt4 book ai didi

深入剖析构建JSON字符串的三种方式(推荐)

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 25 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章深入剖析构建JSON字符串的三种方式(推荐)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax 时,在后台将数据封装为 JSON 字符串更是常见。之前在做项目的时候用过几种方式在后端将数组或 List 集合转换为 JSON 字符串,现在回想起来竟然又有些遗忘。现在来一个汇总,把这几种构建 JSON 字符串的方式彻底回忆起来.

笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,不足之处,请大家指正~ 。

1、alibaba 的 Fastjson 。

1.Fastjson 是一个以 Java 语言编写的 JSON 处理器,由阿里巴巴公司开发,功能强大.

要使用第三方的工具当然要导入 jar 包了,只需导入 fastjson-1.2.8.jar 即可,jar 包的获取,大家可以直接去网上下载 ,也可以联系本人.

先来一个 fastjson 的简单实例吧,如下代码构造了一个 Customer 的实例,并将此实例转化成为 JSON 字符串,调用了 com.alibaba.fastjson.JSON 的 toJSONString() 方法,将 Customer 实例传入 。

?
1
2
3
4
5
6
7
8
9
10
11
@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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 将 List 集合转换为 JSON 字符串
*/
@Test
public void test2() {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
 
  Customer customer2 = new Customer();
  customer2.setId(1);
  customer2.setCustName("Bob");
  customer2.setAddress("ShangHai");
 
  lists.add(customer2);
 
  String jsonStr = JSON.toJSONString(lists);
  System.out.println(jsonStr);
}

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}] 。

2. 深入研究一下,我们看下面这种情况:3 行创建了一个 List 的 Customer 集合,10 和 11 行进行了一个重复的 add 操作,那么打印结果是什么样的呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test3() {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
  lists.add(customer);
 
  String jsonStr = JSON.toJSONString(lists);
  System.out.println(jsonStr);
 
}

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"$ref":"$[0]"}],大家看,第二个 Customer 实例没有打印出,这就证明了 fastjson 默认禁止循环的引用,如果想改变这种情况,需要在 JSON 的 toJSONString() 方法中传递第二个参数 SerializerFeature.DisableCircularReferenceDetect 即可解决,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test3() {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
  lists.add(customer);
 
  String jsonStr = JSON.toJSONString(lists, SerializerFeature.DisableCircularReferenceDetect);
  System.out.println(jsonStr);
 
}

此时的打印结果为:[{"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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  @Test
  public void test4() {
  Manager mgr = new Manager();
  mgr.setMgrId(1);
  mgr.setMgrName("Tom");
 
  Department dept = new Department();
  dept.setDeptId(2);
  dept.setDeptName("DEV");
 
  mgr.setDept(dept);
  dept.setManager(mgr);
 
  String jsonStr = JSON.toJSONString(dept, SerializerFeature.DisableCircularReferenceDetect);
// String jsonStr = JSON.toJSONString(mgr, SerializerFeature.DisableCircularReferenceDetect);
  System.out.println(jsonStr);
  }

答案是,抛出了异常,常见的 java.lang.StackOverflowError,抛异常的原因是双方都维护关联关系进入了死循环,那么如何解决这个问题呢?可以在一方添加 @JSONField(serialize=false) 注解,7 行所示,即可解决 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Department {
 
  private Integer deptId;
 
  private String deptName;
 
  @JSONField(serialize=false)
  private Manager manager;
 
  public Integer getDeptId() {
  return deptId;
  }
 
  public void setDeptId(Integer deptId) {
  this.deptId = deptId;
  }
 
  public String getDeptName() {
  return deptName;
  }
 
  public void setDeptName(String deptName) {
  this.deptName = deptName;
  }
 
  public Manager getManager() {
  return manager;
  }
 
  public void setManager(Manager manager) {
  this.manager = manager;
  }
 
}

打印结果为:{"dept":{"deptId":2,"deptName":"DEV"},"mgrId":1,"mgrName":"Tom"},结果也很令人满意.

4.最后提供一个 fastjson 的工具类,开发时可以直接使用,供大家参考 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package qi.ssh.utils;
 
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.http.HttpServletResponse;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
 
public class FastJsonUtil {
 
  /**
  * 将对象转成json串
  * @param object
  * @return
  */
  public static String toJSONString(Object object){
  //DisableCircularReferenceDetect来禁止循环引用检测
  return JSON.toJSONString(object,SerializerFeature.DisableCircularReferenceDetect);
  }
 
  //输出json
  public static void write_json(HttpServletResponse response,String jsonString)
  {
  response.setContentType("application/json;utf-8");
  response.setCharacterEncoding("UTF-8");
  try {
   response.getWriter().print(jsonString);
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  }
  /**
  * ajax提交后回调的json字符串
  * @return
  */
  public static String ajaxResult(boolean success,String message)
  {
  Map map=new HashMap();
  map.put("success", success);//是否成功
  map.put("message", message);//文本消息
  String json= JSON.toJSONString(map);
  return json;
  }
 
 
  /**
  * JSON串自动加前缀
  * @param json 原json字符串
  * @param prefix 前缀
  * @return 加前缀后的字符串
  */
 
  public static String JsonFormatterAddPrefix(String json,String prefix,Map< String ,Object> newmap)
  {
  if(newmap == null){
   newmap = new HashMap();
  }
  Map< String ,Object> map = (Map) JSON.parse(json);
 
  for(String key:map.keySet())
  {
   Object object=map.get(key);
   if(isEntity(object)){
   String jsonString = JSON.toJSONString(object);
   JsonFormatterAddPrefix(jsonString,prefix+key+".",newmap);
  
   }else{
   newmap.put(prefix+key, object);
   }
  
  }
  return JSON.toJSONString(newmap);
  }
  /**
  * 判断某对象是不是实体
  * @param object
  * @return
  */
  private static boolean isEntity(Object object)
  {
  if(object instanceof String )
  {
   return false;
  }
  if(object instanceof Integer )
  {
   return false;
  }
  if(object instanceof Long )
  {
   return false;
  }
  if(object instanceof java.math.BigDecimal )
  {
   return false;
  }
  if(object instanceof Date )
  {
   return false;
  }
  if(object instanceof java.util.Collection )
  {
   return false;
  }
  return true;
 
  }
}

2、Jackson 。

1.同样也需要导入 jar 包,Jackson 导入的 jar 包有三个 。

深入剖析构建JSON字符串的三种方式(推荐)

具体使用也通过一个小例子说明:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.software.jackson;
 
import java.util.Arrays;
import java.util.List;
 
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
 
public class Customer {
 
  private int id;
 
  private String name;
 
  public Customer(int id, String name) {
   super();
   this.id = id;
   this.name = name;
  }
 
  public int getId() {
   return id;
  }
 
  public void setId(int id) {
   this.id = id;
  }
 
  public String getName() {
   return name;
  }
 
  public void setName(String name) {
   this.name = name;
  }
 
  public String getCity(){
   return "BeiJing";
  }
 
  @JsonIgnore
  public String getSchool(){
   return "School";
  }
 
  public static void main(String[] args) throws JsonProcessingException {
   //创建ObjectMapper对象
   ObjectMapper mapper = new ObjectMapper();
  
   Customer customer = new Customer(1, "Tom");
   List< Customer > lists = Arrays.asList(customer, new Customer(2, "Bob"));
  
   //调用 ObjectMapper 的 writeValueAsString(xxx) 方法,把一个对象或几个传入,转为一个 JSON 字符串
   String jsonStr = mapper.writeValueAsString(lists);
   System.out.println(jsonStr);
  
  }
 
}

定义了一个 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 @Test
public void test2() throws JsonProcessingException {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
  lists.add(customer);
 
  ObjectMapper mapper = new ObjectMapper();
  String jsonStr = mapper.writeValueAsString(lists);
  System.out.println(jsonStr);
}

来看一下输出结果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],结果显而易见.

3.我们再来看一看如果像 Fastjson 中测试的 Department 和 Manager 双向一对一映射的例子,Jackson 会表现的怎么样:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 @Test
public void test1() throws JsonProcessingException {
  Manager mgr = new Manager();
  mgr.setMgrId(1);
  mgr.setMgrName("Tom");
 
  Department dept = new Department();
  dept.setDeptId(2);
  dept.setDeptName("DEV");
 
  mgr.setDept(dept);
  dept.setManager(mgr);
 
  ObjectMapper mapper = new ObjectMapper();
  String jsonStr = mapper.writeValueAsString(dept);
  System.out.println(jsonStr);
}

直接运行还是会出相同的异常 Caused by: java.lang.StackOverflowError,我们的思路与测试 Fastjson 一样,为 Department 中的 Manager 引用添加 @JsonIgnore 注解,异常解决了,但打印结果是很满意,结果为:{"deptId":2,"deptName":"DEV"} ,远不如 Fastjson 的输出结果。由此可以看出 Fastjson 功能之强大.

3、Google Gson 。

1.看看如何使用:jar 包呢只需要一个 gson-2.2.4.jar ,普通对象与集合转为 JSON 没有什么可说的,简单演示一下将 List 集合转为 JSON 字符串吧,直接 new 出 Gson 的对象,调用其 toJson() 方法传入需要转换的对象即可.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 @Test
public void test2() {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
 
  Customer customer2 = new Customer();
  customer2.setId(1);
  customer2.setCustName("Bob");
  customer2.setAddress("ShangHai");
 
  lists.add(customer2);
 
  Gson gson = new Gson();
  String jsonStr = gson.toJson(lists);
  System.out.println(jsonStr);
}

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}] 。

2. 那有没有禁止循环引用呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 @Test
public void test3() {
  List< Customer > lists = new ArrayList<>();
 
  Customer customer = new Customer();
  customer.setId(1);
  customer.setCustName("Tom");
  customer.setAddress("BeiJing");
 
  lists.add(customer);
  lists.add(customer);
 
  Gson gson = new Gson();
  String jsonStr = gson.toJson(lists);
  System.out.println(jsonStr);
 
}

输出结果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],显而易见是没有的.

3.若有双向一对一的关联关系映射的话,Google Gson 也是会有死循环问题造成 java.lang.StackOverflowError 异常,但是 Gson 并没有为我们提供一个注解,要解决此问题LZ提供一个解决方案的思路,Google Gson 使用的是 ExclusionStrategy 策略进行某个字段或某个域的序列化,可以通过此接口自定义一个 注解来解决此问题。但是建议大家如果涉及到双向关联关系的对象转换为 JSON 的需求是,使用 Fastjson.

4、三种方式的简单比较 。

LZ 从以下几个方面来比较构造 JSON 字符串的三种方式:

1. jar 包方面:显然是 Fastjson 和 Google Gson 胜出,Jackson 需要加入 3 个 jar 包.

2. 简单对象或集合转为 JSON:若是普通的简单对象或集合进行转换,可能 Jackson 和 Google Gson 要胜出一些了,起码构造比较方便.

3. 涉及到双向关联关系的转换:毫无疑问阿里巴巴的 Fastjson 将胜出.

建议大家在实际的开发中根据自己的需求合理选择某一方式.

以上这篇深入剖析构建JSON字符串的三种方式(推荐)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我.

原文链接:http://www.cnblogs.com/crawl/p/7701856.html 。

最后此篇关于深入剖析构建JSON字符串的三种方式(推荐)的文章就讲到这里了,如果你想了解更多关于深入剖析构建JSON字符串的三种方式(推荐)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com