递归创建树形结构数据
创建一个树形结构对象,然后用递归算法,返回前端一个树形的list集合
1、先创建实体对象,树形结构必须要有关联的pid字段
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Node implements IBaseTree{
/**
* 主键id
*/
private Integer id;
/**
* 名称
*/
private String name;
/**
* 关联父id
*/
private Integer pid;
/**
* 关联子对象集合
*/
private List<Node> children = new ArrayList<>();
public Node(Integer id,String name,Integer pid){
this.id = id;
this.name = name;
this.pid = pid;
}
}
2、下面是转换数据的工具类:直接使用的是递归算法
public class TreeUtil {
/**
* 建树
* @param list
* @return
*/
public static List<Node> build(List<Node> list){
List<Node> res = new ArrayList<>();
for (Node node : list) {
//如果是父节点,就查找下面所有字节点添加到子节点的集合中,也可以先把所有一级节点过滤出来遍历
if(node.getPid()==0){
buildChildren(node,list);
res.add(node);
}
}
return res;
}
/**
* 递归查找一个节点下的所有子节点
* @param node
* @param list
*/
public static void buildChildren(Node node,List<Node> list){
//将所有的一级子节点查询出来
List<Node> children = list.stream().filter(p->p.getPid().equals(node.getId())).collect(Collectors.toList());
//如果一级子节点不为空,开始递归查找所有节点,直到子节点集合为空停止
if(!CollectionUtils.isEmpty(children)){
for (Node n : children) {
buildChildren(n,list);
}
node.setChildren(children);
}
}
}
下面是单元测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceControllerTest {
@Test
public void test01() throws Exception {
List<Node> nodes = new ArrayList<>();
nodes.add(new Node(1,"湖北",0));
nodes.add(new Node(2,"湖南",0));
nodes.add(new Node(3,"武汉",1));
nodes.add(new Node(4,"武昌区",3));
nodes.add(new Node(5,"黄冈",1));
List<Node> list = TreeUtil.build(nodes);
System.err.println(list);
}
}
上面这个是递归创建树形结构的基本思路和代码,但是不能当成工具类使用,下面是将整个建树的过程进行封装抽取成一套工具类的过程:
1、这个是抽取的返回的树形结构对象:基本结构是对象及下面的子对象集合,如果有多层就封装在children中
@Data
public class Ztree<T> {
private T t;
private List<T> children;
}
2、对实体的抽取和封装,BaseEntity可以用来抽取数据库建表是的必填字段(id,create_time,update_time,del),IBaseTree抽取的是针对的树形结构的数据,一般都是自关联的表,有pid字段的,Type 就是实体类,用来继承和实现需要的Base类/接口
@Data
public abstract class BaseEntity<E> implements Serializable {
@Id
@JsonSerialize(using = ToStringSerializer.class)
@GeneratedValue(generator = "JDBC")
private E id;
}
public interface IBaseTree {
void setPid(Integer pid);
Integer getPid();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Type extends BaseEntity<Integer> implements IBaseTree {
private Integer pid;
private String name;
}
3 、工具类的抽取
public class TreeUtil {
/**
*
* @param list 传入查询到的所有的list数据
* @return 返回Ztree的list对象,已经转换成树形结构
*/
public static <T extends BaseEntity & IBaseTree> List<Ztree> getTree(List<T> list){
List<Ztree> res = new ArrayList<>();
List<T> collect = list.stream().filter(p -> p.getPid() == 0).collect(Collectors.toList());
for (T t : collect) {
Ztree ztree = new Ztree();
setZtree(t, list, ztree);
res.add(ztree);
}
return res;
}
/**
* @param t
* @param list 整个数据的list集合
* @param ztree
*/
private static <T extends BaseEntity & IBaseTree> void setZtree(T t, List<T> list, Ztree ztree) {
ztree.setT(t);
ztree.setChildren(getChildrens(t, list));
}
/**
*
* @param t
* @param list 整个数据的list集合
* @return
*/
private static <T extends BaseEntity & IBaseTree> List getChildrens(T t, List<T> list) {
List res = new ArrayList<>();
for (T l : list) {
Ztree ztree = new Ztree();
if(Objects.equals(l.getPid(), t.getId())){
setZtree(l, list, ztree);
res.add(ztree);
}
}
return res;
}
}
4、单元测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceControllerTest {
@Test
public void test01() throws Exception {
Type type1 = new Type(0,"湖北");
type1.setId(1);
Type type2 = new Type(0,"湖南");
type2.setId(2);
Type type3 = new Type(1,"武汉");
type3.setId(3);
Type type4 = new Type(1,"黄冈");
type4.setId(4);
Type type5 = new Type(2,"长沙");
type5.setId(5);
Type type6 = new Type(4,"黄梅");
type6.setId(6);
List<Type> list = Arrays.asList(type1,type2,type3,type4,type5,type6);
List<Ztree> ztrees = TreeUtil.getTree(list);
System.err.println(ztrees);
}
}