package com.ruoyi.common.utils;
|
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
|
import java.util.*;
|
import java.util.function.BiConsumer;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
|
/**
|
* 树结构工具类:根据 parentId 构造树、一次性获取所有叶子节点。
|
* 核心方法为泛型实现,id / parentId / children 通过函数注入,可复用于任何节点类型。
|
*/
|
public class TreeUtils {
|
|
private TreeUtils() {
|
}
|
|
/* ================== 通用方法 ================== */
|
|
/**
|
* 根据 parentId 构造树,O(n) 一次遍历。
|
* 根节点为「父Id不在集合中」的节点;若不存在根节点(如全是自引用的环)则原样返回。
|
*
|
* @param nodes 节点列表
|
* @param idGetter 取节点id
|
* @param parentIdGetter 取父节点id
|
* @param childrenSetter 设置子节点列表
|
*/
|
public static <T, K> List<T> buildTree(
|
List<T> nodes,
|
Function<T, K> idGetter,
|
Function<T, K> parentIdGetter,
|
BiConsumer<T, List<T>> childrenSetter) {
|
if (nodes == null || nodes.isEmpty()) {
|
return new ArrayList<>();
|
}
|
// 按父Id分组,一次遍历拿到每个节点的子列表
|
Map<K, List<T>> byParent = nodes.stream().collect(Collectors.groupingBy(parentIdGetter));
|
for (T node : nodes) {
|
childrenSetter.accept(node, byParent.getOrDefault(idGetter.apply(node), new ArrayList<>()));
|
}
|
Set<K> ids = nodes.stream().map(idGetter).filter(Objects::nonNull).collect(Collectors.toSet());
|
List<T> roots = nodes.stream()
|
.filter(n -> !ids.contains(parentIdGetter.apply(n)))
|
.collect(Collectors.toList());
|
return roots.isEmpty() ? nodes : roots;
|
}
|
|
/**
|
* 一次性获取所有叶子节点:即「id 不出现在任何节点的 parentId 中」的节点,O(n) 一次遍历。
|
*
|
* @param nodes 节点列表
|
* @param idGetter 取节点id
|
* @param parentIdGetter 取父节点id
|
*/
|
public static <T, K> List<T> getLeafNodes(
|
List<T> nodes,
|
Function<T, K> idGetter,
|
Function<T, K> parentIdGetter) {
|
if (nodes == null || nodes.isEmpty()) {
|
return new ArrayList<>();
|
}
|
Set<K> parentIds = nodes.stream()
|
.map(parentIdGetter)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
return nodes.stream()
|
.filter(n -> !parentIds.contains(idGetter.apply(n)))
|
.collect(Collectors.toList());
|
}
|
|
/* ================== SysDept 便捷方法 ================== */
|
|
/**
|
* 根据 SysDept.parentId 构造部门树
|
*/
|
public static List<SysDept> buildDeptTree(List<SysDept> depts) {
|
return buildTree(depts, SysDept::getDeptId, SysDept::getParentId, SysDept::setChildren);
|
}
|
|
/**
|
* 一次性获取所有部门叶子节点
|
*/
|
public static List<SysDept> getLeafDepts(List<SysDept> depts) {
|
return getLeafNodes(depts, SysDept::getHisDeptId, SysDept::getHisParentId);
|
}
|
}
|