首页 > 其他分享 >树形结构工具类

树形结构工具类

时间:2024-09-25 15:45:50浏览次数:7  
标签:String menu px pid sys 树形 工具 id 结构

  前言

  日常开发中,树形结构的数据是比较常见的一种数据结构,比如系统菜单、组织机构、数据字典等,有时候需要后端把数据转成树形结构再返回给前端,对此特意封装通用树形结构工具类

  封装了以下方法:

  根据父id,递归获取所有子节点,转为树结构

 

  根据子id,递归获取所有父节点,转为树结构

 

  拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql

   

  依赖hutool

        <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>

 

  完整代码

package cn.huanzi.qch.util;

import cn.hutool.core.bean.BeanUtil;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * 树形结构工具类
 */
public class TreeUtil{

    /**
     * 根据父id,递归获取所有子节点,转为树结构
     *
     * @param idFieldName id字段名称
     * @param pIdFieldName pid字段名称
     * @param childrenFieldName children字段名称
     * @param pxFieldName px字段名称
     * @param pId 父节点id
     * @param allList 所有菜单列表
     * @return 每个根节点下,所有子菜单列表
     */
    public static <M>  List<M> toTreeByParentId(String idFieldName, String pIdFieldName, String childrenFieldName, String pxFieldName,String pId, List<M> allList){
        //子节点
        List<M> childList = new ArrayList<>(allList.size());
        for (int i = 0; i < allList.size(); i++) {
            M model = allList.get(i);

            //遍历所有节点将节点的父id与传过来的根节点的id比较
            //父节点id字段,例如:pid
            if (BeanUtil.getFieldValue(model,pIdFieldName).equals(pId)){
                childList.add(model);

                //删除,减少下次循环次数
                allList.remove(i);
                i--;
            }
        }
        //递归
        for (M model : childList) {
            //主键字段,例如:id,子节点字段,例如:children
            BeanUtil.setFieldValue(model,childrenFieldName,TreeUtil.toTreeByParentId(idFieldName,pIdFieldName,childrenFieldName,pxFieldName,String.valueOf(BeanUtil.getFieldValue(model,idFieldName)), allList));
        }

        //排序字段,例如:px,如果不需要排序可以注释
        if(null != pxFieldName && !pxFieldName.isEmpty()){
            childList.sort(Comparator.comparingInt(m -> Integer.parseInt(String.valueOf(BeanUtil.getFieldValue(m, pxFieldName))))); //排序
        }

        //底层节点的子节点赋空值,节省内存空间
        if(childList.size() <= 0){
            childList = null;
        }

        return childList;
    }
    public static <M>  List<M> toTreeByParentId(String pId, List<M> allList){
        //设置一下默认值
        return TreeUtil.toTreeByParentId("id","pid","children","px",pId,allList);
    }

    /**
     * 根据子id,递归获取所有父节点,转为树结构
     *
     * @param idFieldName id字段名称
     * @param pIdFieldName pid字段名称
     * @param childrenFieldName children字段名称
     * @param cId 子节点id
     * @param allList 所有菜单列表
     * @return 每个根节点下,所有子菜单列表
     */
    public static <M> M toTreeByChildrenId(String idFieldName, String pIdFieldName, String childrenFieldName,String cId, List<M> allList){
        return TreeUtil.toTreeByChildrenId(idFieldName,pIdFieldName,childrenFieldName,null,cId,allList);
    }
    private static <M> M toTreeByChildrenId(String idFieldName, String pIdFieldName, String childrenFieldName,M parent,String cId, List<M> allList){
        //父节点
        M newParent = null;

        for (int i = 0; i < allList.size(); i++) {
            M model = allList.get(i);

            // 相等说明:找出当前节点
            if (BeanUtil.getFieldValue(model,idFieldName).equals(cId)){
                newParent = model;

                //设置子节点
                if(parent != null){
                    ArrayList<M> childList = new ArrayList<>(1);
                    childList.add(parent);
                    BeanUtil.setFieldValue(newParent,childrenFieldName, childList);

                }

                //删除,减少下次循环次数
                allList.remove(i);
                i--;
                break;
            }
        }

        //父节点为空,则说明为顶层节点
        String menuParentId = newParent == null ? "" : String.valueOf(BeanUtil.getFieldValue(newParent,pIdFieldName));
        if("".equals(menuParentId)){
            return parent;
        }

        //父节点递归
        newParent = TreeUtil.toTreeByChildrenId(idFieldName,pIdFieldName,childrenFieldName,newParent,menuParentId,allList);

        return newParent;
    }
    public static <M> M toTreeByChildrenId(String cId, List<M> allList){
        //设置一下默认值
        return TreeUtil.toTreeByChildrenId("id", "pid", "children",null,cId,allList);

    }

    /**
     * 拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql
     * @param select 查询字段,例如: select id
     * @param tableName 表名,例如 sys_dept
     * @param initWhere 查询条件,例如:pid = '-1'
     * @param idField id字段名
     * @param pidField pid字段名
     * @param maxLevel 拼接最大层级
     * @return union拼接好的sql脚本
     */
    public static String getParentSql(String select, String tableName, String initWhere, String idField, String pidField, int maxLevel) {
        return getUnionSql(select,tableName,initWhere,idField,pidField,maxLevel);
    }
    public static String getChildSql(String select, String tableName, String initWhere, String idField, String pidField, int maxLevel) {
        return getUnionSql(select,tableName,initWhere,pidField,idField,maxLevel);
    }
    private static String getUnionSql(String select, String tableName, String initWhere, String whereIn, String selectIn, int maxLevel) {
        StringBuilder stringBuilder = new StringBuilder(select);
        stringBuilder.append(" from ").append(tableName).append(" where 1=1 ");
        if (null != initWhere && !initWhere.isEmpty()) {
            stringBuilder.append(" and ").append(initWhere);
        }

        String tmp = String.format("from %s where %s", tableName, initWhere);

        for(int i = 0; i < maxLevel; ++i) {
            tmp = String.format(" from %s where %s in ( select %s %s)", tableName, whereIn, selectIn, tmp);
            stringBuilder.append(" union ").append(select).append(tmp);
        }

        return stringBuilder.toString();
    }

}
TreeUtil

 

  完整main测试

    /**
     * 测试
     */
    public static void main(String[] args) {
        ArrayList<Menu> list = new ArrayList<>();
        list.add(new Menu("1","-1","系统管理",1));
        list.add(new Menu("11","1","菜单维护",1));
        list.add(new Menu("12","1","角色维护",2));
        list.add(new Menu("13","1","系统安全",3));
        list.add(new Menu("131","13","日志管理",1));
        list.add(new Menu("12","-1","用户管理",2));

        //备份list
        List<Menu> list1 = BeanUtil.copyToList(list, Menu.class);

        List<Menu> menus = TreeUtil.toTreeByParentId("-1", list);
        System.out.println(menus);

        Menu menu = TreeUtil.toTreeByChildrenId("131", list1);
        System.out.println(menu);

        String sql = TreeUtil.getChildSql("select id", "lp_sys_menu", "pid = '-1'", "id", "pid", 3);
        System.out.println(sql);
    }

    /**
     * 测试菜单类
     */
    public static class Menu {
        private String id; //节点id
        private String pid; //父节点id
        private List<Menu> children; //子节点
        private int px; //排序字段
        private String menuName; //菜单名称

        public Menu() {
        }

        public Menu(String id, String pid, String name, int px) {
            this.id = id;
            this.pid = pid;
            this.menuName = name;
            this.px = px;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getPid() {
            return pid;
        }

        public void setPid(String pid) {
            this.pid = pid;
        }

        public List<Menu> getChildren() {
            return children;
        }

        public void setChildren(List<Menu> children) {
            this.children = children;
        }

        public int getPx() {
            return px;
        }

        public void setPx(int px) {
            this.px = px;
        }

        public String getMenuName() {
            return menuName;
        }

        public void setMenuName(String menuName) {
            this.menuName = menuName;
        }

        @Override
        public String toString() {
            return "Menu{" +
                    "id='" + id + '\'' +
                    ", pid='" + pid + '\'' +
                    ", children=" + children +
                    ", px=" + px +
                    ", menuName='" + menuName + '\'' +
                    '}';
        }

    }
View Code

 

  效果展示

[Menu{id='1', pid='-1', children=[Menu{id='11', pid='1', children=null, px=1, menuName='菜单维护'}, Menu{id='12', pid='1', children=null, px=2, menuName='角色维护'}, Menu{id='13', pid='1', children=[Menu{id='131', pid='13', children=null, px=1, menuName='日志管理'}], px=3, menuName='系统安全'}], px=1, menuName='系统管理'}, Menu{id='12', pid='-1', children=null, px=2, menuName='用户管理'}]
Menu{id='1', pid='-1', children=[Menu{id='13', pid='1', children=[Menu{id='131', pid='13', children=null, px=1, menuName='日志管理'}], px=3, menuName='系统安全'}], px=1, menuName='系统管理'}
select id from lp_sys_menu where 1=1  and pid = '-1' union select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1') union select id from lp_sys_menu where pid in ( select id  from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1')) union select id from lp_sys_menu where pid in ( select id  from lp_sys_menu where pid in ( select id  from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1')))

 

  原数据

   根据父id,递归获取所有子节点,转为树结构

   根据子id,递归获取所有父节点,转为树结构

   拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql

SELECT
    id
FROM
    lp_sys_menu
WHERE
    1 = 1
    AND pid = '-1'
UNION
SELECT
    id
FROM
    lp_sys_menu
WHERE
    pid IN (
        SELECT
            id
        FROM
            lp_sys_menu
        WHERE
            pid = '-1'
    )
UNION
SELECT
    id
FROM
    lp_sys_menu
WHERE
    pid IN (
        SELECT
            id
        FROM
            lp_sys_menu
        WHERE
            pid IN (
                SELECT
                    id
                FROM
                    lp_sys_menu
                WHERE
                    pid = '-1'
            )
    )
UNION
SELECT
    id
FROM
    lp_sys_menu
WHERE
    pid IN (
        SELECT
            id
        FROM
            lp_sys_menu
        WHERE
            pid IN (
                SELECT
                    id
                FROM
                    lp_sys_menu
                WHERE
                    pid IN (
                        SELECT
                            id
                        FROM
                            lp_sys_menu
                        WHERE
                            pid = '-1'
                    )
            )
    )

 

 

  后记

  树形结构工具类暂时先记录到这,后续再进行补充

 

标签:String,menu,px,pid,sys,树形,工具,id,结构
From: https://www.cnblogs.com/huanzi-qch/p/18431505

相关文章

  • 2024年开源API工具盘点,覆盖API全生命周期
    2024年经济持续低迷,本文整理一些免费的开源工具,旨在帮助企业组织降低工具的支出成本,能用免费的何必用付费的呢(狗头)?如何高效地管理API的全生命周期——从设计、开发、测试、部署到监控和优化,已经成为每个开发者和技术团队关注的重点。以下工具清单,无论你是刚刚入门API开发,还是经验......
  • 未来写作的革新:5个顶级AI写作工具推荐
    引言在数字化时代,创作和表达的方式正在被人工智能(AI)技术不断革新。AI写作工具不仅能够提高我们的写作效率,还可以激发我们的创作灵感和创意表达。今天,我们来推荐五款顶级的AI写作工具,它们将为您的写作带来前所未有的体验。正文1.文心一格:艺术创作的灵魂伴侣适用场景:创意写作,艺术创......
  • 微信小程序开发工具最新版下载
    最近,下载微信小程序开发工具的时候,因为网络问题,发现不能够直接下载,需要使用代理才行如果你也遇到这个问题,可以通过网盘进行下载。一、官网下载下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html二、网盘下载通过百度网盘分享的文件:微信小程序开发工......
  • 企业如何通过ETL工具实现主数据的同步
    1、主数据的定义与重要性主数据,作为企业的核心数据资产,涵盖了客户、产品、供应商、员工等关键业务实体信息。这些数据的稳定性、共享性和对决策的影响力,使其成为企业运营和战略决策不可或缺的基础。主数据的质量与一致性直接关系到企业运营效率、客户体验及市场竞争力。2、ETL在主......
  • 架构师日记-从数据库发展历程到数据结构设计探析
    一数据库发展史起初,数据的管理方式是文件系统,数据存储在文件中,数据管理和维护都由程序员完成。后来发展出树形结构和网状结构的数据库,但都存在着难以扩展和维护的问题。直到七十年代,关系数据库理论的提出,以表格形式组织数据,数据之间存在关联关系,具有了良好的结构化和规范......
  • Git工具的使用教程二
    1.3时光穿梭机——版本回退版本回退分为两步骤进行操作:步骤:1.查看版本,确定需要回到的时候点  指令:        gitlog        gitlog--pretty=oneline2.回退操作  指令:......
  • CPU内部结构域寄存器
    CPU内部结构域寄存器64位和32位系统区别:寄存器是CPU内部最基本的存储单元。CPU对外是通过总线(地址、控制、数据)来和外部设备交互的,总线的宽度是8位,同时CPU的寄存器也是8位,那么这个CPU就叫8位CPU。如果总线是32位,寄存器也是32位的,那么这......
  • 蓝队自动化应急响应工具(非常详细)零基础入门到精通,收藏这一篇就够了
    最近在工作中遇到了一个挺不错的工具,特别适合我们这些专注于网络安全的技术人员。你知道我们在日常工作中经常需要面对各种安全事件和威胁,有时候真的会感觉自己像在打游击战。不过,有了这个工具,应对安全事件就轻松多了。我最近开始用一个叫做FindAll的工具,它是为蓝队设计的......
  • 如何运用AI工具优化写作过程,提升语言润色、排版及格式调整的效率,掌握SCI期刊的投稿流
    科学研究的核心在于将复杂的思想和实验成果通过严谨的写作有效地传递给学术界和工业界。对于研究生、青年学者及科研人员,如何高效撰写和发表SCI论文,成为提升学术水平和科研成果的重要环节。旨在帮助学员系统掌握从选题到投稿的全过程,提高论文撰写效率与质量,尤其是在当今AI技术......
  • 微软宣称其新工具可纠正人工智能幻觉 但专家依然对此表示怀疑
    人工智能经常胡言乱语,微软现在说它有办法解决这个问题,但我们有理由对此持怀疑态度。微软今天发布了一项名为"更正"(Correction)的服务,它可以自动修改人工智能生成的与事实不符的文本。Correction首先会标记出可能存在错误的文本–例如,公司季度财报电话会议的摘要可能存在错误......