当前位置: 首页 > article >正文

java 查询树结构数据,无限层级树结构通用方法

1、数据库表数据

2、controller层TestTree简单测试
@RestController
@RequestMapping("/test")
public class testTreeController {
    @Autowired
    private TestTreeService testTreeService;
    @GetMapping("/list")
    public List<TestTree> List(TestTree tree)
    {
        List<TestTree> testTrees = testTreeService.getTreeList(tree);
        return testTrees;
    }
}
3、TestTree实体类
@TableName(value ="test_tree")
@Data
public class TestTree implements TreeNode {
    /**
     * id
     */
    @TableId
    private String id;

    /**
     * 父级id
     */
    private String pid;

    /**
     * 名称
     */
    private String name;

    /**
     * 类型
     */
    private String type;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;

    @TableField(exist = false)
    private List childNodeList = new ArrayList<>();

    @Override
    public void setChildNodeList(List childNodeList) {
        this.childNodeList = childNodeList;
    }

    @Override
    public List getChildNodeList() {
        return childNodeList;
    }
}
4、TestTreeService 接口
public interface TestTreeService extends IService<TestTree> {

   /**
     * 查找树结构List
     * @param tree 查询条件
     * @return 树结构结果
     */
    List<TestTree> getTreeList(TestTree tree);
}
5、TestTreeServiceImpl 实现类
@Service
public class TestTreeServiceImpl extends ServiceImpl<TestTreeMapper, TestTree>
    implements TestTreeService{

    public List<TestTree> selectList(TestTree tree) {
        LambdaQueryWrapper<TestTree> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(ObjectUtil.isNotEmpty(tree.getId()), TestTree::getId, tree.getId());
        queryWrapper.like(ObjectUtil.isNotEmpty(tree.getName()), TestTree::getName, tree.getName());
        queryWrapper.like(ObjectUtil.isNotEmpty(tree.getType()), TestTree::getType, tree.getType());
        return super.list(queryWrapper);
    }

    @Override
    public List<TestTree> getTreeList(TestTree tree) {
        //查询数据
        List<TestTree> list  = this.selectList(tree);
        //封装树结构,通用方法,参数为传入的List
        List<TestTree> treeList = TreeList.getTreeList(list);
        //返回树结构List
        return  treeList;
    }
}
6、构建树结构
6.1、定义TreeNode
public interface TreeNode<E extends TreeNode> {
    /**
     * 获取节点ID
     */
     String getId();


    /**
     * 获取父ID
     */
     String getPid();

     void setChildNodeList(List<E> childNodeList);

    /**
     * 子节点数据
     */
     List<E> getChildNodeList();
}
6.2、构建树结构
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 处理树形结构的数据
 */
public final class TreeList {
    public static <E extends TreeNode> List<E> getTreeList(List<E> allData){
        //通过流操作,过滤出所有pid为空或者为null的节点,就是树的顶层节点
        List<E> topNode = allData.stream().filter(item -> Objects.isNull(item) || StrUtil.isBlank(item.getPid())).collect(Collectors.toList());
        //移除所有pid为空或为null的节点
        allData.removeIf(item->Objects.isNull(item) || StrUtil.isBlank(item.getPid()));
        //将剩余节点按pid分租,结果存储在map中,pid作为键,节点列表作为值
        Map<String, List<E>> map = allData.stream().collect(Collectors.groupingBy(TreeNode::getPid));
        //构建树形结构
        buildTree(topNode,map);
        //返回顶层节点列表
        return topNode;
    }

    //构建树形结构
    public static <E extends TreeNode> void buildTree(List<E> topNode, Map<String,List<E>> map){
        for (E node : topNode) {
            //遍历顶层节点,如果节点为null,则跳过
            if (Objects.isNull(node)){
                continue;
            }
            //获取当前节点的id
            String id = node.getId();
            //从map中获取其子节点列表
            List<E> treeNodes = map.get(id);
            //将其设置为当前节点的子节点列表
            node.setChildNodeList(treeNodes);
            //如果当前节点没有子节点,则继续下一个节点
            if (CollectionUtil.isEmpty(treeNodes)){
                continue;
            }
            //对当前节点的子节点列表递归调用buildTree方法,继续构建树形结构
            buildTree(treeNodes,map);
        }
    }
}
7、postman测试

 结果

[
    {
        "id": "1",
        "pid": null,
        "name": "第一层级",
        "type": "1",
        "childNodeList": [
            {
                "id": "2",
                "pid": "1",
                "name": "第二层级",
                "type": "2",
                "childNodeList": [
                    {
                        "id": "3",
                        "pid": "2",
                        "name": "第三层级",
                        "type": "3",
                        "childNodeList": [
                            {
                                "id": "4",
                                "pid": "3",
                                "name": "第四层级",
                                "type": "4",
                                "childNodeList": [
                                    {
                                        "id": "5",
                                        "pid": "4",
                                        "name": "第五层级",
                                        "type": "5",
                                        "childNodeList": null
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "id": "6",
                        "pid": "2",
                        "name": "次二层级",
                        "type": "6",
                        "childNodeList": null
                    }
                ]
            }
        ]
    }
]

http://www.kler.cn/a/488053.html

相关文章:

  • 前端 图片上鼠标画矩形框,标注文字,任意删除
  • C++ 如何将 gRPC集成到机器人系统中
  • QT自定义工具条渐变背景颜色一例
  • [离线数仓] 总结二、Hive数仓分层开发
  • Android车载音频系统目录
  • TCP 如何获取端口信息
  • 【TI毫米波雷达】DCA1000不使用mmWave Studio的数据采集方法,以及自动化实时数据采集
  • 年度技术突破奖|中兴微电子引领汽车芯片新变革
  • Vue2与Vue3在项目开发中的选择:深入探讨
  • Web枚举:深入了解目标应用系统
  • leetcode39.组合总和
  • Blender 2D动画与MATLAB数学建模:跨界融合的创新实践探索
  • 任务调度系统Quartz.net详解2-Scheduler、Calendar及Listener
  • 【买二赠一——二分、贪心(有误)】
  • 【教程】数据可视化处理之2024年各省GDP排名预测!
  • 理解Unity脚本编译过程:程序集
  • Markdown中甘特图的使用
  • 需求:h5和小程序预览图片需要有当前第几张标识
  • 人工智能知识分享第九天-机器学习_集成学习
  • Center Loss 和 ArcFace Loss 笔记
  • socket网络编程-TC/IP方式
  • 《解锁数据科学的魔法盒子:JupyterLab 全面解析》
  • 什么是VLAN?
  • eslint.config.js和.eslintrc.js有什么区别
  • flutter 开启了服务并隐藏后如何关闭
  • Jmeter_后置处理beanshell