一、背景
最近领导新给了一个需求,需要前台传一段正确的json串,经过解析以后能把层级关系正确的存入数据库。先看看前端成果物:
二、需求分析
1、要求是一段正确的json串(符合json格式的字符串),所以要考虑用户可能输入任意的字符串 => 所以需要对输入的字符串进行捕获,不符合的情况下弹出警告框提示用户。
2、对于符合json格式的字符串怎么去格式化校验,是一个难题。如果不借助官方现成的工具,当时想到的是通过字符串中的 { 和 [ 去分析层级关系,没遇到 { 或 [ 层级关系就应该递加一层,没遇到 } 或 ] 就减少一层。但是其中有很多细节是需要考究的,比如在json串的键值对中,可能会出现 "list": [] "name": {} "list": [{}] 这种情况,此时去递加层级关系大可不必!下面是我的一些思路,当时有根据这个思路做了几版代码。但是最终都没有完美的实现!有兴趣的可以参考或者指出问题一起探讨,哈哈哈哈哈哈
public void commonJSONParse(String jsonStr) {
char[] specialArr = { '\'', '"', '\\' }; //包含此类字符时,不执行逻辑
List<Character> specialList = CollectionUtils.arrayToList(specialArr);
int level = 0;
Map<Integer, Integer> map = new TreeMap<>(); //key储存索引,value储存层级关系
char[] charArr = jsonStr.toCharArray();
for (int i = 0; i < charArr.length; i++) {
char cunrretChar = charArr[i];
int index = specialList.indexOf(Character.valueOf(cunrretChar));
if (index == -1) {
switch (cunrretChar) {
case '{':
map.put(i, ++level);
break;
case '}':
map.put(i, level--);
break;
case '[':
map.put(i, ++level);
break;
case ']':
map.put(i, level--);
break;
default:
break;
}
}
}
for (Integer key : map.keySet()) {
System.out.println(key + ": " + map.get(key) + "=>" + jsonStr.charAt(key.intValue()));
}
for (Integer key : map.keySet()) {
}
}
3、解决办法
最终在网上是发现了一个现成方法可以进行json串的格式化校验
formatJson() {
try {
//jptextarea是文本框的值,用于接收你写入的json串
//JSON.stringify()通过设置第二第三参数值可以到达校验的目的
//第三个参数决定校验后的空格数
//需要注意的是文本框中只是一个符合json格式的字符串,所以必须先经过JSON.parse()解析为
//对象才能调用JSON.stringify
this.jPTextarea = JSON.stringify(JSON.parse(this.jPTextarea), null, 4);
} catch (error) {
console.error(error);
this.showCommonAlert("JSON格式错误!请规范!");
}
},
三、后端实现
以上是js实现方式,后端实现方式也写了几个版本,但是最后发现还是递归比较好用。没想到有更好的方式,因为json串里的层级关系可以无限嵌套,第一时间想到的就是递归来做。递归的话,说下我的思路:
1、根据json串首字母是 { 或 [ 来判断此json串本质是一个集合类型还是对象类型。
2、对象类型使用阿里巴巴的fastjson包下的JSONObject.parse()解析,解析后返回的是一个可以转成map类型的Object对象;同理JSONArray.parse()用于解析集合也是。
3、通过JSONArray.parse()返回可以转成JSONArray类型的对象后,在循环拿取里面的JSONObject类型的对象,所以不管是集合还是对象类型,最终都可以转成对象类型来做。
4、递归的条件就是,每次碰上JSONObject就执行递归,因为后端逻辑不一样,这里就不附上代码!