先描述一下我的业务需求,随意给出一个会员,查询出这个会员的名称、等级,并且已这个会员为根节点查询出他名下所有的直属会员的名称等级信息,然后一级级向下递归,查出整个树结构图,以树结构形势出参给前台
代码如下:
创建实体类1:该类的主要作用是因为我的业务需求需要展示名称和内容,两个id是用来对比谁是谁的下线的,为了方便,新建一个实体类存储数据库查询出来的数据
package com.aaa.bbb.server.vo;
import lombok.*;
/**
* 树结构用数据库查询数据中转实体类
*/
@Data
public class TreeStructureDtoVo {
//会员id
private String memberId;
//名称
private String name;
//内容
private String value;
//父id
private String parentId;
}
创建实体类2:该类的主要作用是给前台出参用的
package com.aaa.bbb.sever.vo;
import lombok.*;
import java.util.List;
/**
* 树结构出参实体类
*/
@Data
@Builder
public class MemberTreeVo {
//会员id(处理时需要和父id比较,必要字段)
private String memberId;
//名称(业务逻辑需要,非必要字段)
private String name;
//内容(业务逻辑需要,非必要字段)
private String value;
//直属子级集合(必要字段)
private List<MemberTreeVo> children;
}
递归工具类
package com.aaa.bbb.common.utils;
import com.aaa.bbb.server.vo.MemberTreeVo;
import com.aaa.bbb.server.vo.TreeStructureDtoVo;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: 查询会员关系树(工具类需根据业务逻辑更改)
* @author:
*/
public class TreeStructureUtil {
/**
* @param structureDTOS 包括根级在内的所有数据信息集合
* @param rootTree 根级数据信息
*/
public static MemberTreeVo packageTree(List<TreeStructureDtoVo> structureDTOS, MemberTreeVo rootTree){
if (structureDTOS != null && structureDTOS.size() > 0) {
//循环执行judgeObj()方法,->为Lambda 表达式的简写,左侧为入参(无入参可以写‘()’代替),右测为出参或是结果、须执行的方法体等
structureDTOS.forEach(structureDTO -> judgeObj(structureDTO, rootTree));
//判断当前节点是否有下级,如果有,获取所有下级,自己调用自己,没有,就证明已经没有下线了,直接将最终结果return出去
if (rootTree.getChildren() != null && rootTree.getChildren().size() > 0) {
rootTree.getChildren().forEach(r -> packageTree(structureDTOS, r));
}
}
return rootTree;
}
/**
* 递归查询:我的所有下线
* @param treeStructureDtoVo 当前被查询是否是当前节点下线的信息
* @param memberTreeVo 当前需要查询下线的节点信息
*/
public static void judgeObj(TreeStructureDtoVo treeStructureDtoVo, MemberTreeVo memberTreeVo){
//获取当前节点的子级集合参数,如果当前为null的时候声明,不为空证明已经存储过下线数据了,后面的直接add()
List<MemberTreeVo> children = memberTreeVo.getChildren();
if (children == null) {
children = new ArrayList<>();
}
//被查询的数据不是根节点 与 被查询的父id等于当前节点信息的id 需要存入当前节点的子级集合中
if (!treeStructureDtoVo.getParentId().equals("null") && memberTreeVo.getMemberId().equals(treeStructureDtoVo.getParentId())) {
//@Builder
children.add(MemberTreeVo.builder().memberId(treeStructureDtoVo.getMemberId()).name(treeStructureDtoVo.getName()).value(treeStructureDtoVo.getValue()).build());
memberTreeVo.setChildren(children);
}
}
}
实现代码
package com.daka.daka;
import com.alibaba.fastjson.JSON;
import com.daka.dto.TreeStructureDTO;
import com.daka.util.StructureUtils;
import com.daka.vo.Tree;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 处理树
*/
public class StructureOperation {
public static void main(String[] args){
//声明最终出参集合
List<TreeStructureDtoVo> treeList=packData();
System.out.println("树结构param:" + JSON.toJSONString(treeList));
// 开始组装树
// 现先获取根节点(树结构起点的parentId在数据库查询是直接赋值为'null'),下面的treeStructureDtoVo其实就是吧根节点的值单独拿出来,根据parentId的‘null’来区分
TreeStructureDtoVo treeStructureDtoVo = treeList.stream()
.filter(structureDTO -> structureDTO.getParentId().equals("null"))
.collect(Collectors.toList()).get(0);
//根节点赋值
MemberTreeVo rootTree = MemberTreeVo.builder()
.memberId(treeStructureDtoVo.getMemberId())
.name(treeStructureDtoVo.getName())
.value(treeStructureDtoVo.getValue())
.build();
MemberTreeVo tree = TreeStructureUtil.packageTree(sonMemberId, rootTree);
System.out.println("树结构result:" + JSON.toJSONString(tree));
return new ResultUtil<>().setData(tree);
}
/**
* 组装数据(模拟从数据库中获取)
*/
public static List<TreeStructureDTO> packData(){
List<TreeStructureDtoVo> result = new ArrayList<TreeStructureDtoVo>();
result.add(TreeStructureDtoVo.builder().memberId(1L).parentId(null).name("根节点").value("值1").build());
result.add(TreeStructureDtoVo.builder().memberId(2L).parentId(1L).name("1级节点A").value(值2).build());
result.add(TreeStructureDtoVo.builder().memberId(3L).parentId(1L).name("1级节点B").value(值3).build());
result.add(TreeStructureDtoVo.builder().memberId(4L).parentId(2L).name("2级节点A").value(值4).build());
result.add(TreeStructureDtoVo.builder().memberId(5L).parentId(2L).name("2级节点B").value(值5).build());
result.add(TreeStructureDtoVo.builder().memberId(6L).parentId(3L).name("2级节点C").value(值6).build());
result.add(TreeStructureDtoVo.builder().memberId(7L).parentId(5L).name("3级节点A").value(值7).build());
result.add(TreeStructureDtoVo.builder().memberId(8L).parentId(6L).name("3级节点B").value(值8).build());
result.add(TreeStructureDtoVo.builder().memberId(9L).parentId(6L).name("3级节点C").value(值9).build());
return result;
}
}