文章目录

  • 前言
  • 一、List常用业务场景的两种数据类型?
  • 二、封装Tree
  • 1.针对List类型为实体类封装树
  • 2.针对List类型为Map封装树
  • 3.查找当前节点下所有子节点
  • 总结



前言

在Java日常开发中,经常遇到需要组装数据格式为多层级递归树的形式给前端使用,根据具体的业务场景和数据结构封装树的工具类也是各种各样,那么有没有一种通用、简洁、容易理解且高效的方式实现这样的业务场景呢?


一、List常用业务场景的两种数据类型?

一般根据业务场景常用的数据结构类型有List<Entity>和List<Map>这两种数据类型,那么接下来针对这两种类型分别封装树结构

二、封装Tree

1.针对List类型为实体类封装树

实体类代码如下(示例):

import lombok.Data;
import java.util.List;

@Data
public class Entity {
	private String gid; -- 主键
	private String name; -- 名称
	private String parentId; -- 所属父级
	private List<Entity> children; -- 子集合
}

封装Tree代码如下(示例):

import java.util.*;
import org.springframework.util.CollectionUtils;

public class TreeUtil {

	/**
	* 构建树
	* @param parent: 父级目录 入口初始化传 null
	* @param all : 要封装的所有数据集合,包含上下级关系
	*/
	public static List<Entity> buildTree(Entity parent, List<Entity> all) {
		
		if(CollectionUtils.isEmpty(all)) {
			return Collections.emptyList();
		}
		
		if(Objects.isNull(parent)) {
			return all.stream().filter(e -> "0".equals(e.getParentId())).filter(a -> {
				a.setChildren(buildTree(a,all));
				return true;
			}).collect(Collectors.toList());
		}else {
			return all.stream().filter(e -> parent.getGid().equals(e.getParentId())).filter(a -> {
				a.setChildren(buildTree(a,all));
				return true;
			}).collect(Collectors.toList());
		}
	}
}

2.针对List类型为Map封装树

封装Tree代码如下(示例):

import java.util.*;
import org.springframework.util.CollectionUtils;

public class TreeUtil {
	
	/**
	* 构建树
	* @param root : 父级目录 入口初始化传 null
	* @param all : 要封装的所有数据集合,包含上下级关系
	*/
	public static List<Map> buildTree(Map root, List<Map> all) {
		
		if(CollectionUtils.isEmpty(all)) {
			return Collections.emptyList();
		}
		
		if(Objects.isNull(root)) {
			return all.stream().filter(e -> "0".equals(e.get("parent_id")))
					.map(a -> {
						a.put("children", buildTree(a,all));
						return a;
					}
			).collect(Collectors.toList());
		}else {
			return all.stream().filter(e -> root.get("gid").equals(e.get("parent_id")))
					.map(a -> {
						a.put("children", buildTree(a,all));
						return a;
					}
			).collect(Collectors.toList());
		}
	}
}

3.查找当前节点下所有子节点

import java.util.*;
import org.springframework.util.CollectionUtils;

public class TreeUtil {

	/**
	* 查找当前节点下所有子节点
	* @param nodeId : 当前节点
	* @param all : 所有节点数据查找目标集合
	* @param result : 查找的当前节点及节点所有子节点集合
	*/
	public static void findNodeChild(String nodeId, List<Map> all, List<String> result) {
		// 1、查找当前节点下的所有子节点
		List<Map> child = all.stream().filter(a -> nodeId.equals(a.get("parent_id"))).collect(Collectors.toList());
		// 2、添加当前节点
		result.add(nodeId);
		// 3、递归查找
		if(!CollectionUtils.isEmpty(child)) {
			child.stream().forEach(g -> {
				findNodeChild(g.get("gid").toString(),all,result);
			});
		}
	}
}

总结

调用方式:以上封装默认顶级父节点的parent_id赋值为"0"

// 1、调用树
List<Entity> all = jdbc; // 从数据库获取的需要封装的业务数据包含上下级关系那种
List<Entity> result = TreeUtil.buildTree(null,all); // 返回前端的树结构数据
// 2、查找当前节点及其下所有子节点
List<String> result = Lists.newArrayList(); // 当前节点及其下所有子节点gid集合
String nodeId = gid; // 前端传参当前节点gid
TreeUtil.findNodeChild(nodeId,all,result);