职场萌新最近又碰到头疼的需求,需要把机构数据构造成树型结构传给前端。当时想的是第一次把所有顶级机构传给前端,前端每次展开机构的时候,把当前机构id传给我,我直接找出它的下级机构给前端。因为有了解过一些前端的知识,觉得每次发异步请求,页面理论应该是能够实现的。可是前端小姐姐能力有限,说今天要是不给树结构就找其他小哥哥去联调了,那咱肯定不同意是吧,只能亲自操刀构建树型结构数据。
这里考虑到有的兄弟可能在工作没时间具体看,先上干货吧。
方法一:JDK8流式运算
创建前端所需的dto,其中id、pid、child是必不可少的,其他字段根据实际需求添加。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NodeOrg {
/**
* ID
*/
private Integer id;
/**
* 机构名称
*/
private String nodeName;
/**
* 上级机构ID
*/
private Integer pid;
/**
* 创建时间
*/
private Date creationDate;
private List<NodeOrg> child ;
}
可以像我一样把查出来的所有机构数据用此工具类过滤,也可以直接把下面四步直接写到构建树的服务方法里。
public class TreeUtil {
public static List<NodeOrg> buildTree(List<NodeOrg> nodes) {
//先选出非顶级的节点
List<NodeOrg> list = nodes.stream().filter(node -> node.getPid() != null).collect(Collectors.toList());
//将这些非顶级节点的数据按pid进行分组
Map<Integer, List<NodeOrg>> sub = list.stream().collect(Collectors.groupingBy(node -> node.getPid()));
//循环设置对应的子节点(根据id = pid)
nodes.forEach(node -> node.setChild(sub.get(node.getId())));
//选出父节点数据
List<NodeOrg> collect = nodes.stream().filter(node -> node.getPid() == null).collect(Collectors.toList());
return collect;
}
}
造一些假数据试一试有没有问题。
然后swagger测试一下成果吧。
[
{
"id": 1,
"nodeName": "西瓜科技",
"pid": null,
"creationDate": "2021-02-24T02:23:50.000+0000",
"child": [
{
"id": 2,
"nodeName": "一级部门-01",
"pid": 1,
"creationDate": "2022-08-11T16:43:17.000+0000",
"child": [
{
"id": 6,
"nodeName": "二级部门-01-A1",
"pid": 2,
"creationDate": "2022-08-11T16:43:21.000+0000",
"child": [
{
"id": 8,
"nodeName": "三级部门-01-A1-A1",
"pid": 6,
"creationDate": "2022-08-11T16:43:23.000+0000",
"child": null
}
]
},
{
"id": 7,
"nodeName": "二级部门-01-B1",
"pid": 2,
"creationDate": "2022-08-11T16:43:22.000+0000",
"child": null
}
]
},
{
"id": 3,
"nodeName": "一级部门-02",
"pid": 1,
"creationDate": "2022-08-11T16:43:19.000+0000",
"child": [
{
"id": 9,
"nodeName": "二级部门-02-A2",
"pid": 3,
"creationDate": "2022-08-11T16:43:24.000+0000",
"child": null
}
]
},
{
"id": 4,
"nodeName": "一级部门-03",
"pid": 1,
"creationDate": "2022-08-11T16:43:20.000+0000",
"child": [
{
"id": 10,
"nodeName": "二级部门-03-B3",
"pid": 4,
"creationDate": "2022-08-11T16:43:24.000+0000",
"child": null
}
]
},
{
"id": 5,
"nodeName": "一级部门-04",
"pid": 1,
"creationDate": "2022-08-11T16:43:20.000+0000",
"child": null
}
]
}
]
搞定下班!
方法二:逐步理解,硬撸法
正所谓,授人与鱼,不如授人与渔。有时间的兄弟可以跟我一起学学捕鱼技巧。
其实,构造树型结构就四部,把理念掌握了,实现起来就会有方向。
一、去除顶级节点
//获取非子结点
static List<NodeOrg> getChildTree(List<NodeOrg> node) {
List childList = new ArrayList<>();
for (NodeOrg nodeOrg : node) {
if (nodeOrg.getPid() != null) {
childList.add(nodeOrg);
}
}
return childList;
}
二、将所有子节点按父节点分组
//将父节点相同的分组
static Map<Integer, List<NodeOrg>> groupTree(List<NodeOrg> childList) {
Map<Integer, List<NodeOrg>> map = new HashMap<>();
for (NodeOrg nodeOrg : childList) {
List<NodeOrg> parallelNodeList;
Integer pid = nodeOrg.getPid();
if (map.containsKey(pid)) {
parallelNodeList = map.get(pid);
} else {
parallelNodeList = new ArrayList<>();
}
parallelNodeList.add(nodeOrg);
map.put(pid, parallelNodeList);
}
return map;
}
三、按分组分别注入到对应的父节点中去。
//注入子节点
static void setChildNode(Map<Integer, List<NodeOrg>> groupTree, List<NodeOrg> node) {
Set<Map.Entry<Integer, List<NodeOrg>>> entries = groupTree.entrySet();
for (NodeOrg nodeOrg : node) {
for (Map.Entry<Integer, List<NodeOrg>> entry : entries) {
Integer id = nodeOrg.getId();
Integer key = entry.getKey();
List<NodeOrg> value = entry.getValue();
if (id==key) {
nodeOrg.setChild(value);
}
}
}
}
四、过滤出父节点。
//获取顶级节点数据
static List<NodeOrg> getTopTree(List<NodeOrg> node) {
List<NodeOrg> treeList = new ArrayList<>();
for (NodeOrg nodeOrg : node) {
if (nodeOrg.getPid() != null) {
continue;
}
treeList.add(nodeOrg);
}
return treeList;
}
最后测试一下有没有用。
[
{
"id": 1,
"nodeName": "西瓜科技",
"pid": null,
"creationDate": "2021-02-24T02:23:50.000+0000",
"child": [
{
"id": 2,
"nodeName": "一级部门-01",
"pid": 1,
"creationDate": "2022-08-11T16:43:17.000+0000",
"child": [
{
"id": 6,
"nodeName": "二级部门-01-A1",
"pid": 2,
"creationDate": "2022-08-11T16:43:21.000+0000",
"child": [
{
"id": 8,
"nodeName": "三级部门-01-A1-A1",
"pid": 6,
"creationDate": "2022-08-11T16:43:23.000+0000",
"child": null
}
]
},
{
"id": 7,
"nodeName": "二级部门-01-B1",
"pid": 2,
"creationDate": "2022-08-11T16:43:22.000+0000",
"child": null
}
]
},
{
"id": 3,
"nodeName": "一级部门-02",
"pid": 1,
"creationDate": "2022-08-11T16:43:19.000+0000",
"child": [
{
"id": 9,
"nodeName": "二级部门-02-A2",
"pid": 3,
"creationDate": "2022-08-11T16:43:24.000+0000",
"child": null
}
]
},
{
"id": 4,
"nodeName": "一级部门-03",
"pid": 1,
"creationDate": "2022-08-11T16:43:20.000+0000",
"child": [
{
"id": 10,
"nodeName": "二级部门-03-B3",
"pid": 4,
"creationDate": "2022-08-11T16:43:24.000+0000",
"child": null
}
]
},
{
"id": 5,
"nodeName": "一级部门-04",
"pid": 1,
"creationDate": "2022-08-11T16:43:20.000+0000",
"child": null
}
]
}
]
效果和流式的一模一样!创作不易,点个赞支持一下吧:)