列表转换成Tree型结构数据
前情提要
本文是作者第一篇文章,内容参考某位大大的一个树形结构的代码进行更改优化而来,如果哪位看到有人发的类似文章请在下面评论区中告知,作者会及时转载。
满足作者目前使用的项目,如果有什么问题请在评论区回复。
maven包
<!-- beanutils-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.0</version>
</dependency>
代码部分
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 集合转树
*
* @author hwj
* @since 2022-07-29
*/
public class TreeUtil {
/**
* 把列表转换为树结构 根节点固定为空
*
* @param originalList 原始list数据
* @param keyName 作为唯一标示的字段名称
* @param parentFieldName 模型中作为parent字段名称
* @param childrenFieldName 模型中作为children的字段名称
* @return 组装后的集合
*/
public static <T> List<T> getTree(List<T> originalList, String keyName, String parentFieldName,
String childrenFieldName) throws Exception {
// 获取根节点,即找出父节点为空的对象
List<T> topList = new ArrayList<>();
for (int i = 0; i < originalList.size(); i++) {
T t = originalList.get(i);
String parentId = BeanUtils.getProperty(t, parentFieldName);
if (StringUtils.isBlank(parentId)) {
topList.add(t);
}
}
// 将根节点从原始list移除,减少下次处理数据
originalList.removeAll(topList);
// 递归封装树
fillTree(topList, originalList, keyName, parentFieldName, childrenFieldName);
return topList;
}
/**
* 把列表转换为树结构 根节点为入参
*
* @param originalList 原始list数据
* @param keyName 作为唯一标示的字段名称
* @param parentFieldName 模型中作为parent字段名称
* @param rootId 模型中作为根节点的字段值
* @param childrenFieldName 模型中作为children的字段名称
* @return 组装后的集合
*/
public static <T> List<T> getTree(List<T> originalList, String keyName, String parentFieldName,
String rootId, String childrenFieldName) throws Exception {
// 获取根节点,即找出父节点为空的对象
List<T> topList = new ArrayList<>();
for (int i = 0; i < originalList.size(); i++) {
T t = originalList.get(i);
//获取上级id的值
String parentId = BeanUtils.getProperty(t, parentFieldName);
//判断上级id值是否是传入的根节点
if (StringUtils.equals(parentId, rootId)) {
topList.add(t);
}
}
// 将根节点从原始list移除,减少下次处理数据
originalList.removeAll(topList);
// 递归封装树
fillTree(topList, originalList, keyName, parentFieldName, childrenFieldName);
return topList;
}
/**
* 封装树
*
* @param parentList 要封装为树的父对象集合
* @param originalList 原始list数据
* @param keyName 作为唯一标示的字段名称
* @param parentFieldName 模型中作为parent字段名称
* @param childrenFieldName 模型中作为children的字段名称
*/
public static <T> void fillTree(List<T> parentList, List<T> originalList, String keyName, String parentFieldName,
String childrenFieldName) throws Exception {
for (int i = 0; i < parentList.size(); i++) {
List<T> children = fillChildren(parentList.get(i), originalList, keyName,
parentFieldName, childrenFieldName);
if (children.isEmpty()) {
continue;
}
originalList.removeAll(children);
fillTree(children, originalList, keyName, parentFieldName, childrenFieldName);
}
}
/**
* 封装子对象
*
* @param parent 父对象
* @param originalList 待处理对象集合
* @param keyName 作为唯一标示的字段名称
* @param parentFieldName 模型中作为parent字段名称
* @param childrenFieldName 模型中作为children的字段名称
*/
public static <T> List<T> fillChildren(T parent, List<T> originalList, String keyName, String parentFieldName,
String childrenFieldName) throws Exception {
List<T> childList = new ArrayList<>();
String parentId = BeanUtils.getProperty(parent, keyName);
for (int i = 0; i < originalList.size(); i++) {
T t = originalList.get(i);
String childParentId = BeanUtils.getProperty(t, parentFieldName);
if (parentId.equals(childParentId)) {
childList.add(t);
}
}
if (!childList.isEmpty()) {
FieldUtils.writeDeclaredField(parent, childrenFieldName, childList, true);
}
return childList;
}
}
调用方法生成树
//查询菜单树 "id", "parentId", "children"为生成菜单结构的字段名,可以任意更换
List<Menu> menuList = this.list();
//返回的树形结构
List<Menu> tree;
try {
tree = TreeUtil.getTree(menuList , "id", "parentId", "children");
} catch (Exception e) {
log.error(e.getMessage(), e);
}
菜单实体类 删除了部分无用字段 如果有错误可以在评论区评论
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ApiModel
@Data
public class Menu implements Serializable {
/**
* id
*/
@ApiModelProperty("id")
private String id;
/**
* 菜单名称
*/
@ApiModelProperty("菜单名称")
private String name;
/**
* 上级菜单id
*/
@ApiModelProperty("上级菜单id")
private String parentId;
/**
* 上级菜单名称
*/
@ApiModelProperty("上级菜单名称")
private String parentName;
/**
* 菜单路径
*/
@ApiModelProperty("菜单路径")
private String url;
/**
* 菜单地址
*/
@ApiModelProperty("菜单地址")
private String path;
/**
* 下级节点
*/
@ApiModelProperty("下级节点")
private List<Menu> children;
}