Java 树形结构、层级结构数据构建
目录
- 前言
- 一、树状结构数据库存储
- 二、工具类
- 三、测试
- 四、自定义树节点返回类型(只保留部分字段)
- 1. 新增 TreeNodeDTO 类
- 2.修改TreeUtil 类
- 3.测试
- 4.输出
前言
有时候,开发过程中我们会遇到一些树状层级结构。
比如,公司部门组织架构,或者 国家 - - 省 - - 市 - - 镇 - - 村 这样的层级结构:
|-- A 国|-- q 省|-- r 城|-- w 镇|-- z 村|-- p 村|-- l 镇|-- s 村|-- t 城|-- e 镇|-- f 村|-- w 省|-- k 城|-- j 镇|-- h 村
|-- B 国|-- v 省|-- x 城|-- n 镇|-- u 村|-- y 村|-- g 镇|-- s 村|-- t 城|-- e 镇|-- f 村|-- c 省|-- m 城|-- j 镇|-- h 村
这样的树状层级结构,每一层都有许多节点,每个节点下都有许多子节点。
那这样的结构怎么存储,以及怎么处理呢?
下面我们以 国家 - -》 公司 - -》地区 - -》部门 - -》人员 的层级结构进行示例。
中国
├── 华为
│ ├── 华东地区
│ │ ├── 人力部
│ │ │ ├── 张1
│ │ │ └── 李2
│ │ ├── 开发部
│ │ │ ├── 王3
│ │ │ └── 赵4
│ │ └── 后勤部
│ │ ├── 孙5
│ │ └── 周6
│ └── 华南地区
│ ├── 人力部
│ │ ├── 钱7
│ │ └── 吴8
│ ├── 开发部
│ │ ├── 张9
│ │ └── 李10
│ └── 后勤部
│ ├── 王11
│ └── 赵12
└── 小米├── 华东地区│ ├── 人力部│ │ ├── 孙13│ │ └── 周14│ ├── 开发部│ │ ├── 钱15│ │ └── 吴16│ └── 后勤部│ ├── 张17│ └── 李18└── 华南地区├── 人力部│ ├── 王19│ └── 赵20├── 开发部│ ├── 孙21│ └── 周22└── 后勤部├── 钱23└── 吴24
美国
├── 谷歌
│ ├── 华盛顿地区
│ │ ├── HR
│ │ │ ├── Alice1
│ │ │ └── Bob2
│ │ ├── Development
│ │ │ ├── Charlie3
│ │ │ └── David4
│ │ └── Logistics
│ │ ├── Eve5
│ │ └── Frank6
│ └── 纽约地区
│ ├── HR
│ │ ├── Grace7
│ │ └── Helen8
│ ├── Development
│ │ ├── Alice9
│ │ └── Bob10
│ └── Logistics
│ ├── Charlie11
│ └── David12
└── 微软├── 华盛顿地区│ ├── HR│ │ ├── Eve13│ │ └── Frank14│ ├── Development│ │ ├── Grace15│ │ └── Helen16│ └── Logistics│ ├── Alice17│ └── Bob18└── 纽约地区├── HR│ ├── Charlie19│ └── David20├── Development│ ├── Eve21│ └── Frank22└── Logistics├── Grace23└── Helen24
一、树状结构数据库存储
在数据库中可以用 id、name、parentId、orderNum 字段来存储数据。
id 是主键;
parentId 是父节点 id ,顶层节点 中国和美国设置为 0 ;
orderNum 用来对同一节点下同级节点进行顺序先后确定。
最终数据库表如下:
id | name | parentId | orderNum |
---|---|---|---|
1 | 中国 | 0 | 1 |
2 | 美国 | 0 | 2 |
3 | 华为 | 1 | 1 |
4 | 小米 | 1 | 2 |
5 | 谷歌 | 2 | 1 |
6 | 微软 | 2 | 2 |
7 | 华东地区 | 3 | 1 |
8 | 华南地区 | 3 | 2 |
9 | 华东地区 | 4 | 1 |
10 | 华南地区 | 4 | 2 |
11 | 华盛顿地区 | 5 | 1 |
12 | 纽约地区 | 5 | 2 |
13 | 华盛顿地区 | 6 | 1 |
14 | 纽约地区 | 6 | 2 |
15 | 人力部 | 7 | 1 |
16 | 开发部 | 7 | 2 |
17 | 后勤部 | 7 | 3 |
18 | 人力部 | 8 | 1 |
19 | 开发部 | 8 | 2 |
20 | 后勤部 | 8 | 3 |
21 | 人力部 | 9 | 1 |
22 | 开发部 | 9 | 2 |
23 | 后勤部 | 9 | 3 |
24 | 人力部 | 10 | 1 |
25 | 开发部 | 10 | 2 |
26 | 后勤部 | 10 | 3 |
27 | HR | 11 | 1 |
28 | Development | 11 | 2 |
29 | Logistics | 11 | 3 |
30 | HR | 12 | 1 |
31 | Development | 12 | 2 |
32 | Logistics | 12 | 3 |
33 | HR | 13 | 1 |
34 | Development | 13 | 2 |
35 | Logistics | 13 | 3 |
36 | HR | 14 | 1 |
37 | Development | 14 | 2 |
38 | Logistics | 14 | 3 |
39 | 张1 | 15 | 1 |
40 | 李2 | 15 | 2 |
41 | 王3 | 16 | 1 |
42 | 赵4 | 16 | 2 |
43 | 孙5 | 17 | 1 |
44 | 周6 | 17 | 2 |
45 | 钱7 | 18 | 1 |
46 | 吴8 | 18 | 2 |
47 | 张9 | 19 | 1 |
48 | 李10 | 19 | 2 |
49 | 王11 | 20 | 1 |
50 | 赵12 | 20 | 2 |
51 | 孙13 | 21 | 1 |
52 | 周14 | 21 | 2 |
53 | 钱15 | 22 | 1 |
54 | 吴16 | 22 | 2 |
55 | 张17 | 23 | 1 |
56 | 李18 | 23 | 2 |
57 | 王19 | 24 | 1 |
58 | 赵20 | 24 | 2 |
59 | 孙21 | 25 | 1 |
60 | 周22 | 25 | 2 |
61 | 钱23 | 26 | 1 |
62 | 吴24 | 26 | 2 |
63 | Alice1 | 27 | 1 |
64 | Bob2 | 27 | 2 |
65 | Charlie3 | 28 | 1 |
66 | David4 | 28 | 2 |
67 | Eve5 | 29 | 1 |
68 | Frank6 | 29 | 2 |
69 | Grace7 | 30 | 1 |
70 | Helen8 | 30 | 2 |
71 | Alice9 | 31 | 1 |
72 | Bob10 | 31 | 2 |
73 | Charlie11 | 32 | 1 |
74 | David12 | 32 | 2 |
75 | Eve13 | 33 | 1 |
76 | Frank14 | 33 | 2 |
77 | Grace15 | 34 | 1 |
78 | Helen16 | 34 | 2 |
79 | Alice17 | 35 | 1 |
80 | Bob18 | 35 | 2 |
81 | Charlie19 | 36 | 1 |
82 | David20 | 36 | 2 |
83 | Eve21 | 37 | 1 |
84 | Frank22 | 37 | 2 |
85 | Grace23 | 38 | 1 |
86 | Helen24 | 38 | 2 |
二、工具类
CompanyInfo 类
import java.util.ArrayList;
import java.util.List;public class CompanyInfo {private Long id;private String name;private Long parentId;private Integer orderNum;//子节点列表private List<CompanyInfo> children = new ArrayList<>();public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}public Integer getOrderNum() {return orderNum;}public void setOrderNum(Integer orderNum) {this.orderNum = orderNum;}public List<CompanyInfo> getChildren() {return children;}public void setChildren(List<CompanyInfo> children) {this.children = children;}public CompanyInfo(Long id, String name, Long parentId, Integer orderNum) {this.id = id;this.name = name;this.parentId = parentId;this.orderNum = orderNum;}
}
TreeUtil 类处理树状结构:
import java.util.*;
import java.util.stream.Collectors;public class TreeUtil {/*** 构建树结构** @param nodes 数据列表* @return 树形结构列表*/public static List<CompanyInfo> buildTree(List<CompanyInfo> nodes) {// 先构建一个 id -> 节点的映射,方便查找父节点Map<Long, CompanyInfo> idNodeMap = nodes.stream().collect(Collectors.toMap(CompanyInfo::getId, node -> node));// 最终返回的树根节点集合List<CompanyInfo> treeRoots = new ArrayList<>();for (CompanyInfo node : nodes) {if (node.getParentId() == 0) {// 顶层节点treeRoots.add(node);} else {// 找到父节点,添加到其 children 中CompanyInfo parent = idNodeMap.get(node.getParentId());if (parent != null) {parent.getChildren().add(node);}}}// 对每层 children 根据 orderNum 排序sortTree(treeRoots);return treeRoots;}private static void sortTree(List<CompanyInfo> nodes) {if (nodes == null || nodes.isEmpty()) return;nodes.sort(Comparator.comparing(CompanyInfo::getOrderNum));for (CompanyInfo node : nodes) {sortTree(node.getChildren());}}
}
三、测试
public static void main(String[] args) {List<CompanyInfo> flatList = new ArrayList<>();// 国家flatList.add(new CompanyInfo(1L, "中国", 0L, 1));flatList.add(new CompanyInfo(2L, "美国", 0L, 2));// 公司flatList.add(new CompanyInfo(3L, "华为", 1L, 1));flatList.add(new CompanyInfo(4L, "小米", 1L, 2));flatList.add(new CompanyInfo(5L, "谷歌", 2L, 1));flatList.add(new CompanyInfo(6L, "微软", 2L, 2));// 地区flatList.add(new CompanyInfo(7L, "华东地区", 3L, 1));flatList.add(new CompanyInfo(8L, "华南地区", 3L, 2));flatList.add(new CompanyInfo(9L, "华东地区", 4L, 1));flatList.add(new CompanyInfo(10L, "华南地区", 4L, 2));flatList.add(new CompanyInfo(11L, "华盛顿地区", 5L, 1));flatList.add(new CompanyInfo(12L, "纽约地区", 5L, 2));flatList.add(new CompanyInfo(13L, "华盛顿地区", 6L, 1));flatList.add(new CompanyInfo(14L, "纽约地区", 6L, 2));// 部门flatList.add(new CompanyInfo(15L, "人力部", 7L, 1));flatList.add(new CompanyInfo(16L, "开发部", 7L, 2));flatList.add(new CompanyInfo(17L, "后勤部", 7L, 3));flatList.add(new CompanyInfo(18L, "人力部", 8L, 1));flatList.add(new CompanyInfo(19L, "开发部", 8L, 2));flatList.add(new CompanyInfo(20L, "后勤部", 8L, 3));flatList.add(new CompanyInfo(21L, "人力部", 9L, 1));flatList.add(new CompanyInfo(22L, "开发部", 9L, 2));flatList.add(new CompanyInfo(23L, "后勤部", 9L, 3));flatList.add(new CompanyInfo(24L, "人力部", 10L, 1));flatList.add(new CompanyInfo(25L, "开发部", 10L, 2));flatList.add(new CompanyInfo(26L, "后勤部", 10L, 3));flatList.add(new CompanyInfo(27L, "HR", 11L, 1));flatList.add(new CompanyInfo(28L, "Development", 11L, 2));flatList.add(new CompanyInfo(29L, "Logistics", 11L, 3));flatList.add(new CompanyInfo(30L, "HR", 12L, 1));flatList.add(new CompanyInfo(31L, "Development", 12L, 2));flatList.add(new CompanyInfo(32L, "Logistics", 12L, 3));flatList.add(new CompanyInfo(33L, "HR", 13L, 1));flatList.add(new CompanyInfo(34L, "Development", 13L, 2));flatList.add(new CompanyInfo(35L, "Logistics", 13L, 3));flatList.add(new CompanyInfo(36L, "HR", 14L, 1));flatList.add(new CompanyInfo(37L, "Development", 14L, 2));flatList.add(new CompanyInfo(38L, "Logistics", 14L, 3));// 人员flatList.add(new CompanyInfo(39L, "张1", 15L, 1));flatList.add(new CompanyInfo(40L, "李2", 15L, 2));flatList.add(new CompanyInfo(41L, "王3", 16L, 1));flatList.add(new CompanyInfo(42L, "赵4", 16L, 2));flatList.add(new CompanyInfo(43L, "孙5", 17L, 1));flatList.add(new CompanyInfo(44L, "周6", 17L, 2));flatList.add(new CompanyInfo(45L, "钱7", 18L, 1));flatList.add(new CompanyInfo(46L, "吴8", 18L, 2));flatList.add(new CompanyInfo(47L, "张9", 19L, 1));flatList.add(new CompanyInfo(48L, "李10", 19L, 2));flatList.add(new CompanyInfo(49L, "王11", 20L, 1));flatList.add(new CompanyInfo(50L, "赵12", 20L, 2));flatList.add(new CompanyInfo(51L, "孙13", 21L, 1));flatList.add(new CompanyInfo(52L, "周14", 21L, 2));flatList.add(new CompanyInfo(53L, "钱15", 22L, 1));flatList.add(new CompanyInfo(54L, "吴16", 22L, 2));flatList.add(new CompanyInfo(55L, "张17", 23L, 1));flatList.add(new CompanyInfo(56L, "李18", 23L, 2));flatList.add(new CompanyInfo(57L, "王19", 24L, 1));flatList.add(new CompanyInfo(58L, "赵20", 24L, 2));flatList.add(new CompanyInfo(59L, "孙21", 25L, 1));flatList.add(new CompanyInfo(60L, "周22", 25L, 2));flatList.add(new CompanyInfo(61L, "钱23", 26L, 1));flatList.add(new CompanyInfo(62L, "吴24", 26L, 2));flatList.add(new CompanyInfo(63L, "Alice1", 27L, 1));flatList.add(new CompanyInfo(64L, "Bob2", 27L, 2));flatList.add(new CompanyInfo(65L, "Charlie3", 28L, 1));flatList.add(new CompanyInfo(66L, "David4", 28L, 2));flatList.add(new CompanyInfo(67L, "Eve5", 29L, 1));flatList.add(new CompanyInfo(68L, "Frank6", 29L, 2));flatList.add(new CompanyInfo(69L, "Grace7", 30L, 1));flatList.add(new CompanyInfo(70L, "Helen8", 30L, 2));flatList.add(new CompanyInfo(71L, "Alice9", 31L, 1));flatList.add(new CompanyInfo(72L, "Bob10", 31L, 2));flatList.add(new CompanyInfo(73L, "Charlie11", 32L, 1));flatList.add(new CompanyInfo(74L, "David12", 32L, 2));flatList.add(new CompanyInfo(75L, "Eve13", 33L, 1));flatList.add(new CompanyInfo(76L, "Frank14", 33L, 2));flatList.add(new CompanyInfo(77L, "Grace15", 34L, 1));flatList.add(new CompanyInfo(78L, "Helen16", 34L, 2));flatList.add(new CompanyInfo(79L, "Alice17", 35L, 1));flatList.add(new CompanyInfo(80L, "Bob18", 35L, 2));flatList.add(new CompanyInfo(81L, "Charlie19", 36L, 1));flatList.add(new CompanyInfo(82L, "David20", 36L, 2));flatList.add(new CompanyInfo(83L, "Eve21", 37L, 1));flatList.add(new CompanyInfo(84L, "Frank22", 37L, 2));flatList.add(new CompanyInfo(85L, "Grace23", 38L, 1));flatList.add(new CompanyInfo(86L, "Helen24", 38L, 2));List<CompanyInfo> tree = TreeUtil.buildTree(flatList);System.out.println(JSONObject.toJSONString(tree));}
输出:
[{"children": [{"children": [{"children": [{"children": [{"children": [],"id": 39,"name": "张1","orderNum": 1,"parentId": 15},{"children": [],"id": 40,"name": "李2","orderNum": 2,"parentId": 15}],"id": 15,"name": "人力部","orderNum": 1,"parentId": 7},{"children": [{"children": [],"id": 41,"name": "王3","orderNum": 1,"parentId": 16},{"children": [],"id": 42,"name": "赵4","orderNum": 2,"parentId": 16}],"id": 16,"name": "开发部","orderNum": 2,"parentId": 7},{"children": [{"children": [],"id": 43,"name": "孙5","orderNum": 1,"parentId": 17},{"children": [],"id": 44,"name": "周6","orderNum": 2,"parentId": 17}],"id": 17,"name": "后勤部","orderNum": 3,"parentId": 7}],"id": 7,"name": "华东地区","orderNum": 1,"parentId": 3},{"children": [{"children": [{"children": [],"id": 45,"name": "钱7","orderNum": 1,"parentId": 18},{"children": [],"id": 46,"name": "吴8","orderNum": 2,"parentId": 18}],"id": 18,"name": "人力部","orderNum": 1,"parentId": 8},{"children": [{"children": [],"id": 47,"name": "张9","orderNum": 1,"parentId": 19},{"children": [],"id": 48,"name": "李10","orderNum": 2,"parentId": 19}],"id": 19,"name": "开发部","orderNum": 2,"parentId": 8},{"children": [{"children": [],"id": 49,"name": "王11","orderNum": 1,"parentId": 20},{"children": [],"id": 50,"name": "赵12","orderNum": 2,"parentId": 20}],"id": 20,"name": "后勤部","orderNum": 3,"parentId": 8}],"id": 8,"name": "华南地区","orderNum": 2,"parentId": 3}],"id": 3,"name": "华为","orderNum": 1,"parentId": 1},{"children": [{"children": [{"children": [{"children": [],"id": 51,"name": "孙13","orderNum": 1,"parentId": 21},{"children": [],"id": 52,"name": "周14","orderNum": 2,"parentId": 21}],"id": 21,"name": "人力部","orderNum": 1,"parentId": 9},{"children": [{"children": [],"id": 53,"name": "钱15","orderNum": 1,"parentId": 22},{"children": [],"id": 54,"name": "吴16","orderNum": 2,"parentId": 22}],"id": 22,"name": "开发部","orderNum": 2,"parentId": 9},{"children": [{"children": [],"id": 55,"name": "张17","orderNum": 1,"parentId": 23},{"children": [],"id": 56,"name": "李18","orderNum": 2,"parentId": 23}],"id": 23,"name": "后勤部","orderNum": 3,"parentId": 9}],"id": 9,"name": "华东地区","orderNum": 1,"parentId": 4},{"children": [{"children": [{"children": [],"id": 57,"name": "王19","orderNum": 1,"parentId": 24},{"children": [],"id": 58,"name": "赵20","orderNum": 2,"parentId": 24}],"id": 24,"name": "人力部","orderNum": 1,"parentId": 10},{"children": [{"children": [],"id": 59,"name": "孙21","orderNum": 1,"parentId": 25},{"children": [],"id": 60,"name": "周22","orderNum": 2,"parentId": 25}],"id": 25,"name": "开发部","orderNum": 2,"parentId": 10},{"children": [{"children": [],"id": 61,"name": "钱23","orderNum": 1,"parentId": 26},{"children": [],"id": 62,"name": "吴24","orderNum": 2,"parentId": 26}],"id": 26,"name": "后勤部","orderNum": 3,"parentId": 10}],"id": 10,"name": "华南地区","orderNum": 2,"parentId": 4}],"id": 4,"name": "小米","orderNum": 2,"parentId": 1}],"id": 1,"name": "中国","orderNum": 1,"parentId": 0},{"children": [{"children": [{"children": [{"children": [{"children": [],"id": 63,"name": "Alice1","orderNum": 1,"parentId": 27},{"children": [],"id": 64,"name": "Bob2","orderNum": 2,"parentId": 27}],"id": 27,"name": "HR","orderNum": 1,"parentId": 11},{"children": [{"children": [],"id": 65,"name": "Charlie3","orderNum": 1,"parentId": 28},{"children": [],"id": 66,"name": "David4","orderNum": 2,"parentId": 28}],"id": 28,"name": "Development","orderNum": 2,"parentId": 11},{"children": [{"children": [],"id": 67,"name": "Eve5","orderNum": 1,"parentId": 29},{"children": [],"id": 68,"name": "Frank6","orderNum": 2,"parentId": 29}],"id": 29,"name": "Logistics","orderNum": 3,"parentId": 11}],"id": 11,"name": "华盛顿地区","orderNum": 1,"parentId": 5},{"children": [{"children": [{"children": [],"id": 69,"name": "Grace7","orderNum": 1,"parentId": 30},{"children": [],"id": 70,"name": "Helen8","orderNum": 2,"parentId": 30}],"id": 30,"name": "HR","orderNum": 1,"parentId": 12},{"children": [{"children": [],"id": 71,"name": "Alice9","orderNum": 1,"parentId": 31},{"children": [],"id": 72,"name": "Bob10","orderNum": 2,"parentId": 31}],"id": 31,"name": "Development","orderNum": 2,"parentId": 12},{"children": [{"children": [],"id": 73,"name": "Charlie11","orderNum": 1,"parentId": 32},{"children": [],"id": 74,"name": "David12","orderNum": 2,"parentId": 32}],"id": 32,"name": "Logistics","orderNum": 3,"parentId": 12}],"id": 12,"name": "纽约地区","orderNum": 2,"parentId": 5}],"id": 5,"name": "谷歌","orderNum": 1,"parentId": 2},{"children": [{"children": [{"children": [{"children": [],"id": 75,"name": "Eve13","orderNum": 1,"parentId": 33},{"children": [],"id": 76,"name": "Frank14","orderNum": 2,"parentId": 33}],"id": 33,"name": "HR","orderNum": 1,"parentId": 13},{"children": [{"children": [],"id": 77,"name": "Grace15","orderNum": 1,"parentId": 34},{"children": [],"id": 78,"name": "Helen16","orderNum": 2,"parentId": 34}],"id": 34,"name": "Development","orderNum": 2,"parentId": 13},{"children": [{"children": [],"id": 79,"name": "Alice17","orderNum": 1,"parentId": 35},{"children": [],"id": 80,"name": "Bob18","orderNum": 2,"parentId": 35}],"id": 35,"name": "Logistics","orderNum": 3,"parentId": 13}],"id": 13,"name": "华盛顿地区","orderNum": 1,"parentId": 6},{"children": [{"children": [{"children": [],"id": 81,"name": "Charlie19","orderNum": 1,"parentId": 36},{"children": [],"id": 82,"name": "David20","orderNum": 2,"parentId": 36}],"id": 36,"name": "HR","orderNum": 1,"parentId": 14},{"children": [{"children": [],"id": 83,"name": "Eve21","orderNum": 1,"parentId": 37},{"children": [],"id": 84,"name": "Frank22","orderNum": 2,"parentId": 37}],"id": 37,"name": "Development","orderNum": 2,"parentId": 14},{"children": [{"children": [],"id": 85,"name": "Grace23","orderNum": 1,"parentId": 38},{"children": [],"id": 86,"name": "Helen24","orderNum": 2,"parentId": 38}],"id": 38,"name": "Logistics","orderNum": 3,"parentId": 14}],"id": 14,"name": "纽约地区","orderNum": 2,"parentId": 6}],"id": 6,"name": "微软","orderNum": 2,"parentId": 2}],"id": 2,"name": "美国","orderNum": 2,"parentId": 0}
]
四、自定义树节点返回类型(只保留部分字段)
上面我们返回了所有字段信息,如果最终只需要 id 、name 字段呢?
1. 新增 TreeNodeDTO 类
import java.util.ArrayList;
import java.util.List;public class TreeNodeDTO {private Long id;private String name;// 子节点private List<TreeNodeDTO> children = new ArrayList<>();public TreeNodeDTO() {}public TreeNodeDTO(Long id, String name) {this.id = id;this.name = name;}// Getter 和 Setterpublic Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<TreeNodeDTO> getChildren() {return children;}public void setChildren(List<TreeNodeDTO> children) {this.children = children;}
}
2.修改TreeUtil 类
TreeUtil 类中增加 convertToDtoTree 和 convertNode 方法。
TreeUtil 类修改后如下:
package com.hai.tang.util;import com.hai.tang.model.CompanyInfo;
import com.hai.tang.model.TreeNodeDTO;import java.util.*;
import java.util.stream.Collectors;public class TreeUtil {/*** 构建树结构** @param nodes 数据列表* @return 树形结构列表*/public static List<CompanyInfo> buildTree(List<CompanyInfo> nodes) {// 先构建一个 id -> 节点的映射,方便查找父节点Map<Long, CompanyInfo> idNodeMap = nodes.stream().collect(Collectors.toMap(CompanyInfo::getId, node -> node));// 最终返回的树根节点集合List<CompanyInfo> treeRoots = new ArrayList<>();for (CompanyInfo node : nodes) {if (node.getParentId() == 0) {// 顶层节点treeRoots.add(node);} else {// 找到父节点,添加到其 children 中CompanyInfo parent = idNodeMap.get(node.getParentId());if (parent != null) {parent.getChildren().add(node);}}}// 对每层 children 根据 orderNum 排序sortTree(treeRoots);return treeRoots;}private static void sortTree(List<CompanyInfo> nodes) {if (nodes == null || nodes.isEmpty()) return;nodes.sort(Comparator.comparing(CompanyInfo::getOrderNum));for (CompanyInfo node : nodes) {sortTree(node.getChildren());}}/*** 将树结构转换为TreeNodeDTO,即只返回id,和name字段** @param 树形结构列表*/public static List<TreeNodeDTO> convertToDtoTree(List<CompanyInfo> treeNodes) {if (treeNodes == null) return new ArrayList<>();return treeNodes.stream().map(TreeUtil::convertNode).collect(Collectors.toList());}private static TreeNodeDTO convertNode(CompanyInfo node) {TreeNodeDTO dto = new TreeNodeDTO(node.getId(), node.getName());if (node.getChildren() != null && !node.getChildren().isEmpty()) {dto.setChildren(node.getChildren().stream().map(TreeUtil::convertNode).collect(Collectors.toList()));}return dto;}
}
3.测试
public static void main(String[] args) {List<CompanyInfo> flatList = new ArrayList<>();// 国家flatList.add(new CompanyInfo(1L, "中国", 0L, 1));flatList.add(new CompanyInfo(2L, "美国", 0L, 2));// 公司flatList.add(new CompanyInfo(3L, "华为", 1L, 1));flatList.add(new CompanyInfo(4L, "小米", 1L, 2));flatList.add(new CompanyInfo(5L, "谷歌", 2L, 1));flatList.add(new CompanyInfo(6L, "微软", 2L, 2));// 地区flatList.add(new CompanyInfo(7L, "华东地区", 3L, 1));flatList.add(new CompanyInfo(8L, "华南地区", 3L, 2));flatList.add(new CompanyInfo(9L, "华东地区", 4L, 1));flatList.add(new CompanyInfo(10L, "华南地区", 4L, 2));flatList.add(new CompanyInfo(11L, "华盛顿地区", 5L, 1));flatList.add(new CompanyInfo(12L, "纽约地区", 5L, 2));flatList.add(new CompanyInfo(13L, "华盛顿地区", 6L, 1));flatList.add(new CompanyInfo(14L, "纽约地区", 6L, 2));// 部门flatList.add(new CompanyInfo(15L, "人力部", 7L, 1));flatList.add(new CompanyInfo(16L, "开发部", 7L, 2));flatList.add(new CompanyInfo(17L, "后勤部", 7L, 3));flatList.add(new CompanyInfo(18L, "人力部", 8L, 1));flatList.add(new CompanyInfo(19L, "开发部", 8L, 2));flatList.add(new CompanyInfo(20L, "后勤部", 8L, 3));flatList.add(new CompanyInfo(21L, "人力部", 9L, 1));flatList.add(new CompanyInfo(22L, "开发部", 9L, 2));flatList.add(new CompanyInfo(23L, "后勤部", 9L, 3));flatList.add(new CompanyInfo(24L, "人力部", 10L, 1));flatList.add(new CompanyInfo(25L, "开发部", 10L, 2));flatList.add(new CompanyInfo(26L, "后勤部", 10L, 3));flatList.add(new CompanyInfo(27L, "HR", 11L, 1));flatList.add(new CompanyInfo(28L, "Development", 11L, 2));flatList.add(new CompanyInfo(29L, "Logistics", 11L, 3));flatList.add(new CompanyInfo(30L, "HR", 12L, 1));flatList.add(new CompanyInfo(31L, "Development", 12L, 2));flatList.add(new CompanyInfo(32L, "Logistics", 12L, 3));flatList.add(new CompanyInfo(33L, "HR", 13L, 1));flatList.add(new CompanyInfo(34L, "Development", 13L, 2));flatList.add(new CompanyInfo(35L, "Logistics", 13L, 3));flatList.add(new CompanyInfo(36L, "HR", 14L, 1));flatList.add(new CompanyInfo(37L, "Development", 14L, 2));flatList.add(new CompanyInfo(38L, "Logistics", 14L, 3));// 人员flatList.add(new CompanyInfo(39L, "张1", 15L, 1));flatList.add(new CompanyInfo(40L, "李2", 15L, 2));flatList.add(new CompanyInfo(41L, "王3", 16L, 1));flatList.add(new CompanyInfo(42L, "赵4", 16L, 2));flatList.add(new CompanyInfo(43L, "孙5", 17L, 1));flatList.add(new CompanyInfo(44L, "周6", 17L, 2));flatList.add(new CompanyInfo(45L, "钱7", 18L, 1));flatList.add(new CompanyInfo(46L, "吴8", 18L, 2));flatList.add(new CompanyInfo(47L, "张9", 19L, 1));flatList.add(new CompanyInfo(48L, "李10", 19L, 2));flatList.add(new CompanyInfo(49L, "王11", 20L, 1));flatList.add(new CompanyInfo(50L, "赵12", 20L, 2));flatList.add(new CompanyInfo(51L, "孙13", 21L, 1));flatList.add(new CompanyInfo(52L, "周14", 21L, 2));flatList.add(new CompanyInfo(53L, "钱15", 22L, 1));flatList.add(new CompanyInfo(54L, "吴16", 22L, 2));flatList.add(new CompanyInfo(55L, "张17", 23L, 1));flatList.add(new CompanyInfo(56L, "李18", 23L, 2));flatList.add(new CompanyInfo(57L, "王19", 24L, 1));flatList.add(new CompanyInfo(58L, "赵20", 24L, 2));flatList.add(new CompanyInfo(59L, "孙21", 25L, 1));flatList.add(new CompanyInfo(60L, "周22", 25L, 2));flatList.add(new CompanyInfo(61L, "钱23", 26L, 1));flatList.add(new CompanyInfo(62L, "吴24", 26L, 2));flatList.add(new CompanyInfo(63L, "Alice1", 27L, 1));flatList.add(new CompanyInfo(64L, "Bob2", 27L, 2));flatList.add(new CompanyInfo(65L, "Charlie3", 28L, 1));flatList.add(new CompanyInfo(66L, "David4", 28L, 2));flatList.add(new CompanyInfo(67L, "Eve5", 29L, 1));flatList.add(new CompanyInfo(68L, "Frank6", 29L, 2));flatList.add(new CompanyInfo(69L, "Grace7", 30L, 1));flatList.add(new CompanyInfo(70L, "Helen8", 30L, 2));flatList.add(new CompanyInfo(71L, "Alice9", 31L, 1));flatList.add(new CompanyInfo(72L, "Bob10", 31L, 2));flatList.add(new CompanyInfo(73L, "Charlie11", 32L, 1));flatList.add(new CompanyInfo(74L, "David12", 32L, 2));flatList.add(new CompanyInfo(75L, "Eve13", 33L, 1));flatList.add(new CompanyInfo(76L, "Frank14", 33L, 2));flatList.add(new CompanyInfo(77L, "Grace15", 34L, 1));flatList.add(new CompanyInfo(78L, "Helen16", 34L, 2));flatList.add(new CompanyInfo(79L, "Alice17", 35L, 1));flatList.add(new CompanyInfo(80L, "Bob18", 35L, 2));flatList.add(new CompanyInfo(81L, "Charlie19", 36L, 1));flatList.add(new CompanyInfo(82L, "David20", 36L, 2));flatList.add(new CompanyInfo(83L, "Eve21", 37L, 1));flatList.add(new CompanyInfo(84L, "Frank22", 37L, 2));flatList.add(new CompanyInfo(85L, "Grace23", 38L, 1));flatList.add(new CompanyInfo(86L, "Helen24", 38L, 2));List<CompanyInfo> tree = TreeUtil.buildTree(flatList);List<TreeNodeDTO> dtoTree = TreeUtil.convertToDtoTree(tree);System.out.println(JSONObject.toJSONString(dtoTree));}
4.输出
[{"children": [{"children": [{"children": [{"children": [{"children": [],"id": 39,"name": "张1"},{"children": [],"id": 40,"name": "李2"}],"id": 15,"name": "人力部"},{"children": [{"children": [],"id": 41,"name": "王3"},{"children": [],"id": 42,"name": "赵4"}],"id": 16,"name": "开发部"},{"children": [{"children": [],"id": 43,"name": "孙5"},{"children": [],"id": 44,"name": "周6"}],"id": 17,"name": "后勤部"}],"id": 7,"name": "华东地区"},{"children": [{"children": [{"children": [],"id": 45,"name": "钱7"},{"children": [],"id": 46,"name": "吴8"}],"id": 18,"name": "人力部"},{"children": [{"children": [],"id": 47,"name": "张9"},{"children": [],"id": 48,"name": "李10"}],"id": 19,"name": "开发部"},{"children": [{"children": [],"id": 49,"name": "王11"},{"children": [],"id": 50,"name": "赵12"}],"id": 20,"name": "后勤部"}],"id": 8,"name": "华南地区"}],"id": 3,"name": "华为"},{"children": [{"children": [{"children": [{"children": [],"id": 51,"name": "孙13"},{"children": [],"id": 52,"name": "周14"}],"id": 21,"name": "人力部"},{"children": [{"children": [],"id": 53,"name": "钱15"},{"children": [],"id": 54,"name": "吴16"}],"id": 22,"name": "开发部"},{"children": [{"children": [],"id": 55,"name": "张17"},{"children": [],"id": 56,"name": "李18"}],"id": 23,"name": "后勤部"}],"id": 9,"name": "华东地区"},{"children": [{"children": [{"children": [],"id": 57,"name": "王19"},{"children": [],"id": 58,"name": "赵20"}],"id": 24,"name": "人力部"},{"children": [{"children": [],"id": 59,"name": "孙21"},{"children": [],"id": 60,"name": "周22"}],"id": 25,"name": "开发部"},{"children": [{"children": [],"id": 61,"name": "钱23"},{"children": [],"id": 62,"name": "吴24"}],"id": 26,"name": "后勤部"}],"id": 10,"name": "华南地区"}],"id": 4,"name": "小米"}],"id": 1,"name": "中国"},{"children": [{"children": [{"children": [{"children": [{"children": [],"id": 63,"name": "Alice1"},{"children": [],"id": 64,"name": "Bob2"}],"id": 27,"name": "HR"},{"children": [{"children": [],"id": 65,"name": "Charlie3"},{"children": [],"id": 66,"name": "David4"}],"id": 28,"name": "Development"},{"children": [{"children": [],"id": 67,"name": "Eve5"},{"children": [],"id": 68,"name": "Frank6"}],"id": 29,"name": "Logistics"}],"id": 11,"name": "华盛顿地区"},{"children": [{"children": [{"children": [],"id": 69,"name": "Grace7"},{"children": [],"id": 70,"name": "Helen8"}],"id": 30,"name": "HR"},{"children": [{"children": [],"id": 71,"name": "Alice9"},{"children": [],"id": 72,"name": "Bob10"}],"id": 31,"name": "Development"},{"children": [{"children": [],"id": 73,"name": "Charlie11"},{"children": [],"id": 74,"name": "David12"}],"id": 32,"name": "Logistics"}],"id": 12,"name": "纽约地区"}],"id": 5,"name": "谷歌"},{"children": [{"children": [{"children": [{"children": [],"id": 75,"name": "Eve13"},{"children": [],"id": 76,"name": "Frank14"}],"id": 33,"name": "HR"},{"children": [{"children": [],"id": 77,"name": "Grace15"},{"children": [],"id": 78,"name": "Helen16"}],"id": 34,"name": "Development"},{"children": [{"children": [],"id": 79,"name": "Alice17"},{"children": [],"id": 80,"name": "Bob18"}],"id": 35,"name": "Logistics"}],"id": 13,"name": "华盛顿地区"},{"children": [{"children": [{"children": [],"id": 81,"name": "Charlie19"},{"children": [],"id": 82,"name": "David20"}],"id": 36,"name": "HR"},{"children": [{"children": [],"id": 83,"name": "Eve21"},{"children": [],"id": 84,"name": "Frank22"}],"id": 37,"name": "Development"},{"children": [{"children": [],"id": 85,"name": "Grace23"},{"children": [],"id": 86,"name": "Helen24"}],"id": 38,"name": "Logistics"}],"id": 14,"name": "纽约地区"}],"id": 6,"name": "微软"}],"id": 2,"name": "美国"}
]