Hutool TreeUtil 教程
一、简介Hutool 的TreeUtil是一个树结构工具类用于处理节点数据构建树形结构如菜单树、组织树、地区树等支持无限级分类。二、核心概念2.1 关键类TreeNode: 树节点配置类定义节点属性id、parentId、children等TreeUtil: 工具类提供构建树的方法三、快速开始3.1 添加依赖dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.26/version /dependency3.2 定义节点类import lombok.Data; import java.util.List; Data public class Menu { private String id; private String parentId; private String name; private Integer sort; private ListMenu children; }四、基本用法4.1 方式一使用 TreeNodeConfigimport cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNodeConfig; import cn.hutool.core.lang.tree.TreeUtil; public class TreeUtilDemo { public static void main(String[] args) { // 构建节点列表 ListMenu menus buildMenuList(); // 配置树节点 TreeNodeConfig config new TreeNodeConfig(); config.setIdKey(id); // 节点ID字段名 config.setParentIdKey(parentId); // 父节点ID字段名 config.setWeightKey(sort); // 排序字段 config.setChildrenKey(children); // 子节点字段名 config.setDeep(3); // 最大深度 // 构建树 ListTreeString treeList TreeUtil.build(menus, 0, config, (menu, tree) - { tree.setId(menu.getId()); tree.setParentId(menu.getParentId()); tree.setName(menu.getName()); tree.setWeight(menu.getSort()); // 添加额外属性 tree.putExtra(extra, 自定义值); }); System.out.println(JSONUtil.toJsonPrettyStr(treeList)); } }4.2 方式二简化版// 如果节点类实现了 TreeNode 接口 ListTreeString treeList TreeUtil.build(menus, 0);五、完整示例5.1 构建菜单树import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNodeConfig; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.json.JSONUtil; import lombok.Data; import java.util.ArrayList; import java.util.List; Data public class Menu { private String id; private String parentId; private String name; private Integer sort; private String path; } public class MenuTreeBuilder { public static ListTreeString buildMenuTree(ListMenu menus) { // 配置 TreeNodeConfig config new TreeNodeConfig(); config.setIdKey(id); config.setParentIdKey(parentId); config.setWeightKey(sort); // 构建树 return TreeUtil.build(menus, 0, config, (menu, tree) - { tree.setId(menu.getId()); tree.setParentId(menu.getParentId()); tree.setName(menu.getName()); tree.setWeight(menu.getSort()); // 自定义字段 tree.putExtra(path, menu.getPath()); tree.putExtra(type, menu); }); } public static void main(String[] args) { ListMenu menus new ArrayList(); // 一级菜单 Menu menu1 new Menu(); menu1.setId(1); menu1.setParentId(0); menu1.setName(系统管理); menu1.setSort(1); menu1.setPath(/system); // 二级菜单 Menu menu11 new Menu(); menu11.setId(11); menu11.setParentId(1); menu11.setName(用户管理); menu11.setSort(1); menu11.setPath(/system/user); Menu menu12 new Menu(); menu12.setId(12); menu12.setParentId(1); menu12.setName(角色管理); menu12.setSort(2); menu12.setPath(/system/role); menus.add(menu1); menus.add(menu11); menus.add(menu12); ListTreeString tree buildMenuTree(menus); System.out.println(JSONUtil.toJsonPrettyStr(tree)); } }5.2 输出结果[ { id: 1, parentId: 0, name: 系统管理, weight: 1, path: /system, type: menu, children: [ { id: 11, parentId: 1, name: 用户管理, weight: 1, path: /system/user, type: menu }, { id: 12, parentId: 1, name: 角色管理, weight: 2, path: /system/role, type: menu } ] } ]六、高级用法6.1 自定义根节点ID// 使用不同的根节点标识 ListTreeString tree TreeUtil.build(nodes, -1, config, (node, tree) - { // 映射逻辑 });6.2 带条件的树构建// 过滤无效节点 ListMenu validMenus menus.stream() .filter(m - m.getStatus() 1) // 只构建启用的菜单 .collect(Collectors.toList()); ListTreeString tree TreeUtil.build(validMenus, 0, config, ...);6.3 多根节点树// 自动识别多个根节点parentId 不在列表中的节点 ListTreeString tree TreeUtil.build(menus, null, config, ...);6.4 获取树中所有节点IDimport cn.hutool.core.lang.tree.Tree; import java.util.ArrayList; import java.util.List; public ListString getAllNodeIds(ListTreeString trees) { ListString ids new ArrayList(); for (TreeString tree : trees) { ids.add(tree.getId()); if (tree.getChildren() ! null) { ids.addAll(getAllNodeIds(tree.getChildren())); } } return ids; }七、常见问题7.1 节点顺序问题// 设置权重字段进行排序 config.setWeightKey(sort); // 或者使用 Comparator config.setComparator(Comparator.comparing(Tree::getWeight));7.2 循环引用问题确保数据本身没有循环引用如A的父ID是BB的父ID是ATreeUtil会处理这种情况但可能导致栈溢出。7.3 性能优化// 大量数据时使用并行流处理 ListTreeString tree TreeUtil.build(menus, 0, config, (menu, tree) - { // 映射逻辑 }); // TreeUtil 内部已优化无需额外处理八、实际应用场景8.1 地区选择器public ListTreeString buildRegionTree(ListRegion regions) { TreeNodeConfig config new TreeNodeConfig(); config.setIdKey(code); config.setParentIdKey(parentCode); config.setWeightKey(orderNum); return TreeUtil.build(regions, 0, config, (region, tree) - { tree.setId(region.getCode()); tree.setParentId(region.getParentCode()); tree.setName(region.getName()); tree.putExtra(level, region.getLevel()); tree.putExtra(zipCode, region.getZipCode()); }); }8.2 部门树public ListTreeString buildDeptTree(ListDepartment depts) { TreeNodeConfig config new TreeNodeConfig(); config.setIdKey(deptId); config.setParentIdKey(parentId); config.setWeightKey(orderNum); config.setDeep(5); return TreeUtil.build(depts, 0, config, (dept, tree) - { tree.setId(dept.getDeptId()); tree.setParentId(dept.getParentId()); tree.setName(dept.getDeptName()); tree.putExtra(leader, dept.getLeader()); tree.putExtra(phone, dept.getPhone()); tree.putExtra(status, dept.getStatus()); }); }九、注意事项数据类型统一: id和parentId建议使用相同数据类型如String或Long根节点标识: 确保根节点的parentId匹配指定的根ID值性能考虑: 大数据量10000时注意性能TreeUtil内部使用Map索引性能良好线程安全: TreeUtil本身是线程安全的但结果需要自行处理空值处理: 如果parentId为null会被当作根节点处理十、总结Hutool TreeUtil 的优势✅ 简单易用代码简洁✅ 性能优秀使用Map索引✅ 配置灵活支持自定义字段✅ 功能完善满足大部分树形结构需求
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2544506.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!