基于Map的树节点-MapTree
# 📚简介
MapTree是Hutool树结构模块中基于LinkedHashMap实现的树节点类,实现了Node接口。它通过转换器将实体对象转化为TreeNodeMap节点实体,属性有序且支持排序,是构建树结构的核心节点类。
# 🌲核心功能
- 动态属性:基于LinkedHashMap实现,支持动态扩展属性
- 父子关联:支持设置和获取父节点,自动关联父节点ID
- 节点遍历:支持深度优先遍历和广度优先遍历
- 节点过滤:支持递归过滤树节点
- 树克隆:支持克隆整个树结构
- 灵活配置:支持自定义节点配置
- 可视化打印:支持打印树结构
# 🎯使用场景
- 动态树结构:需要动态扩展节点属性的场景
- 菜单管理:构建系统菜单树,支持多级菜单
- 组织架构:构建公司部门层级结构
- 分类管理:构建商品分类树、文章分类树等
- 权限管理:构建权限树,实现基于角色的权限控制
# 🚀快速开始
# 创建MapTree节点
// 创建默认配置的MapTree
MapTree<Integer> root = new MapTree<>();
root.setId(1);
root.setName("根节点");
// 创建子节点
MapTree<Integer> child1 = new MapTree<>();
child1.setId(2);
child1.setName("子节点1");
MapTree<Integer> child2 = new MapTree<>();
child2.setId(3);
child2.setName("子节点2");
// 关联父子关系
root.addChildren(child1, child2);
# 树遍历
// 深度优先遍历
root.walk(node -> {
Console.log("深度优先: {}", node.getName());
});
// 广度优先遍历
root.walk(node -> {
Console.log("广度优先: {}", node.getName());
}, true);
# 节点过滤
// 过滤名称包含"子节点"的节点
MapTree<Integer> filteredTree = root.filterNew(node -> {
return node.getName().toString().contains("子节点");
});
# 树克隆
// 克隆树结构
MapTree<Integer> clonedTree = root.cloneTree();
# 📖方法详解
# 构造方法
// 默认构造方法,使用默认配置
MapTree<Integer> tree1 = new MapTree<>();
// 使用自定义配置
TreeNodeConfig config = new TreeNodeConfig();
config.setIdKey("id");
config.setParentIdKey("pid");
MapTree<Integer> tree2 = new MapTree<>(config);
# getId() / setId(T id)
功能:获取/设置节点ID
参数:
id:节点ID
返回值:
getId():返回节点IDsetId():返回当前节点,用于链式调用
使用示例:
// 设置ID
mapTree.setId(1);
// 获取ID
Integer id = mapTree.getId();
# getParentId() / setParentId(T parentId)
功能:获取/设置父节点ID
参数:
parentId:父节点ID
返回值:
getParentId():返回父节点IDsetParentId():返回当前节点,用于链式调用
使用示例:
// 设置父节点ID
mapTree.setParentId(0);
// 获取父节点ID
Integer parentId = mapTree.getParentId();
# getName() / setName(CharSequence name)
功能:获取/设置节点名称
参数:
name:节点名称
返回值:
getName():返回节点名称setName():返回当前节点,用于链式调用
使用示例:
// 设置节点名称
mapTree.setName("节点名称");
// 获取节点名称
CharSequence name = mapTree.getName();
# getWeight() / setWeight(Comparable<?> weight)
功能:获取/设置节点权重,用于排序
参数:
weight:节点权重
返回值:
getWeight():返回节点权重setWeight():返回当前节点,用于链式调用
使用示例:
// 设置节点权重
mapTree.setWeight(100);
// 获取节点权重
Comparable<?> weight = mapTree.getWeight();
# getParent() / setParent(parent)
功能:获取/设置父节点
参数:
parent:父节点
返回值:
getParent():返回父节点setParent():返回当前节点,用于链式调用
使用示例:
// 设置父节点
child.setParent(parent);
// 获取父节点
MapTree<Integer> parent = child.getParent();
# getChildren() / setChildren(children)
功能:获取/设置子节点列表
参数:
children:子节点列表
返回值:
getChildren():返回子节点列表setChildren():返回当前节点,用于链式调用
使用示例:
// 设置子节点列表
List<MapTree<Integer>> children = new ArrayList<>();
mapTree.setChildren(children);
// 获取子节点列表
List<MapTree<Integer>> children = mapTree.getChildren();
# addChildren(children)
功能:添加子节点,同时关联父节点
参数:
children:子节点数组
返回值:返回当前节点,用于链式调用
使用示例:
// 添加子节点
mapTree.addChildren(child1, child2, child3);
# hasChild()
功能:判断节点是否有子节点
返回值:boolean - 是否有子节点
使用示例:
// 判断是否有子节点
boolean hasChild = mapTree.hasChild();
# walk(consumer)
功能:递归遍历树节点,默认深度优先遍历
参数:
consumer:节点处理器
使用示例:
// 深度优先遍历
mapTree.walk(node -> {
Console.log("节点名称: {}", node.getName());
});
# walk(consumer, broadFirst)
功能:递归遍历树节点,支持深度优先和广度优先
参数:
consumer:节点处理器broadFirst:是否广度优先遍历,false为深度优先
使用示例:
// 广度优先遍历
mapTree.walk(node -> {
Console.log("节点名称: {}", node.getName());
}, true);
# filter(predicate)
功能:递归过滤当前树,会修改当前树
参数:
predicate:过滤条件,返回true保留节点
返回值:过滤后的节点,null表示不满足条件
使用示例:
// 过滤ID大于10的节点
MapTree<Integer> filteredTree = mapTree.filter(node -> node.getId() > 10);
# filterNew(predicate)
功能:递归过滤并生成新的树,不修改原树
参数:
predicate:过滤条件,返回true保留节点
返回值:过滤后的新树,null表示不满足条件
使用示例:
// 过滤名称包含"test"的节点
MapTree<Integer> filteredTree = mapTree.filterNew(node -> {
return node.getName().toString().contains("test");
});
# getNode(id)
功能:根据ID查询节点,采用深度优先遍历
参数:
id:节点ID
返回值:查询到的节点,未找到返回null
使用示例:
// 根据ID查询节点
MapTree<Integer> node = mapTree.getNode(10);
# getParentsName(id, includeCurrentNode)
功能:获取指定ID节点的所有父节点名称列表
参数:
id:节点IDincludeCurrentNode:是否包含当前节点
返回值:父节点名称列表
使用示例:
// 获取父节点名称列表
List<CharSequence> parentNames = mapTree.getParentsName(10, true);
# getParentsName(includeCurrentNode)
功能:获取当前节点的所有父节点名称列表
参数:
includeCurrentNode:是否包含当前节点
返回值:父节点名称列表
使用示例:
// 获取当前节点的父节点名称列表
List<CharSequence> parentNames = mapTree.getParentsName(true);
# cloneTree()
功能:克隆整个树结构
返回值:克隆后的树节点
使用示例:
// 克隆树
MapTree<Integer> clonedTree = mapTree.cloneTree();
# putExtra(key, value)
功能:扩展节点属性
参数:
key:属性键value:属性值
使用示例:
// 扩展节点属性
mapTree.putExtra("extra1", "value1");
mapTree.putExtra("extra2", 123);
# 💡注意事项
- 线程安全:MapTree类不是线程安全的,多线程环境下需要加锁保护
- 属性类型:获取属性时需要注意类型转换,特别是自定义扩展属性
- 树遍历性能:对于大型树结构,遍历操作可能影响性能
- 树克隆:克隆树时,节点属性如果是引用类型,不会深度克隆
- 父节点关联:使用addChildren方法添加子节点时,会自动关联父节点
# 📦相关类
- TreeNodeConfig:树节点配置类,用于自定义节点字段映射
- TreeUtil:树结构核心工具类,提供树构建、查询等方法
- TreeBuilder:树构建器,提供流式API构建树结构
- Node:树节点接口,定义了树节点的基本属性和行为
# 🎨扩展使用
# 自定义节点配置
// 自定义节点配置
TreeNodeConfig config = new TreeNodeConfig();
config.setIdKey("id");
config.setParentIdKey("pid");
config.setNameKey("name");
config.setWeightKey("sort");
config.setChildrenKey("children");
// 使用自定义配置创建MapTree
MapTree<Integer> tree = new MapTree<>(config);
tree.setId(1);
tree.setName("自定义配置节点");
tree.setWeight(100);
# 动态扩展属性
// 扩展节点属性
MapTree<Integer> tree = new MapTree<>();
tree.setId(1);
tree.setName("节点");
tree.putExtra("url", "https://hutool.cn");
tree.putExtra("icon", "icon-home");
tree.putExtra("visible", true);
// 获取扩展属性
String url = (String) tree.get("url");
boolean visible = (boolean) tree.get("visible");
# 树结构可视化
// 打印树结构
Console.log(root.toString());
# 树节点过滤
// 过滤权重大于50的节点
MapTree<Integer> filteredTree = root.filterNew(node -> {
Comparable<?> weight = node.getWeight();
return weight != null && Integer.parseInt(weight.toString()) > 50;
});
# 📝总结
MapTree是一个功能强大的树节点类,基于LinkedHashMap实现,支持动态扩展属性、父子关联、节点遍历、节点过滤、树克隆等功能。它提供了灵活的API,适用于各种树结构场景,如菜单管理、组织架构、分类管理等。通过MapTree,开发者可以快速构建和操作各类树状结构,提高开发效率。