我这里需要的数据格式这这样的:
数据库的部分数据如下:
直接上代码,首先创建一个bean类,进行封装数据,(可以直接用Map,但用来比较费劲,我还是采用将数据库中的数据封装到bean 中,更直接些)
public class UnCdeAreaBean implements Serializable {
private static final long serialVersionUID = 8139867807928157021L;
/**
* 主键6位串
*/
private String value; // 这里是数据库中id ,因实际json显示需要改为value
/**
* 名称
*/
private String text; // 这里是数据库中name,因实际json显示需要改为text
/**
* 父节点ID
*/
private String pid;
/**
* 级别
*/
private String numLevel;
/**
* 是否有效 1:有效 0:无效
*/
private String isValid;
private List<UnCdeAreaBean> children = new ArrayList<>();
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
// public String getId() {
// return this.id;
// }
//
// public void setId(String id) {
// this.id = id;
// }
// public String getName() {
// return this.name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPid() {
return this.pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getNumLevel() {
return this.numLevel;
}
public void setNumLevel(String numLevel) {
this.numLevel = numLevel;
}
public String getIsValid() {
return this.isValid;
}
public void setIsValid(String isValid) {
this.isValid = isValid;
}
// public List<UnCdeAreaBean> getNodes() {
// return nodes;
// }
//
// public void setNodes(List<UnCdeAreaBean> nodes) {
// this.nodes = nodes;
// }
public List<UnCdeAreaBean> getChildren() {
return children;
}
public void setChildren(List<UnCdeAreaBean> children) {
this.children = children;
}
public UnCdeAreaBean(String value, String text, String pid, String numLevel) {
this.value = value;
this.text = text;
this.pid = pid;
this.numLevel = numLevel;
}
public UnCdeAreaBean(){}
}
接下来就是从数据库中获取数据,然后进行封装到上面创建的实体中:
public List<UnCdeAreaBean> getAreaInfoOptimize() {
// 从数据库中获取地区数据
String sql = " select t.* from xxx_tab t WHERE t.is_valid = '1' AND t.num_level < 4 ORDER BY t.id ";
List<Map<String, Object>> unCdeAreas = this.findForJdbc(sql);
// 将List<Map<String, Object>> 转成 List<UnCdeAreaBean>
List<UnCdeAreaBean> UnCdeAreaBeanArrayList = new ArrayList<>();
unCdeAreas.forEach(map -> {
UnCdeAreaBean UnCdeAreaBean = new UnCdeAreaBean((String) map.get("ID"),(String) map.get("NAME"),
map.get("PID").toString(), String.valueOf(map.get("NUM_LEVEL")));
UnCdeAreaBeanArrayList.add(UnCdeAreaBean);
});
// 创建一个顶层节点
UnCdeAreaBean root = new UnCdeAreaBean();
// 构建树结构
UnCdeAreaBean areaBean = buildNodes(root, UnCdeAreaBeanArrayList);
// System.out.println("JSON.toJSONString(root) = " +JSON.toJSONString(areaBean));
List<UnCdeAreaBean> nodes = areaBean.getChildren();
// System.out.println("List<UnCdeAreaBean> nodes "+JSONArray.toJSONString(nodes));
return nodes;
}
构建树的代码:
public static UnCdeAreaBean buildNodes(UnCdeAreaBean root, List<UnCdeAreaBean> nodes) {
// 剩余节点(还没有找到父节点的节点)
ArrayList<UnCdeAreaBean> remainNodes = new ArrayList<>();
// 当前节点下的子节点
ArrayList<UnCdeAreaBean> child = new ArrayList<>();
Iterator<UnCdeAreaBean> iterator = nodes.iterator();
while (iterator.hasNext()) {
UnCdeAreaBean node = iterator.next();
// 顶层节点 为多个的时候 北京市、天津市、河北省...就是第一层的时候
if (Objects.equals(node.getNumLevel(), "1")) {
// root = node;
child.add(node); // 这里解释一下,我先将北京市、天津市、河北省...添加child 中作为第一层节点。实际中可能还会遇到这种情况:一个超级root顶节点,只是用来展开,没有实际含义的,点击就展开,root下面才是北京市、天津市、河北省... 这种情况就直接放开注释 root = node ,将child.add(node) 注释即可
continue;
}
// 该节点找到了子节点
if (Objects.equals(root.getValue(), node.getPid())) {
child.add(node);
} else {
// 没有找到子节点
remainNodes.add(node);
}
}
// 根节点设置子节点
root.setChildren(child);
// 每一个节点再去寻找对应的子节点
root.getChildren().stream().forEach(x -> {
buildNodes(x, remainNodes);
});
return root;
}
PS: 这里我遇到的一个问题,就是实际需要构建的树结构,有多个顶节点,如:北京市、天津市、河北省 等,而 有一个顶节点的,如:中国下面北京市、天津市、河北省,这里省上层还有一个root顶节点中国。不知道有没有说清楚。
数据如下:
第一种情况,有一个顶节点的 xxx公司就是root顶节点
menus.add(new Menu("0", "xxx公司", "", "1"));
menus.add(new Menu("1", "财务部", "0", "2"));
menus.add(new Menu("2", "人事部", "0", "2"));
menus.add(new Menu("11", "财务部11", "1", "3"));
menus.add(new Menu("12", "财务部12", "1", "3"));
menus.add(new Menu("22", "财务部22", "2", "3"));
menus.add(new Menu("21", "财务部21", "2", "3"));
第二种情况,多个顶节点的:财务部 和 人事部 并列的顶节点
// menus.add(new Menu("0", "xxx公司", "", "1"));
menus.add(new Menu("1", "财务部", "1", "2"));
menus.add(new Menu("2", "人事部", "2", "2"));
menus.add(new Menu("11", "财务部11", "1", "3"));
menus.add(new Menu("12", "财务部12", "1", "3"));
menus.add(new Menu("22", "财务部22", "2", "3"));
menus.add(new Menu("21", "财务部21", "2", "3"));
上述举例的数据得到的json
第一种情况结果,有一个顶层节点 xxx公司,然后公司下面 才是 财务部和人事部
{
"id":"0",
"level":"1",
"name":"xxx公司",
"nodes":[
{
"id":"1",
"level":"2",
"name":"财务部",
"nodes":[
{
"id":"11",
"level":"3",
"name":"财务部11",
"nodes":[
],
"parentId":"1"
},
{
"id":"12",
"level":"3",
"name":"财务部12",
"nodes":[
],
"parentId":"1"
}
],
"parentId":"0"
},
{
"id":"2",
"level":"2",
"name":"人事部",
"nodes":[
{
"id":"22",
"level":"3",
"name":"财务部22",
"nodes":[
],
"parentId":"2"
},
{
"id":"21",
"level":"3",
"name":"财务部21",
"nodes":[
],
"parentId":"2"
}
],
"parentId":"0"
}
],
"parentId":""
}
第二种情况json: 直接就是财务部和人事部 作为顶节点,没有超级root 节点 “xxx公司”
{
"nodes":[
{
"id":"1",
"level":"2",
"name":"财务部",
"nodes":[
{
"id":"11",
"level":"3",
"name":"财务部11",
"nodes":[
],
"parentId":"1"
},
{
"id":"12",
"level":"3",
"name":"财务部12",
"nodes":[
],
"parentId":"1"
}
],
"parentId":"0"
},
{
"id":"2",
"level":"2",
"name":"人事部",
"nodes":[
{
"id":"22",
"level":"3",
"name":"财务部22",
"nodes":[
],
"parentId":"2"
},
{
"id":"21",
"level":"3",
"name":"财务部21",
"nodes":[
],
"parentId":"2"
}
],
"parentId":"0"
}
]
}
如有问题,欢迎交流指正。