在构建树时,某些特殊的业务场景下,我们需要从叶子节点向根节点反向构建树,方法如下:
新建数据源对象DataSourcce,一般为从数据库查询到的数据
package bean;
import lombok.Data;
import java.io.Serializable;
@Data
public class DataSource implements Serializable {
private static final long serialVersionUID = 6485359623656969131L;
private Long id;
private String name;
/**
* 父节点id
*/
private Long parentId;
/**
* 是否为叶子节点
*/
private Boolean isLeaf;
}
新建树对象TreeNode,即需要返回的树节点对象
package bean;
import lombok.Data;
import java.util.List;
@Data
public class TreeNode {
private Long id;
private String value;
private String label;
private Long parentId;
private Boolean isLeaf;
private List<TreeNode> children;
}
核心方法buildDataSourceTree
/**
* 从叶子节点构建树
*
* @param orgs 叶子节点集合
* @param parentTree 最终的树
* @return
*/
private List<TreeNode> buildDataSourceTree(List<DataSource> orgs, List<TreeNode> parentTree) {
// 最终树
if (CollectionUtils.isNotEmpty(orgs)) {
// 叶子节点的父节点集合
List<DataSource> parrentOrgsList = new ArrayList<>();
// 根据父节点id分组,便于分批处理减少循环次数 key:父节点id value:此父节点的子节点集合
Map<Long, List<DataSource>> orgMap = orgs.stream().collect(Collectors.groupingBy(DataSource::getParentId));
// copy最终树
final List<TreeNode> finalParentTree = parentTree;
// 是否还有节点未回溯到根节点
AtomicReference<Boolean> isAllRootNode = new AtomicReference<>(false);
// 循环orgMap分批处理
orgMap.forEach((key, value) -> {
// 若父节点id=1,则说明已经到达根节点
if (key == 1L) {
return;
}
isAllRootNode.set(true);
// 查询父节点
Wrapper<DataSource> parentNodeWrapper = Wrappers.<DataSource>lambdaQuery()
.eq(DataSource::getId, key);
DataSource parentOrgs = super.getOne(parentNodeWrapper);
parrentOrgsList.add(parentOrgs);
// 判断父节点是否在树中已存在(只回溯了一层)
for (int i = 0; i < finalParentTree.size(); i++) {
// 如果存在,直接将子树添加到该节点下
if (finalParentTree.get(i).getId().equals(parentOrgs.getId())) {
if (value.get(0).getIsLeaf()) {
finalParentTree.get(i).getChildren().addAll(
Objects.requireNonNull(transToTreeNode(value)));
}
finalParentTree.get(i).getChildren().addAll(getChlidenNode(finalParentTree, key));
return;
}
}
// 在树中不存在,则新建一个节点
TreeNode node = Objects.requireNonNull(transToTreeNode(new ArrayList<DataSource>() {
private static final long serialVersionUID = -8635887848543228675L;
{
add(parentOrgs);
}
})).get(0);
// 构建此层父节点的树,并将父节点的子节点添加到对于父节点下
List<TreeNode> treeNodeVOS = new ArrayList<>();
// 如果是叶子节点,将节点添加进去
if (value.get(0).getIsLeaf()) {
treeNodeVOS.addAll(Objects.requireNonNull(transToTreeNode(value)));
}
// 将子树添加进去
treeNodeVOS.addAll(getChlidenNode(finalParentTree, key));
node.setChildren(treeNodeVOS);
finalParentTree.add(node);
});
// 如果还有节点未回溯到根节点,进入循环构建
if (isAllRootNode.get()) {
buildDataSourceTree(parrentOrgsList, finalParentTree);
}
// 赋值到最终树
parentTree = finalParentTree;
}
return parentTree;
}
/**
* 获取子树
*
* @param parentTree
* @param parentId
* @return
*/
private List<TreeNode> getChlidenNode(List<TreeNode> parentTree, Long parentId) {
List<TreeNode> childen = new ArrayList<>();
for (int i = 0; i < parentTree.size(); i++) {
if (parentId.equals(parentTree.get(i).getParentId())) {
childen.add(parentTree.get(i));
}
}
// 获取子树的同时,将子树从最终树删除
parentTree.removeAll(childen);
return childen;
}
/**
* 转换DataSource为TreeNode
*
* @param list
* @return
*/
private List<TreeNode> transToTreeNode(List<DataSource> list) {
if (CollectionUtils.isEmpty(list)) {
return null;
}
List<TreeNode> tree = new ArrayList<>();
list.forEach(org -> {
TreeNode vo = new TreeNode();
vo.setId(org.getId());
vo.setValue(String.valueOf(org.getId()));
vo.setLabel(org.getName());
vo.setIsLeaf(org.getIsLeaf());
vo.setParentId(org.getParentId());
tree.add(vo);
});
return tree;
}