若依框架---数据转树状层级

简介: 若依框架---数据转树状层级

问题起源


最近在给公司的后台管理系统添加用户管理,部门管理,角色管理等等功能,设计到一个很重要的显示是,树状Tree来显示部门层级结构,如下图:


而数据库mysql中的数据是这样的:


是二维的,扁平的,一行一行的,准确的说,检索出来是一个条状的list,这个list通过parent_id有所关联。


那么,如何将其转换为树状层级结构呢?


通常由两种方式,一种是后台转换,在查询的时候,通过后台程序构造树状结构关联。一种是前端转换,通过javascript来将后端返回的列表list转换为一颗或多颗树。


后台转换


逐层查找


我们先来看看如何通过后端查询来进行转换:


首先查询根部节点:

public List<Record> getDeptTree() {
  List<Record> orgs = Db.find("SELECT dept_id as id, dept_name as `label` FROM sys_dept WHERE parent_id = 0 ORDER by order_num ASC ");
    for (Record o : orgs) {
        buildChildren(o);
    }
    return orgs;    
}


重点关注其中的方法 buildChildren(Record dept),这是一个递归函数:

private void buildChildren(Record org) {
    List<Record> children = getOrgChildren(org.getInt("id"));
    if (!children.isEmpty()) {
        for (Record r : children) {
            buildChildren(r);
        }
        org.set("children", children);
    }
}
private List<Record> getOrgChildren(Integer id) {
    List<Record> children = Db.find("SELECT dept_id as id, dept_name as `label` FROM sys_dept WHERE parent_id = ? ORDER by order_num ASC , id);
    return children;
  }


如此便将其数据从一行一行的数据表中构造为树状结构,如下所示:

[
    {
        "id": 100,
        "label": "若依科技",
        "children": [
            {
                "id": 101,
                "label": "深圳总公司",
                "children": [
                    {
                        "id": 103,
                        "label": "研发部门"
                    },
                    {
                        "id": 104,
                        "label": "市场部门"
                    },
                    {
                        "id": 105,
                        "label": "测试部门"
                    },
                    {
                        "id": 106,
                        "label": "财务部门"
                    },
                    {
                        "id": 107,
                        "label": "运维部门"
                    }
                ]
            },
            {
                "id": 102,
                "label": "长沙分公司",
                "children": [
                    {
                        "id": 108,
                        "label": "市场部门"
                    },
                    {
                        "id": 109,
                        "label": "财务部门"
                    }
                ]
            }
        ]
    }
]


上述算法是我们在自己的数据中重新实现的,


若依中的实现似乎是另一种方式。


检索全部数据算法构造


即一次性检索出全部的数据,然后通过算法来构造树状结构。若依中便是这样来实现的。

@Override
public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts)
{
    List<SysDept> deptTrees = buildDeptTree(depts);
    return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
}
/**
     * 构建前端所需要树结构
     * 
     * @param depts 部门列表
     * @return 树结构列表
     */
    @Override
    public List<SysDept> buildDeptTree(List<SysDept> depts)
    {
        List<SysDept> returnList = new ArrayList<SysDept>();
        List<Long> tempList = new ArrayList<Long>();
        for (SysDept dept : depts)
        {
            tempList.add(dept.getDeptId());
        }
        for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();)
        {
            SysDept dept = (SysDept) iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId()))
            {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty())
        {
            returnList = depts;
        }
        return returnList;
    }


其中的判断语句:

if (!tempList.contains(dept.getParentId())) { ...将节点添加到返回列表中 }


判断的是,当前列表中是否有其父节点,如果某有,说明该节点是最顶级的节点。


再来看其中的递归方法 recursionFn(depts, dept)

/**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t)
    {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                recursionFn(list, tChild);
            }
        }
    }


这里的list总是完整检索的数据,而参数t表示以t为父节点的所有子节点。


获取节点子节点的函数:

/**
     * 得到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t)
    {
        List<SysDept> tlist = new ArrayList<SysDept>();
        Iterator<SysDept> it = list.iterator();
        while (it.hasNext())
        {
            SysDept n = (SysDept) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue())
            {
                tlist.add(n);
            }
        }
        return tlist;
    }


总结


两种方式各有优劣,第二种方式数据库检索次数少,每次检索子节点不需要向数据库发起请求,但是其需要满足能够一次性查询出所有的数据;第一种方式数据库查询次数多,但是如果仅知道一个父节点id通过这种方式来构造数据比较直观,尤其是当你的数据库层级结构设计上没有ancestors字段时。


目录
相关文章
|
SQL 数据库
若依框架---树状层级部门数据库表
若依框架---树状层级部门数据库表
1432 0
若依框架 --- ruoyi 表格的设置
若依框架 --- ruoyi 表格的设置
1977 0
使用ruoyi-vue控制数据权限
使用ruoyi-vue控制数据权限
1773 0
|
缓存
若依 this.$router.push 同地址不同参,页面不刷新问题
若依 this.$router.push 同地址不同参,页面不刷新问题
1582 0
|
SQL 监控 NoSQL
架构师第一课,一文带你玩转 ruoyi 架构
我理解的架构/框架应该有以下功能: 1.满足日常开发功能,如单点登陆、消息队列、监控等; 2.规范开发者的开发,指定代码格式、注释等; 3.提高开发效率,提供一系列的封装方法,并减少bug的产生率。 下文将详细介绍ruoyi框架。
8388 1
架构师第一课,一文带你玩转 ruoyi 架构
|
11月前
|
监控 NoSQL Java
若依RuoYi项目环境搭建教程(RuoYi-Vue + RuoYi-Vue3版本)
若依(RuoYi)是一款基于Spring Boot和Vue.js的开源Java快速开发脚手架,支持OAuth2、JWT鉴权,集成多种安全框架和持久化框架。它提供了系统管理、监控管理、任务调度、代码生成等常用功能模块,适合中小型公司快速搭建Web应用。本文主要介绍若依框架的特点、版本发展、优缺点及项目部署步骤,帮助开发者快速上手并部署若依项目。
13285 3
若依RuoYi项目环境搭建教程(RuoYi-Vue + RuoYi-Vue3版本)
|
SQL XML JavaScript
【若依Java】15分钟玩转若依二次开发,新手小白半小时实现前后端分离项目,springboot+vue3+Element Plus+vite实现Java项目和管理后台网站功能
摘要: 本文档详细介绍了如何使用若依框架快速搭建一个基于SpringBoot和Vue3的前后端分离的Java管理后台。教程涵盖了技术点、准备工作、启动项目、自动生成代码、数据库配置、菜单管理、代码下载和导入、自定义主题样式、代码生成、启动Vue3项目、修改代码、以及对代码进行自定义和扩展,例如单表和主子表的代码生成、树形表的实现、商品列表和分类列表的改造等。整个过程详细地指导了如何从下载项目到配置数据库,再到生成Java和Vue3代码,最后实现前后端的运行和功能定制。此外,还提供了关于软件安装、环境变量配置和代码自动生成的注意事项。
28167 73
|
SQL XML Java
ruoyi若依框架@DataScope注解使用以及碰到的一些问题
ruoyi若依框架@DataScope注解使用以及碰到的一些问题
4730 0
|
前端开发
若依框架------树形菜单
若依框架------树形菜单
1045 0