ListToTreeUtil(从数据库查出List转成Tree)
前言:在开发中,经常会碰到需要将数据库中的List转换成一个Tree,例如:评论列表、系统菜单、部门关系、商品分类等等。这个工具类就是用来直接将数据库中的List数据,根据
parentId
和id
字段将其直接转成一个前端可以使用的Tree。
一、实体
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SumTree<T> {
private String id;
private String parentId;
private Boolean hasChildren;
private List<SumTree<T>> children;
}
我们需要编写一个类继承这个类,只要是树形结构,就一定会有id
和parentId
这两个属性。
@Data
public class LocalOrganizeTreeModel extends SumTree {
/**
* 部门名称
*/
private String fullName;
/**
* 机构编码
*/
private String enCode;
/**
* 机构分类
*/
private String category;
/**
* 同步状态
*/
private String syncState;
/**
* 提交状态
*/
private String submitState;
/**
* 描述
*/
private String description;
/**
* 最后修改时间
*/
private Date lastModifyTime;
}
将原有的Entity转换成TreeModel,我们可以使用BeanUtils直接将其拷贝。
List<LocalOrganizesTreeModel> list = new ArrayList<>();
localOrganizes.forEach(localOrganize -> {
LocalOrganizesTreeModel model = new LocalOrganizesTreeModel();
BeanUtils.copyProperties(localOrganize, model);
list.add(model);
});
二、使用工具类直接生成
工具类如下:
import java.util.ArrayList;
import java.util.List;
/***
* 操作树的工具
*/
public class TreeDotUtils {
/**
* 将List转换为Tree
*/
public static <T extends SumTree> List<SumTree<T>> convertListToTreeDot(List<T> tList){
List<SumTree<T>> sumTrees = new ArrayList<>();
if(tList != null && tList.size() > 0){
for(T t:tList){
if(!isTreeDotExist(tList,t.getParentId())){
//不存在以父ID为ID的点,说明是当前点是顶级节点
SumTree<T> tSumTree = getTreeDotByT(t, tList);
sumTrees.add(tSumTree);
}
}
}
return sumTrees;
}
/**
* 根据ID判断该点是否存在
* @MethosName isTreeDotExist
* @Author xiaowd
* @Date 2020/4/22 9:50
* @param tList
* @param id 点ID
* @return java.lang.Boolean
*/
private static <T extends SumTree> Boolean isTreeDotExist(List<T> tList, String id) {
for(T t:tList){
if(t.getId().equals(id)){
return true;
}
}
return false;
}
/**
* 获取指定父点的子树
* @MethosName getChildTreeList
* @Author xiaowd
* @Date 2020/4/22 10:02
* @param parentTreeDot 父点
* @param tList
* @return java.util.List<cn.eshore.common.entity.Tree<T>>
*/
private static <T extends SumTree> List<SumTree<T>> getChildTreeDotList(SumTree<T> parentTreeDot, List<T> tList){
List<SumTree<T>> childTreeDotList = new ArrayList<>();
for(T t:tList){
if(parentTreeDot.getId().equals(t.getParentId())){
//如果父ID是传递树点的ID,那么就是传递树点的子点
SumTree<T> tSumTree = getTreeDotByT(t,tList);
childTreeDotList.add(tSumTree);
}
}
return childTreeDotList;
}
/**
* 根据实体获取TreeDot
* @MethosName getTreeDotByT
* @Author xiaowd
* @Date 2020/5/4 22:17
* @param t
* @param tList
* @return pri.xiaowd.layui.pojo.TreeDot<T>
*/
private static <T extends SumTree> SumTree<T> getTreeDotByT(T t,List<T> tList){
SumTree<T> sumTree = t;
List<SumTree<T>> children = getChildTreeDotList(sumTree,tList);
sumTree.setHasChildren(children.size()==0?false:true);
if(children.size()==0){
children=null;
}
sumTree.setChildren(children);
return sumTree;
}
}
调用方法:
List<SumTree<LocalOrganizesTreeModel>> sumTrees = TreeDotUtils.convertListToTreeDot(list);
这个sumTrees就是封装好了的树。
三、JDK1.8 Stram流3行实现转换
// 先将List按parentId分组,分别放在一个map中
Map<String, List<LocalOrganizes>> byParentId = localOrganizes.stream().collect(Collectors.groupingBy(LocalOrganizes::getParentId));
// 将其放入对应的组织下
localOrganizes.forEach(localOrganize -> localOrganize.setChildren(byParentId.get(localOrganize.getId())));
// 只留下根节点,本例中根节点父ID为-1。具体视情况而定。
localOrganizes.stream().filter(localOrganize -> localOrganize.getParentId().equals(-1));
四、使用嵌套for循环
List<LocalOrganizes> result = new ArrayList<>();
for (LocalOrganizes organize : localOrganizes) {
// 找到根节点, 放入结果集中
if (organize.getParentId().equals("-1")) {
result.add(organize);
}
// 寻找这个节点的孩子
for (LocalOrganizes child : localOrganizes) {
if (child.getParentId().equals(organize.getId())) {
organize.getChildren().add(child);
}
}
}