适用于需要多叉树业务场景,例如模拟文件夹等
package com.daicy.compowercloud.api;
import com.alibaba.fastjson.annotation.JSONField;
import com.daicy.compowercloud.workfile.model.FileTreeEntity;
import com.google.common.collect.Lists;
import lombok.Data;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author : Duanshaojie
* @ClassName: HashHashTreeNode
* @date 2022-09-13-10:20
* @description :
*/
public class TreeNode<T extends TreeNode.NodeData> {
/**
* 节点数据
*/
private T data;
/**
* 子节点
*/
private List<TreeNode<T>> sonNodes = new LinkedList();
/**
* 当前节点放置子节点
*
* @param data 数据
* @return com.dsj.api.HashTreeNode
* @author duanshaojie
* @date 2022/09/13 10:52
*/
public void putSon(T data) {
TreeNode<T> sonNode = new TreeNode<T>();
sonNode.setData(data);
sonNodes.add(sonNode);
}
/**
* 当前节点放置子节点
*
* @return com.dsj.api.HashTreeNode
* @author duanshaojie
* @date 2022/09/13 10:52
*/
public void putSon(TreeNode<T> sonNode) {
sonNodes.add(sonNode);
}
/**
* 当前节点是否叶子节点
*
* @return boolean
* @author duanshaojie
* @date 2022/09/13 10:53
*/
public boolean isLeafNode() {
return sonNodes.size() == 0;
}
/**
* 获取子节点集合
*
* @return java.util.List<com.dsj.api.HashTreeNode < T>>
* @author duanshaojie
* @date 2022/09/13 10:53
*/
public List<TreeNode<T>> getSonNodeList() {
return this.sonNodes;
}
/**
* 获取所有指定节点的子节点(递归调用)
*
* @param hashTreeNode
* @return java.util.List<com.dsj.api.HashTreeNode < T>>
* @author duanshaojie
* @date 2022/09/13 11:06
*/
private List<TreeNode<T>> getAllSonNode(TreeNode<T> hashTreeNode) {
if (Objects.isNull(hashTreeNode)) {
return Collections.emptyList();
}
List<TreeNode<T>> dataList = new ArrayList<>();
dataList.addAll(sonNodes);
for (TreeNode<T> sonNode : hashTreeNode.getSonNodeList()) {
dataList.addAll(getAllSonNode(sonNode));
}
return dataList;
}
/**
* 获取当前节点数据
*
* @return T
* @author duanshaojie
* @date 2022/09/13 11:07
*/
public T getData() {
return this.data;
}
/**
* 设置当前节点数据
*
* @param data
* @return void
* @author duanshaojie
* @date 2022/09/13 11:07
*/
public void setData(T data) {
this.data = data;
}
/**
* 树化方法
*
* @param dataList
* @return
*/
public TreeNode<T> getTree(List<T> dataList) {
//节点id和节点的映射
Map<String, TreeNode<T>> treeEntityMap = dataList.stream().collect(Collectors.toMap(entity -> entity.getId().toString()
, entity -> {
TreeNode node = new TreeNode<>();
node.setData(entity);
return node;
}));
//根节点
TreeNode<T> rootNode = null;
/**
* 倒着遍历所有数据 保证现将叶子节点放至父节点下后再归位父节点 思路参考归并排序
*/
for (int i = dataList.size() - 1; i >= 0; i--) {
//当前节点
TreeNode<T> thisNode = treeEntityMap.get(dataList.get(i).getId().toString());
//父节点
TreeNode<T> parentNode = treeEntityMap.get(thisNode.getData().getParentId().toString());
/**
* 如果当前节点的父节点在映射表中 则在父节点中添加此节点
*/
if (Objects.nonNull(parentNode)) {
parentNode.putSon(thisNode);
}
/**
* 判断根节点
*/
if (thisNode.getData().getParentId() == 0) {
rootNode = thisNode;
}
}
//返回Map的最前面的节点
return rootNode;
}
public static class NodeData {
Integer id, parentId;
public Integer getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
}
}
使用方法 数据继承TreeNode.NodeData 树化时将数据集合传入getTree()方法 内部会根据id和parentId树化 如需指定根节点请修改根节点判断条件 代码中默认根节点的父节点为0
附带sql
CREATE TABLE file_tree (
id int(11) NOT NULL COMMENT '主键id',
node_name varchar(255) DEFAULT NULL COMMENT '节点名称(用户根节点为用户id)',
parent_id int(11) DEFAULT NULL COMMENT '父id 跟目录为0',
node_type int(11) DEFAULT NULL COMMENT '节点类型:1-文件夹;2-文件;',
bucket_name varchar(60) DEFAULT NULL COMMENT '数据桶名称(文件类型必传)',
file_key varchar(255) DEFAULT NULL COMMENT '文件Key COS文件key',
res_platform int(11) DEFAULT NULL COMMENT '源平台:1-腾讯;',
user_id varchar(60) DEFAULT NULL COMMENT '用户id ',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;