项目开发中经常会遇到多叉树的展示,最为常见的便是组织机构图以及省市县结构图,
通常做法是接收服务器端返回来的JSON格式的数据,动态生成树形菜单节点。
动态生成树有两种思路:
- 异步加载节点,适用于节点数量很多的结构,通过zTree等插件封装的方法,传入指定的节点ID查询出当前节点下的子节点信息。
- 一次性生成全部树节点,适用于小数据量的结构。
今天的笔记记录的是第二种思路的实现方式,共两种
第一种为最常规的做法,将节点以节点编号为Key存入散列表,随后遍历散列表通过Key值与节点的parentId对应关系再构造出多叉树:
public class InfiniteLevelTreeUtil { public static List<Node> getInfiniteLevelTree() { // 读取层次数据结果集列表 List<Node> dataList = dao.getNodes(); // 将Node存入散列表 Map<String, Node> nodeMap = dataList.stream().collect(Collectors.toMap(Node::getId, node -> node)); // 根节点 List<Node> root = new ArrayList<>(); // 构造无序的多叉树 for(Map.Entry<String, Node> entry: nodeMap.entrySet()) { Node node = entry.getValue(); if (node.getParentId().equals("-1")) { root.add(node); } else { nodeMap.get(node.getParentId()).addChild(node); } } return root; } } // 节点Bean public class Node { private String id; private String name; private String parentId; private int order; private Children children = new Children(); // ...get set 方法,构造方法 // 兄弟节点排序 public void sortChildren() { if (children != null && children.getSize() != 0) { children.sortChildren(); } } // 添加孩子节点 public void addChild(Node node) { this.children.addChild(node); } } // 子节点Bean public class Children { private List<Node> list = new ArrayList<>(); // ...get set 方法,构造方法 public int getSize() { return list.size(); } public void addChild(Node node) { list.add(node); } // 孩子节点排序 public void sortChildren() { Collections.sort(list, new NodeOrderComparator()); for (Iterator<Node> it = list.iterator(); it.hasNext();) { it.next().sortChildren(); } } } // 节点排序Comparator public class NodeOrderComparator implements Comparator<Node>{ // 按照节点排序值进行排序 public int compare(Node n1, Node n2) { return (n1.getOrder() < n2.getOrder() ? -1 : (n1.getOrder() == n2.getOrder() ? 0 : 1)); } }
第二种做法使用了递归,以parentId = '-1'
(根节点)作为递归方法的入口,构造多叉树。
public class InfiniteLevelTreeUtil { // 入口方法 public List<Node> getInfiniteLevelTree(List<Node> nodeList) { List<Node> list = new ArrayList<>(); // 遍历节点列表 for (Node node : nodeList) { if (node.getParentId().equals("-1")) { // parentID为-1(根节点)作为入口 node.setChildren(getChildrenNode(node.getId(), nodeList)); list.add(node); } } // 排序 list.sort(new NodeOrderComparator()); return list; } // 获取子节点的递归方法 public List<Node> getChildrenNode(String id, List<Node> nodeList) { List<Node> lists = new ArrayList<>(); for (Node node : nodeList) { if (node.getParentId().equals(id)) { // 递归获取子节点 node.setChildren(getChildrenNode(node.getId(), nodeList)); lists.add(node); } } // 排序 lists.sort(new NodeOrderComparator()); return lists; } } // 节点Bean public class Node { private String id; private String name; private String parentId; private int order; private List<Node> children = new ArrayList<>(); // ...get set 方法,构造方法 } // 节点排序Comparator public class NodeOrderComparator implements Comparator<Node>{ // 按照节点排序值进行排序 public int compare(Node n1, Node n2) { return (n1.getOrder() < n2.getOrder() ? -1 : (n1.getOrder() == n2.getOrder() ? 0 : 1)); } }
节点列表如下(id,name,pid,order):
Node n1 = new Node("0", "根节点", "-1", 0); Node n2 = new Node("01", "一级子节点", "0", 0); Node n3 = new Node("011", "二级子节点1", "01", 3); Node n4 = new Node("012", "二级子节点2", "01", 2); Node n5 = new Node("013", "二级子节点3", "01", 1); Node n6 = new Node("0131", "三级子节点1", "013", 1); Node n7 = new Node("0132", "三级子节点2", "013", 1);
运行方法后得到的树结构的JSON串如下:
{ id : '0', name: '根节点', children : [{ id : '01', name: '一级子节点', children : [ { id : '011', name: '二级子节点1', children:[] }, { id : '012', name: '二级子节点2', children:[] }, { id : '013', name: '二级子节点3', children : [ { id : '0131', text : '三级子节点1' }, { id : '01312', text : '三级子节点2' } ] } ] }] }
以上,实现了无线级树节点的构造
java实现构造无限层级树形菜单
利用多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法)
文章来源: Java实现n级树对象的封装