这里首先说一下后台返回的json格式
总结了一下,大概就是两种:
对象 -----{"key" , "value"} 对象类型
集合-----{"key" , "value"} ,{"key" , "value"} ]数组/集合类型
注意:在json转换中 对象即Map , Map 即对象 ; 换言而止 , Map 和对象类型转换出来的json字符串格式是一样的;
下面是一个demo演示一下
@Test
public void MapToJson(){
//map类型
Map map = new HashMap();
map.put("username" , "东方月初");
map.put("password" , "123456");
System.out.println(JSON.toJSONString(map));
//对象类型
User user = new User();
user.setUsername("东方月初");
user.setPassword("123456");
System.out.println(JSON.toJSONString(user));
}
打印结果截图
当前除了这两种 , 还有以各种复杂的格式就是 对象中包含 集合 , 集合中包含对象的混合类型json串, 原理大概差不多 ,这里就不多做解释
接下来进入正题
在有时候,业务逻辑复杂的时候 , 返回的json字符串中可能会出现对象引用的问题, 什么是对象引用呢, 这里简单的做一下演示
首先模拟一个json对象引用的情况
@Test
public void jsonTest(){
//对象类型
User user = new User();
user.setUsername("东方月初");
user.setPassword("123456");
List<User> userList = new ArrayList<User>();
//存储两个相同的对象
userList.add(user);
userList.add(user);
System.out.println(JSON.toJSONString(userList));//打印结果[{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]
/*
[{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]
{"$ref":"$[0]"}
$ref -----链接地址
$[0] -----list集合的索引值
这里因为list集合中的第二个对象的key 和value 域第一个对象的key和value完全一样 , 所以会出现这种情况
可以把他理解为系统简写了第二个对象
在业务逻辑比较复杂的情况下,后台有时候会出现这种对象引用的问题 , 可是这个json串传送给前端页面后 , 前端页面不会识别 ,
*/
解决方案
关闭toJSONString转换json过程中的循环引用
这里是toJSONString的一个构造方法
public static String toJSONString(Object object, SerializerFeature... features) {
return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}
参数2 SerializerFeature 中有一个属性DisableCircularReferenceDetect
作用为关闭循环应用 , 默认情况下为开启
修改上面代码中的参数
System.out.println(JSON.toJSONString(userList , SerializerFeature.DisableCircularReferenceDetect));
打印结果如下:
[{“password”:“123456”,“username”:“东方月初”},{“password”:“123456”,“username”:“东方月初”}]
关闭循环应用有一个缺点就是 , 在更复杂的json情况加 , 比如
@Test
public void jsonTest(){
//对象类型
User userA = new User();
userA.setUsername("东方月初");
userA.setPassword("123456");
User userB = new User();
userB.setUsername("涂山红红");
userB.setPassword("123456");
Role role = new Role();
//role中添加user对象
role.setRoleName("盟主");
role.getUserList().add(userA);
role.getUserList().add(userB);
userA.getRoleList().add(role);
//解析user对象的时候 , user对象中包含List<Role> 集合 , 解析role对象的时候 , role对象中有List<User> 集合 , 会陷入死循环状态
System.out.println(JSON.toJSONString(userA , SerializerFeature.DisableCircularReferenceDetect));
在转换userA的时候 , 由于userA中包含了role , role 中包含了user 这种情况 , 在解析的时候会出现死循环的情况 , 造成堆栈溢出 错误
以上代码运行结果
java.lang.StackOverflowError
at com.alibaba.fastjson.serializer.SerializeWriter.writeFieldValueStringWithDoubleQuoteCheck(SerializeWriter.java:1885)
at com.alibaba.fastjson.serializer.ASMSerializer_1_User.writeDirectNonContext(Unknown Source)
at com.alibaba.fastjson.serializer.ASMSerializer_2_Role.writeDirectNonContext(Unknown Source)
at com.alibaba.fastjson.serializer.ASMSerializer_1_User.writeDirectNonContext(Unknown Source)
…
解决方案:
在toJSONString的参数中 , 可以传入一个filter过滤器SimplePropertyPreFilter
SimplePropertyPreFilter 写在这个过滤器中的属性都会被解析
SimplePropertyPreFilter filter = new SimplePropertyPreFilter(
"username","password" , "roleList" , "roleName" );//会解析写入的属性名称
//解析user对象的时候 , user对象中包含List<Role> 集合 , 解析role对象的时候 , role对象中有List<User> 集合 , 会陷入死循环状态
System.out.println(JSON.toJSONString(userA ,filter , SerializerFeature.DisableCircularReferenceDetect));//[{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]
被过滤的字段就会不显示 , 如果非要全部显示的话 , 介意修改属性名 , 让属性名布绒服