vue3 ts 数组构造树形 VS java 数组构造树形
一、背景
vue3 ts 数组构造树形 VS java 数组构造树形,通常是后端返回树形,但是有一些比较吊的后端就是要返回数组,不管前端死活,未雨绸缪,比较前后端 数组组转 树形结构.
二、实现
同个接口,返回同种数据结构.
其实有用的就是三个字段 id,name,pid,其他字段只是附加说明.
vue3 ts 数组构造树形
vue3 ts 数组构造树形
getSelectData('/api/revWaterUserDoc/queryRevDivision', '', {}).then((data) => {
console.log(buildTree(data)) // 返回的数据直接丢到下面方法中,注意data的数据结构
})
const buildTree = (list:any, pid = 0) =>{ // pid是指对应的父级id,默认为0 也有可能是parentId 为 null 依情况而定.
const tree = [];
for (const item of list) {
if (item.pid === pid) {
const children = buildTree(list, item.id);
if (children.length) {
item.children = children;
}
tree.push(item);
}
}
return tree;
}
java 数组构造树形 (java使用hutool实现列表转树形结构)
java使用hutool实现列表转树形结构
// 任何类型的List<T> 形参:
//list – 源数据集合 parentId – 最顶层父id值 一般为 0 之类 nodeParser – 转换器
//返回值:
//List
List<Tree<Integer>> build = TreeUtil.build(revWaterUserDocPageResult, 0, (node, tree) -> {
tree.setId(node.getId().intValue());
tree.setName(node.getName());
tree.setParentId(node.getPid().intValue());
tree.putExtra("Extra","除上面那三个默认字段,有额外字段显示,可以这么写");
});
java 数组构造树形 (工具类 直接使用 https://gitee.com/lcaiqin/java-tool-related-classes/blob/master/TreeUtil3.java)
注意点:实体类和工具类中的映射字段要存在,可以手动更改.
三种方式组装树形
package me.zhengjie.modules.waterMeter.rest;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author :lcq
* @Date : 2023/5/8 9:52
*/
/**
* 使用前提:
* 主要是根据 反射来 组装树形,所以 要保证 存在下面三个基本属性 id,parentId,children
*/
public class TreeUtil3 {
/**
* 通过递归方式构建树
*
* @param list 列表
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByRecursion(List<T> list) {
return buildTreeByRecursion(list, "id", "parentId", "children");
}
/**
* 通过Map方式构建树
*
* @param list 列表
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByMap(List<T> list) {
return buildTreeByMap(list, "id", "pid", "children", "0");
}
/**
* 通过两层for循环方式构建树
*
* @param list 列表
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByTwoLayersFor(List<T> list) {
return buildTreeByTwoLayersFor(list, "id", "parentId", "children", "0");
}
/**
* 通过递归方式构建树
*
* @param list 列表
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子节点列表名称
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByRecursion(List<T> list, String idName, String parentIdName, String childrenName) {
if (StringUtils.isBlank(idName) || StringUtils.isBlank(parentIdName) || StringUtils.isBlank(childrenName)) {
return new ArrayList<>();
}
List<T> returnList = new ArrayList<>();
//获取list中所有的主键id
List<String> ids = list.stream().map(o -> getFieldValue(o, idName).toString()).collect(Collectors.toList());
for (T t : list) {
String parentId = getFieldValue(t, parentIdName).toString();
//如果是顶级节点, 遍历该父节点的所有子节点,因为顶层的parentId为0
if (!ids.contains(parentId)) {
buildTreeRecursive(list, t, idName, parentIdName, childrenName);
returnList.add(t);
}
}
if (returnList.isEmpty()) {
returnList = list;
}
return returnList;
}
/**
* 递归fn
*
* @param list 分类表
* @param node 子节点
*/
private static <T> void buildTreeRecursive(List<T> list, T node, String idName, String parentIdName, String childrenName) {
// 得到子节点列表
List<T> childList = getChildList(list, node, idName, parentIdName);
setFieldValue(node, childList, childrenName);
for (T child : childList) {
if (hasChild(list, child, idName, parentIdName)) {
buildTreeRecursive(list, child, idName, parentIdName, childrenName);
}
}
}
/**
* 得到子节点列表
*/
private static <T> List<T> getChildList(List<T> list, T node, String idName, String parentIdName) {
List<T> tlist = new ArrayList<>();
String oId = getFieldValue(node, idName).toString();
for (T child : list) {
String tParentId = getFieldValue(child, parentIdName).toString();
if (tParentId.equals(oId)) {
tlist.add(child);
}
}
return tlist;
}
/**
* 判断是否有子节点
*/
private static <T> boolean hasChild(List<T> list, T t, String idName, String parentIdName) {
return getChildList(list, t, idName, parentIdName).size() > 0;
}
/**
* 通过Map方式构建树
*
* @param list 列表
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子节点列表名称
* @param topParentIdVal 顶层节点父id的值
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByMap(List<T> list, String idName, String parentIdName, String childrenName, String topParentIdVal) {
if (StringUtils.isBlank(idName) || StringUtils.isBlank(parentIdName) || StringUtils.isBlank(childrenName)) {
return new ArrayList<>();
}
//根据parentId进行分组
Map<String, List<T>> mapList = list.stream().collect(Collectors.groupingBy(o -> getFieldValue(o, parentIdName).toString()));
//给每个节点设置子节点列表
list.forEach(node -> setFieldValue(node, mapList.get(getFieldValue(node, idName).toString()), childrenName));
return list.stream().filter(o -> topParentIdVal.equals(getFieldValue(o, parentIdName))).collect(Collectors.toList());
}
/**
* 获取属性值
*
* @param o 对象
* @param fieldName 属性名
* @return {@link String}
*/
private static Object getFieldValue(Object o, String fieldName) {
try {
Class<?> oClass = o.getClass();
Field field = oClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(o);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 设置字段值
*
* @param o 对象
* @param val 值
* @param fieldName 属性名
*/
private static void setFieldValue(Object o, Object val, String fieldName) {
try {
Class<?> oClass = o.getClass();
Field field = oClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o, val);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 通过两层for循环方式构建树
*
* @param list 列表
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子节点列表名称
* @param topParentIdVal 顶层节点父id的值
* @return {@link List}<{@link T}>
*/
public static <T> List<T> buildTreeByTwoLayersFor(List<T> list, String idName, String parentIdName, String childrenName, String topParentIdVal) {
List<T> resultList = new ArrayList<>();
for (T node : list) {
//如果是顶层节点
if (topParentIdVal.equals(getFieldValue(node, parentIdName))) {
resultList.add(node);
}
for (T child : list) {
if (getFieldValue(child, parentIdName).equals(getFieldValue(node, idName))) {
List<T> childrenList = (List<T>) getFieldValue(node, childrenName);
if (CollectionUtils.isEmpty(childrenList)) {
childrenList = new ArrayList<>();
setFieldValue(node, childrenList, childrenName);
}
childrenList.add(child);
}
}
}
return resultList;
}
}
结果:
------效果1-buildTreeByMap-----
------效果2-buildTreeByRecursion-----
------效果3 -buildTreeByTwoLayersFor-----
三、遇到的报错
1.实体类和工具类映射的字段不一致,如children 实体类没有.还有就是工具类parentId 但是实体类为Pid ,字段名称不一致.
四、参考博客
本文作者:独而不孤
本文链接:https://www.cnblogs.com/lcaiqin/p/17717793.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步