目录
- 说明
- 实例代码
说明
本文章代码出自摸石头过河写出来的,隔天再写不一定写得出来,所以发个文章记录下。
为什么写这个代码
需求要求,有一段json字符串,数据结构是图下这样:
{
"id": "1",
"string": "sb",
"double": "33",
"long": "2",
"boolean": "true",
"domain": {
"id": "1",
"name": "大白",
"org": {
"code": "1"
},
"jd": [{
"j": "false",
"d": "4"
}, {
"j": "true",
"d": "6"
}]
},
"orgs": [{
"code": "bb",
"id": "true",
"org": {
"code": "1"
},
"sb": [{
"s": "1"
}, {
"b": "true"
}]
}, {
"code": "cc",
"id": "false",
"org": {
"code": "1"
},
"sb": [{
"s": "2"
}, {
"b": "false"
}]
}]
}
可以得知,所有属性都是string类型,又得知有个Attr类,里面放着json属性对应的类型,要求我们如果json里面有属性和Attr类里面名称对应的上,就要把string转换相对应的类型。
以上可能有点绕,举个栗子:图上有个id的属性,它的值是字符串的1,Attr类里面id对应的值是integer,所以最后的结果要是integer类型。
由于json数据结构不可知,只能穷举+递归针对处理:
1、基本数据类型
2、object类型
3、array类型
4、object类型中有array类型
5、array类型中有object类型
实例代码
package com.lq.demo1.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lq.demo1.entity.Attr;
import com.lq.demo1.entity.Constants;
import lombok.extern.slf4j.Slf4j;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class TestService {
public static void main(String[] args) throws JsonProcessingException {
String json = "{\n" +
"\t\"id\": \"1\",\n" +
"\t\"string\": \"sb\",\n" +
"\t\"double\": \"33\",\n" +
"\t\"long\": \"2\",\n" +
"\t\"boolean\": \"true\",\n" +
"\t\"domain\": {\n" +
"\t\t\"id\": \"1\",\n" +
"\t\t\"name\": \"大白\",\n" +
"\t\t\"org\": {\n" +
"\t\t\t\"code\": \"1\"\n" +
"\t\t},\n" +
"\t\t\"jd\": [{\n" +
"\t\t\t\"j\": \"false\",\n" +
"\t\t\t\"d\": \"4\"\n" +
"\t\t}, {\n" +
"\t\t\t\"j\": \"true\",\n" +
"\t\t\t\"d\": \"6\"\n" +
"\t\t}]\n" +
"\t},\n" +
"\t\"orgs\": [{\n" +
"\t\t\"code\": \"bb\",\n" +
"\t\t\"id\": \"true\",\n" +
"\t\t\"org\": {\n" +
"\t\t\t\"code\": \"1\"\n" +
"\t\t},\n" +
"\t\t\"sb\": [{\n" +
"\t\t\t\"s\": \"1\"\n" +
"\t\t}, {\n" +
"\t\t\t\"b\": \"true\"\n" +
"\t\t}]\n" +
"\t}, {\n" +
"\t\t\"code\": \"cc\",\n" +
"\t\t\"id\": \"false\",\n" +
"\t\t\"org\": {\n" +
"\t\t\t\"code\": \"1\"\n" +
"\t\t},\n" +
"\t\t\"sb\": [{\n" +
"\t\t\t\"s\": \"2\"\n" +
"\t\t}, {\n" +
"\t\t\t\"b\": \"false\"\n" +
"\t\t}]\n" +
"\t}]\n" +
"}";
log.info("老:{}", json);
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = (ObjectNode) objectMapper.readTree(json);
Attr a = Attr.builder().id(1).attributeName("id").attributeType("INTEGER").parentId(-1).build();
Attr b = Attr.builder().id(2).attributeName("string").attributeType("STRING").parentId(-1).build();
Attr c = Attr.builder().id(3).attributeName("double").attributeType("INTEGER").parentId(-1).build();
Attr d = Attr.builder().id(4).attributeName("long").attributeType("LONG").parentId(-1).build();
Attr e = Attr.builder().id(5).attributeName("boolean").attributeType("BOOLEAN").parentId(-1).build();
Attr f = Attr.builder().id(6).attributeName("orgs").attributeType("JSONARRAY").parentId(-1).build();
Attr g = Attr.builder().id(7).attributeName("code").attributeType("STRING").parentId(6).build();
Attr h = Attr.builder().id(7).attributeName("id").attributeType("BOOLEAN").parentId(6).build();
Attr l1 = Attr.builder().id(13).attributeName("org").attributeType("JSONOBJECT").parentId(6).build();
Attr m1 = Attr.builder().id(14).attributeName("code").attributeType("INTEGER").parentId(13).build();
Attr m11 = Attr.builder().id(15).attributeName("sb").attributeType("JSONARRAY").parentId(6).build();
Attr m12 = Attr.builder().id(16).attributeName("s").attributeType("INTEGER").parentId(15).build();
Attr m13 = Attr.builder().id(17).attributeName("b").attributeType("BOOLEAN").parentId(15).build();
Attr i = Attr.builder().id(8).attributeName("domain").attributeType("JSONOBJECT").parentId(-1).build();
Attr j = Attr.builder().id(9).attributeName("id").attributeType("INTEGER").parentId(8).build();
Attr k = Attr.builder().id(10).attributeName("name").attributeType("STRING").parentId(8).build();
Attr l = Attr.builder().id(11).attributeName("org").attributeType("JSONOBJECT").parentId(8).build();
Attr m = Attr.builder().id(12).attributeName("code").attributeType("INTEGER").parentId(11).build();
Attr m8 = Attr.builder().id(18).attributeName("jd").attributeType("JSONARRAY").parentId(8).build();
Attr m9 = Attr.builder().id(19).attributeName("j").attributeType("BOOLEAN").parentId(18).build();
Attr m20 = Attr.builder().id(20).attributeName("d").attributeType("INTEGER").parentId(18).build();
List<Attr> attrs = new LinkedList<>();
attrs.add(m8);
attrs.add(m9);
attrs.add(m20);
attrs.add(a);
attrs.add(b);
attrs.add(c);
attrs.add(d);
attrs.add(e);
attrs.add(f);
attrs.add(g);
attrs.add(h);
attrs.add(i);
attrs.add(j);
attrs.add(k);
attrs.add(l);
attrs.add(m);
attrs.add(l1);
attrs.add(m1);
attrs.add(m11);
attrs.add(m12);
attrs.add(m13);
tree(attrs);
log.info("树结构:{}", attrs.toString());
Iterator<Map.Entry<String, JsonNode>> fields = objectNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> next = fields.next();
String key = next.getKey();
JsonNode value = next.getValue();
for (Attr dto : attrs) {
String attributeType = dto.getAttributeType();
if (dto.getAttributeName().equals(key)) {
if (!attributeType.equals(Constants.JSONARRAY) && !attributeType.equals(Constants.JSONOBJECT)) {
//先把最外层的基本类型给解决掉
baseNode(objectNode, key, value, attributeType);
} else if (attributeType.equals(Constants.JSONOBJECT)) {
//第一层的key
objectNode(objectNode, key, key, value, attributeType, attrs);
} else if (attributeType.equals(Constants.JSONARRAY)) {
arraryNode(objectNode, key, key, attributeType, attrs);
}
}
}
}
log.info("新:{}", objectNode.toString());
}
/**
* @param objectNode 原始数据
* @param key 原始数据中的key
* @param value key的value 需要转换类型
* @param attributeType 转换的类型
*/
public static void baseNode(ObjectNode objectNode, String key, JsonNode value, String attributeType) {
//基础类型设置值
if (attributeType.equals(Constants.DOUBLE)) {
objectNode.put(key, value.asDouble());
} else if (attributeType.equals(Constants.INTEGER)) {
objectNode.put(key, value.asInt());
} else if (attributeType.equals(Constants.LONG)) {
objectNode.put(key, value.asLong());
} else if (attributeType.equals(Constants.BOOLEAN)) {
objectNode.put(key, value.asBoolean());
}
}
/**
* @param rootObjectNode 原始数据
* @param rootKey 原始数据中key
* @param attrKey 追加要和attr name 拼接使用的key
* @param attributeType
* @param attrs
*/
public static void arraryNode(ObjectNode rootObjectNode, String rootKey, String attrKey, String attributeType, List<Attr> attrs) {
if (attributeType.equals(Constants.JSONARRAY)) {
ArrayNode jsonNodes = rootObjectNode.withArray(rootKey);
for (int i = 0; i < jsonNodes.size(); i++) {
JsonNode node = jsonNodes.get(i);
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> next = fields.next();
String key = next.getKey();
String dkey = attrKey + "." + key;
//子属性node
JsonNode nextValue = next.getValue();
for (Attr attr : attrs) {
if (dkey.equals(attr.getAttributeName())) {
String attributeType1 = attr.getAttributeType();
if (!attributeType1.equals(Constants.JSONOBJECT) && !attributeType1.equals(Constants.JSONARRAY)) {
//怎么修改值类型?
ObjectNode objectNode = (ObjectNode) node;
if (attributeType1.equals(Constants.DOUBLE)) {
objectNode.put(key, nextValue.asInt());
} else if (attributeType1.equals(Constants.INTEGER)) {
objectNode.put(key, nextValue.asInt());
} else if (attributeType1.equals(Constants.LONG)) {
objectNode.put(key, nextValue.asLong());
} else if (attributeType1.equals(Constants.BOOLEAN)) {
objectNode.put(key, nextValue.asBoolean());
} else if (attributeType1.equals(Constants.STRING)) {
objectNode.put(key, nextValue.asText());
}
} else if (attributeType1.equals(Constants.JSONOBJECT)) {
ObjectNode objectNode = (ObjectNode) node;
objectNode(objectNode, key, dkey, nextValue, attributeType1, attrs);
} else if (attributeType1.equals(Constants.JSONARRAY)) {
ObjectNode objectNode = (ObjectNode) node;
arraryNode(objectNode, key, dkey, attributeType1, attrs);
}
}
}
}
}
}
}
/**
* @param rootObjectNode 原始数据
* @param rootKey 对象名称
* @param attrKey
* @param childJsonNode 对象里面的所有属性
* @param attributeType
* @param attrs
*/
public static void objectNode(ObjectNode rootObjectNode, String rootKey, String attrKey, JsonNode childJsonNode,
String attributeType, List<Attr> attrs) {
if (attributeType.equals(Constants.JSONOBJECT)) {
Iterator<Map.Entry<String, JsonNode>> fields = childJsonNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> next = fields.next();
String key = next.getKey();
String dkey = attrKey + "." + key;
//子属性node
JsonNode nextValue = next.getValue();
for (Attr attr : attrs) {
if (dkey.equals(attr.getAttributeName())) {
String attributeType1 = attr.getAttributeType();
if (!attributeType1.equals(Constants.JSONOBJECT) && !attributeType1.equals(Constants.JSONARRAY)) {
ObjectNode objectNode = rootObjectNode.with(rootKey);
if (attributeType1.equals(Constants.DOUBLE)) {
objectNode.put(key, nextValue.asDouble());
} else if (attributeType1.equals(Constants.INTEGER)) {
objectNode.put(key, nextValue.asInt());
} else if (attributeType1.equals(Constants.LONG)) {
objectNode.put(key, nextValue.asLong());
} else if (attributeType1.equals(Constants.BOOLEAN)) {
objectNode.put(key, nextValue.asBoolean());
}
} else if (attributeType1.equals(Constants.JSONOBJECT)) {
ObjectNode objectNode = rootObjectNode.with(rootKey);
objectNode(objectNode, key, dkey, nextValue, attributeType1, attrs);
} else if (attributeType1.equals(Constants.JSONARRAY)) {
ObjectNode objectNode = rootObjectNode.with(rootKey);
arraryNode(objectNode, key, dkey, attributeType1, attrs);
}
}
}
}
}
}
/**
* 树节点处理名称拼接 查询sql的id必须按照升序排序 不然方法无效
*
* @param all
*/
public static void tree(List<Attr> all) {
//按照id升序 因为Attr是类似tree结构的数据,如果是object类型,一个属性的名称例如就是domain.id 为什么不直接拿id,因为不同节点id可能是string可能是integer,所以要通过对象.属性去重命名 外面匹配也是一样,如果有嵌套的数据,要自行处理名称和Attr重置后的名称匹配,才能得知真正类型是什么
all.stream().sorted(Comparator.comparing(Attr::getId)).collect(Collectors.toList());
for (Attr a : all) {
if (a.getParentId().intValue() != -1) {
setName(a, all);
}
}
}
public static void setName(Attr b, List<Attr> all) {
for (Attr attribute : all) {
if (b.getParentId().equals(attribute.getId())) {
b.setAttributeName(attribute.getAttributeName() + "." + b.getAttributeName());
}
}
}
}
主要难点,就是objectNode和arrayNode怎么去设置值,当时困扰了我很久,因为对ObjectMapper不熟悉,里面很多方法不知道,后面看了下源码才知道,主要的坑有以下几点:
- 所有的数据修改,都可以用ObjectNode.put方法去改,即使是arrayNode类型,之前不知道怎么去修改,妄想自己组装map去覆盖,结果失败。。
- 递归传递的值一定要捋清楚,很容易穿错原数据结构,比如对象套对象、对象套集合、集合套对象套集合等等这种很扭曲很恶心的结构,在针对对象和集合这两个类型卡我很久!!!
- JsonNode可以强转换为ObjectNode类型,之后就可以针对这个节点的值去修改,例如arrayNode我一直在查怎么修改,很多人都说删除原节点,自己写个新的节点加进去,这种很麻烦很麻烦很麻烦,尤其各种变态结构,极其容易出错(我没写成功过)
- ObjectNode.with、ObjectNode.withArray是object、array类型获取节点不同方式,里面填的是key名称,会去同一层找到这个key的所有属性返回,这个就是从源码看到的,百度我没找到,各个类去翻才找到。。。
- 如何去循环一个node,方法是JsonNode.fields();,JsonNode里面有很多方法,可以去源码看看,也有拿所有key的,但是 JsonNode.fields(); 能拿到所有的key-value键值对,其他的要么只能拿key,要么只能拿value,而且value还不是jsonNode类型,后面极其不好处理
就先说到这
\color{#008B8B}{ 就先说到这}
就先说到这
在下
A
p
o
l
l
o
\color{#008B8B}{在下Apollo}
在下Apollo
一个爱分享
J
a
v
a
、生活的小人物,
\color{#008B8B}{一个爱分享Java、生活的小人物,}
一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞!
\color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!}
咱们来日方长,有缘江湖再见,告辞!