项目中经常会遇到各种需要以树形结构展示的功能,比较常见的,如菜单树,分类树,部门树等等,如果为每种类型都遍历递归生成树形结构返回给前端,显得有些冗余且麻烦,并且其实逻辑都是一致的,只是遍历的对象不同而已,故其实可以通过面向接口思维,来实现这种通用工具类的实现。
TreeNode用来表示每个树节点的抽象,即需要生成树的对象需要实现此接口。
public interface TreeNode{ T id(); T parentId(); boolean root(); void setChildren(List extends TreeNode > children); List extends TreeNode > getChildren(); }
TreeUtils用来生成树形结构,以及获取所有叶子节点等操作
public class TreeUtils {
public static > List generateTrees(List nodes) {
List roots = new ArrayList<>();
for (Iterator ite = nodes.iterator(); ite.hasNext(); ) {
T node = ite.next();
if (node.root()) {
roots.add(node);
// 从所有节点列表中删除该节点,以免后续重复遍历该节点
ite.remove();
}
}
roots.forEach(r -> {
setChildren(r, nodes);
});
return roots;
}
@SuppressWarnings("all")
public static void setChildren(T parent, List nodes) {
List children = new ArrayList<>();
Object parentId = parent.id();
for (Iterator ite = nodes.iterator(); ite.hasNext(); ) {
T node = ite.next();
if (Objects.equals(node.parentId(), parentId)) {
children.add(node);
// 从所有节点列表中删除该节点,以免后续重复遍历该节点
ite.remove();
}
}
// 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子
if (children.isEmpty()) {
return;
}
parent.setChildren(children);
children.forEach(m -> {
// 递归设置子节点
setChildren(m, nodes);
});
}
public static > List getLeafs(T parent) {
List leafs = new ArrayList<>();
fillLeaf(parent, leafs);
return leafs;
}
@SuppressWarnings("all")
public static void fillLeaf(T parent, List leafs) {
List children = parent.getChildren();
// 如果节点没有子节点则说明为叶子节点
if (CollectionUtils.isEmpty(children)) {
leafs.add(parent);
return;
}
// 递归调用子节点,查找叶子节点
for (T child : children) {
fillLeaf(child, leafs);
}
}
}
具体使用方式之声明树节点对象
@Getter @Setter public class ResourceListVO implements TreeNode{ private Long id; private Long pid; private Integer type; private String name; private String icon; private String code; private Integer status; private List children; @Override public Long id() { return this.id; } @Override public Long parentId() { return this.pid; } @Override public boolean root() { return Objects.equals(this.pid, 0L); } @Override public void setChildren(List children) { this.children = children; } }
具体使用方式之调用
public ListlistByAccountId(Long accountId) { return TreeUtils.generateTrees(BeanUtils.copyProperties(mapper.selectByAccountId(userId), ResourceListVO.class)); }
通过使用TreeUtils工具可以统一方便地生成一切对象的树形结构以及其他一些对树的操作,避免对每个对象都用特定代码生成。使用起来就是几个字简洁方便爽歪歪biu特否。
补充知识:TreeUtil 数据库菜单生成无限级树形结构
1、项目需求:
从数据库从加载所有的菜单出来,菜单中有
id,parentId,name字段
希望能有一个工具帮我进行树形结构重组;
实例类:
package com.lming.chcservice.util;
import lombok.Data;
import java.util.List;
@Data
public class TreeNode {
private String id;
private String parentId;
private String name;
private boolean hasChild;
public TreeNode(String id, String parentId, String name) {
this.id = id;
this.parentId = parentId;
this.name = name;
}
}
工具类:
package com.lming.chcservice.util;
import java.util.ArrayList;
import java.util.linkedHashMap;
import java.util.List;
import java.util.Map;
public class TreeUtil {
public static Map mapArray = new linkedHashMap();
public List menuCommon;
public List
测试结果:
[
{
"id": "1",
"name": "首页",
"parentId": "0",
"hasChild": true,
"childrens": [
{
"id": "3",
"name": "预约",
"parentId": "1",
"hasChildren": false,
"childrens": []
}
]
},
{
"id": "2",
"name": "订单",
"parentId": "0",
"hasChild": true,
"childrens": [
{
"id": "4",
"name": "捐献",
"parentId": "2",
"hasChild": true,
"childrens": [
{
"id": "5",
"name": "我的订单",
"parentId": "4",
"hasChild": true,
"childrens": [
{
"id": "6",
"name": "个人中心",
"parentId": "5",
"hasChild": true,
"childrens": [
{
"id": "7",
"name": "个人中心2",
"parentId": "6",
"hasChildren": false,
"childrens": []
}
]
}
]
}
]
}
]
}
]
实力类不一致怎么办? 自己写一个实体转换类,将类的对象属性转换成上面的实体类,然后在调用,当然最快的方式直接修改实体类即可用。
以上这篇java之TreeUtils生成一切对象树形结构案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持考高分网。



