后端树形结构

如何将后端传到前端的对象数组转化成树形结构的对象数组 具体实现原理请参考:https://blog.youkuaiyun.com/w1418899532/article/details/90065633 一、问题描述 需要被转化的对象数组: this.state = { test : [ {id: 7, name: '快鱼', pid: 2}, {id: 8, name: '海澜之家', ... 阅读详情

案例

在后端开发中,树形结构数据的查询和处理是一个常见的需求,比如部门管理、分类目录展示等场景。接下来,我们以一个部门管理系统为例,详细介绍如何实现后端的树查询功能。

案例背景

假设我们正在开发一个公司的内部管理系统,其中部门管理模块需要展示部门之间的层级关系。部门数据以树形结构存储,每个部门都有自己的上级部门(根部门的上级部门 ID 为 0),我们需要实现接口查询出扁平结构的部门列表以及树形结构的部门数据。

表结构

CREATE TABLE `department_info` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '部门ID',
  `dep_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '部门名称',
  `level` int NOT NULL COMMENT '层级',
  `parent_id` int NOT NULL COMMENT '父ID,0表示根节点',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;

在这里插入图片描述

在这个表结构中,id作为部门的唯一标识;dep_name存储部门名称;level表示部门在树形结构中的层级,方便后续对层级关系的处理;parent_id用于标识该部门的父部门,当parent_id为 0 时,表示该部门是根部门。

实体结构设计

在 Java 代码中,我们创建ParentDepartment实体类来映射数据库表中的数据,代码如下:

/**
 * 父子关系方案部门实体类
 * @TableName department_info
 */
@TableName(value = "department_info")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ParentDepartment implements Serializable {

    // 序列化版本号
    private static final long serialVersionUID = 1L;

    /**
     * 部门ID
     */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
     * 部门名称
     */
    private String depName;

    /**
     * 部门层级
     */
    private Integer level;

    /**
     * 父部门ID(0表示根节点)
     */
    private Integer parentId;

    /**
     * 子节点列表(非数据库字段)
     */
    @TableField(exist = false)
    private List<ParentDepartment> children;

    /**
     * 是否为叶子节点(非数据库字段)
     */
    @TableField(exist = false)
    private Boolean isLeaf;
}

实现思路

方法一:递归实现

递归是一种经典的处理树形结构数据的方法。基本思路是:首先从数据库中查询出所有的部门数据,然后找到所有根部门(即parent_id为 0 的部门),对于每个根部门,递归地查找它的子部门,将子部门添加到根部门的children列表中,直到所有部门都被正确添加到树形结构中。

    /**
     * 将扁平的部门列表转换为树形结构的部门列表。
     * 该方法会先找出所有根部门(即父部门ID为0的部门),
     * 然后递归构建每个根部门的子树。
     * 
     * @param allDepartments 包含所有部门信息的扁平列表
     * @return 包含所有根部门及其子部门的树形结构列表
     */
    public List<ParentDepartment> formatToTree(List<ParentDepartment> allDepartments) {
        // 用于存储所有根部门的列表
        List<ParentDepartment> rootDepartments = new ArrayList<>();
        // 遍历所有部门,找出父部门ID为0的根部门
        for (ParentDepartment department : allDepartments) {
            if (department.getParentId() == 0) {
                // 将根部门添加到根部门列表中
                rootDepartments.add(department);
            }
        }

        // 遍历所有根部门,为每个根部门构建子树
        for (ParentDepartment root : rootDepartments) {
            buildTree(root, allDepartments);
        }

        // 返回包含所有根部门及其子部门的树形结构列表
        return rootDepartments;
    }

    /**
     * 递归构建指定父部门的子树。
     * 该方法会遍历所有部门,找出当前父部门的所有子部门,
     * 并为每个子部门递归调用自身构建子树。
     * 
     * @param parent 父部门对象
     * @param allDepartments 包含所有部门信息的扁平列表
     */
    private void buildTree(ParentDepartment parent, List<ParentDepartment> allDepartments) {
        // 用于存储当前父部门的所有子部门的列表
        List<ParentDepartment> children = new ArrayList<>();
        // 遍历所有部门,找出当前父部门的子部门
        for (ParentDepartment department : allDepartments) {
            if (department.getParentId().equals(parent.getId())) {
                // 将子部门添加到子部门列表中
                children.add(department);
                // 递归构建子部门的子树
                buildTree(department, allDepartments);
            }
        }
        // 为父部门设置子部门列表
        parent.setChildren(children);
    }

方法二:hutool工具实现

Hutool 是一个功能丰富的 Java 工具类库,其中提供了方便的树形结构处理工具。使用 Hutool 实现树形结构查询更加简洁高效。

首先,需要在项目的pom.xml文件中引入 Hutool 依赖:

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

实现树形结构查询的代码如下:

/**
 * 将扁平化的部门列表转换为树形结构
 * @param departments 扁平部门列表(需包含至少id, parentId, depName字段)
 * @return 树形结构列表(多个顶级节点构成森林结构)
 */
public List<Tree<String>> formatToTreeSimple(List<ParentDepartment> departments) {
    // 1. 防御性编程:处理空输入
    if (CollUtil.isEmpty(departments)) {
        // 返回不可变空集合而非null,避免调用方NPE
        return Collections.emptyList();
    }

    // 2. 初始化树节点配置
    TreeNodeConfig config = new TreeNodeConfig();
    // 指定实体类字段与树节点属性的映射关系
    config.setIdKey("id");            // 节点ID对应实体类的id字段
    config.setParentIdKey("parentId");// 父节点ID对应实体类的parentId字段
    config.setChildrenKey("children");// 子节点集合的字段名称
    config.setNameKey("name");        // 节点显示名称对应实体类的depName字段

    // 3. 构建树形结构
    return TreeUtil.build(
        departments,   // 数据源集合
        "0",          // 根节点的父ID值(通常为0或null)
        config,       // 树配置
        (dept, tree) -> { // 自定义字段映射处理器
            // ---- 核心字段映射 ----
            // 设置节点ID(需转为String类型)
            tree.setId(dept.getId().toString());
            // 设置父节点ID(需转为String类型)
            tree.setParentId(dept.getParentId().toString());
            // 设置节点显示名称
            tree.setName(dept.getDepName());

            // ---- 扩展业务字段 ----
            // 添加部门层级信息
            tree.putExtra("level", dept.getLevel());
            // 添加叶子节点标记(根据children是否为空自动计算)
            tree.putExtra("isLeaf", dept.getIsLeaf());
            
            // 可继续添加其他业务字段...
            // tree.putExtra("manager", dept.getManagerName());
        }
    );
    // 注:返回的List可能包含多个顶级节点(森林结构)
    // 通常业务中只有一个parentId="0"的根节点,可用get(0)获取
}

在这段代码中,我们先创建TreeNodeConfig对象,配置好 ID、父 ID、子节点列表以及名称对应的属性名。然后调用TreeUtil.build方法,传入部门数据列表、根节点 ID、配置对象以及一个函数式接口,在函数式接口中,我们将部门实体类的属性赋值给Tree对象,并可以根据业务需求添加额外的扩展字段。

在后端树查询的实现中,tree.putExtra("level", dept.getLevel()); 和 tree.putExtra("isLeaf", dept.getIsLeaf()); 这两行代码的作用是向树形结构的节点对象 tree 中添加额外的业务数据字段,也就是扩展字段 ,具体来说,它们的作用体现在以下几个方面:

  • 丰富节点信息:默认情况下,树形结构的节点可能只包含基础的标识信息(如节点 ID、父节点 ID、节点名称等)。通过添加level和isLeaf字段,可以让每个节点携带更多与业务相关的信息。比如level字段表示部门在树形结构中的层级,前端拿到数据后,就可以根据层级来设置不同的缩进样式,直观展示部门的层级关系;isLeaf字段表示该节点是否为叶子节点(即是否有子节点),这在前端进行交互操作时很有用,例如可以根据是否为叶子节点来决定是否显示展开 / 收缩按钮。
  • 方便业务处理:在实际业务中,很多操作需要依赖这些额外的信息。比如在权限管理中,可能不同层级的部门有不同的权限;在数据统计时,可能需要区分叶子节点和非叶子节点进行不同的计算。将这些字段直接附加到树形结构的节点中,在后续业务逻辑处理时,就无需再通过复杂的查询或计算来获取,提高开发效率。
  • 增强数据通用性:添加扩展字段使树形结构数据更具通用性和灵活性。即使当前业务不需要这些字段,未来如果有新的功能需求,比如添加部门层级相关的筛选功能,或者根据叶子节点状态进行特殊展示等,已经存在的扩展字段就能直接使用,而不需要对数据结构和代码进行大规模修改。
Java实现树形层级结构的表格 Java实现的,将树形层级结构的数据转换成表格,通过打点的方式向表格中插入数据,支持行头表格、列头表格、交叉表格三种形式 立即下载

相关推荐

Bootstrap整理的各种后台管理模块和树状结构导航

Bootstrap整理的各种后台管理模块和树状结构导航

后端树结构分类数据模型如何设计

树形结构在后端系统中非常常见,特别是分类管理场景,例如商品分类、组织架构等。本文将以给定的数据库表为例,探讨如何设计树结构分类数据模型及其优点。

Mylqs的博客 895

强大后台管理的树形目录源码

强大后台管理的树形目录源码,可自由添加、修改、删除节点,也很漂亮的树

java后端操作树结构

使用场景:当我们得到一个树形结构数据时,可能需要在树形结构上对数据进行筛选,例如通过文件夹(文件)名称模糊查询相关的文件夹并展现其父级。缺点:需要查询出完整的树形结构才能用作筛选,在数据量非常庞大的时候并不适用。stream流递归方法。(2)双层for循环。

不定时分享最优质的网络技术与教程,满满的干货。 682

java树形结构

$(function(){ $.fn.extend({ SimpleTree:function(options){ //初始化参数 var option = $.extend({ click:function(a){ } },options); option.tree=this; /* 在参数对象中添加对当前菜单树的引用,以便在对象中使用该菜单树 */ option._init=function(){ /* * 初始化菜单展开状态,以及分叉节点的样式 */ this.tree.find("ul ul").hide(); /* 隐藏所有子级菜单 */ this.tree.find("ul ul").prev("li").removeClass("open"); /* 移除所有子级菜单父节点的 open 样式 */ this.tree.find("ul ul[show='true']").show(); /* 显示 show 属性为 true 的子级菜单 */ this.tree.find("ul ul[show='true']").prev("li").addClass("open"); /* 添加 show 属性为 true 的子级菜单父节点的 open 样式 */ }/* option._init() End */ /* 设置所有超链接不响应单击事件 */ this.find("a").click(function(){ $(this).parent("li").click(); return false; }); /* 菜单项 接受单击 */ this.find("li").click(function(){ /* * 当单击菜单项 * 1.触发用户自定义的单击事件,将该 标签中的第一个超链接做为参数传递过去 * 2.修改当前菜单项所属的子菜单的显示状态(如果等于 true 将其设置为 false,否则将其设置为 true) * 3.重新初始化菜单 */ option.click($(this).find("a")[0]); /* 触发单击 */ /* * 如果当前节点下面包含子菜单,并且其 show 属性的值为 true,则修改其 show 属性为 false * 否则修改其 show 属性为 true */ /* if($(this).next("ul").attr("show")=="true"){ $(this).next("ul").attr("show","false"); }else{ $(this).next("ul").attr("show","true"); }*/ /* 初始化菜单 */ option._init(); }); /* 设置所有父节点样式 */ this.find("ul").prev("li").addClass("folder"); /* 设置节点“是否包含子节点”属性 */ this.find("li").find("a").attr("hasChild",false); this.find("ul").prev("li").find("a").attr("hasChild",true); /* 初始化菜单 */ option._init(); }/* SimpleTree Function End */ }); });

分析国外几款主流蜜罐产品看欺骗诱捕技术的应用脉络

网络安全的本质是攻防对抗,更本质的其实是人与人心智与技术的全面较量。 欺骗诱捕技术作为攻防对抗技术中比较特殊的技术,能够使防守方更多掌握对抗中的主动权,诱导攻击,迫使攻击者耗费精力的同时,留下丰富的攻击信息。究其本质,欺骗诱捕技术更深层次考验的不止是技术的能力,还有对于攻击者作为人的理解。 国外主流蜜罐产品分析 根据MarketsandMarkets《欺骗技术市场规模、份额和2021年全球市场预测》中提到的欺骗诱捕技术全球主要供应商及产品,我们分析了几款国外主流的蜜罐产品,希望更清晰看到欺骗诱捕技术应

cdyunaq的博客 1309

学弟问我如何用后台实现以树形显示分类的业务逻辑,我直接……

昨天 、一个好久没联系的小学弟找到我,说是最近做项目的时候遇到了一个难题,希望我能帮帮他们。本来想草草的推脱、这……我一听是难题,很快啊,我直接来了兴趣…… 平常最大的喜好就是被难题摁在地上摩擦的我,瞬间这嘴角根本就控制不住的上扬 小学弟:老哥…控制一下……控制一下… 我:咳咳……你且把这难题说给我听听 小学弟:最近做项目的时候,需求是要把分类的结构以树形的样式显示在页面上 我:树形?!嗯……用一下循环嵌套,把二级分类列表嵌套进与其对应的一级分类里面 小学弟:嗯……… 我:害、看老哥给你操作一波 小学

派大星的博客 488

部门树形结构算法 — Java递归实现

部门树形结构算法 — Java递归实现

netuser1937的博客 1326

学习笔记|多组率卡方检验和Fisher确切法|个案加权|规范表达|《小白爱上SPSS》课程:SPSS第十六讲 | 多组率卡方检验和Fisher确切法

学习笔记|多组率卡方检验和Fisher确切法|个案加权|规范表达|《小白爱上SPSS》课程:SPSS第十六讲 | 多组率卡方检验和Fisher确切法

Medlar_CN的博客 2962

ZYNQ程序固化实战:从BOOT.bin生成到QSPI/SD卡双启动模式详解

本文详细解析了ZYNQ 7000系列程序固化的完整流程,重点解决了程序断电丢失问题。通过实战演示,从生成BOOT.bin文件到配置QSPI与SD卡双启动模式,逐步指导开发者实现程序在外部存储中的永久驻留,确保产品脱离调试器独立运行。

weixin_29193259的博客 517

后台构建树形结构

后台构建树形结构

qq_43432057的博客 1587

银行统一监管报送系统

依据《银行业金融机构数据治理指引》,银行业金融机构应当建立适应监管数据报送工作需要的信息系统,实现流程控制的程序化,提高监管数据加工的自动化程度。银行业金融机构应当将监管数据纳入数据治理,建立工作机制和流程,确保监管数据报送工作有效组织开展,监管数据质量持续提升。银行通常要对接报送EAST5.0、1104、CRSS等近40个监管应用,涉及近1000张报表。表13-01是主要的监管报送应用、报送依据、报送规范、监管机构名称。

银行信息系统应用架构详解 4348

Java后端组装树形结构数据

项目开发中,几乎无法避免的会遇到树形结构,今天和大家分享java后端如何处理数据为树形结构。 1.封装测试实体类 package com.ldl.cn.demo; import java.util.ArrayList; import java.util.List; public class Dept { private int id; private int...

SeeYouAgain的博客 1万+

SAP-ABAP:FI财务会计模块常用BAPI及核心用途实例说明

SAP FI模块的BAPI覆盖了从主数据管理、凭证过账到财务关账的全流程操作,是系统集成与自动化的重要工具。实际应用中需结合业务场景选择合适的BAPI,并严格遵循事务控制与校验规则。如需扩展功能,可通过BAdI或用户出口增强标准逻辑。

baidu_35680696的博客 1601

SAP-ABAP:SAP Open SQL 分页技术深度解析:语法、性能陷阱与最佳实践

SAP Open SQL 分页技术深度解析:语法、性能陷阱与最佳实践

baidu_35680696的博客 634

完美解决前后端交互中后端返回树形结构数据

在我们开发中,前端有些树形组件需要的数据类型更多是树形类型,比如Element中的树节点: 前端需要补充的数据类型是: [{ id: 1, label: '一级 1', children: [{ id: 4, label: '二级 1-1', children: [{ id: 9, label: '三级 1-1-1' },

suncat的博客 9279

16、Cortex-M7处理器:高性能与复杂架构解析

本文深入解析了Cortex-M7处理器的高性能架构与复杂设计,涵盖AHB总线矩阵优化、超标量六阶段双发射流水线、增强型分支预测单元及双精度浮点支持。重点介绍了其独特的内存层次结构,包括指令与数据TCM、片上缓存和AXI-M 64位总线接口,提升系统并行性与执行效率。通过实际测试对比M4与M7性能差异,并演示如何将代码与数据定位到TCM以实现零等待运行。同时阐述了缓存机制的工作原理及其对系统性能的影响,为开发者提供全面的性能优化指导。

a1b2c3d的博客 126

前后端三层双层(多层)树形结构处理

前后端树形结构处理----设计理念 相信有许多人曾被树形结构处理从而困扰过下面我就为大家分享一下,在工作中!常见的树形结构该怎么处理! 场景 首先肯定有三个数据 这里我就分为 大主题(第一层数据),小主题(第二层数据),商品(第三层数据) 这里就列举为三层数据吧!其实你搞懂了三层数据处理后,在多也是一样的! 首先你要知道三层数据肯定是有所关联的 那到底是咋样关联的呢? 其实懂点后端的伙伴!肯定知道是通过字段id关联的! (1)假设大主题 总共有四条如下 (后端同理就当下面下面数据为查除数据) let bi

Riven的博客 3055

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

树形结构后端构建

产销差率(NRW)=损失量/供应量(避免除以零)- 仅当子节点存在有效数据时才进行聚合。- 供应总量=所有子节点供应量之和。- 损失量=供应量-销售量。

2303_78263863的博客 533

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java后端实现树形结构实体类

java实现树形结构

weixin_46855885的博客 1370

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

java后端返回前端树形结构_Java后端返回树型数据

前端有时需要展示部门树,城市树,人员树等树形结构,这时后端返回的数据需要经过一定的加工。1. 树结构的节点,设置children属性,可嵌套package com.jiangxb.test.util.tree;import java.util.ArrayList;import java.util.List;/*** @author jiangxiangbo* @date 2020/8/19* @D...

weixin_42509105的博客 2150

Java后端返回树形结构数据

Java后端返回树形结构数据

热爱滑板的代码男 3866

将列表转为树形结构(前后端 写法)

dept_id parent_id ancestors dept_name 11 0 0 根 22 11 0,11 测试1 33 11 0,11 测试2 44 22 1,11,22 测试1-1 前端写法 /** * 构造树型结构数据 * @param {*} data 数据源 * @param {*} id id字段 默认 'id' * @param {*} parentId 父节点字段

AmbroseLe 1075

vue2树形结构-将后端数据处理为树形结构

el-tree树形结构 可以进行编辑新增等功能。

qq_63169664的博客 773

将后端传递的扁平化数据转成树形结构的方法指南

需要将后端传来的数据转成嵌套的树形结构,后端数据形式如下。其中parentId是对应数据的id,children字段是对应的嵌套数据。在实际前端开发中,后端经常返回的是扁平化结构的列表数据,例如**菜单**、**组织架构**、**文件目录**等。为了在前端以**树形结构**进行渲染(如 Vant 的 TreeSelect、ElementUI 的 Tree),我们就需要将这类数据格式化为嵌套结构的树形数据。本文将带你从**思路剖析**到**代码实现**,并提供兼容性方案与完整演示,帮助你掌握数据结构转化的

这里是ShareJasmine的博客~ 664
上一篇: 工厂模式 vs 策略模式:设计模式中的 “创建者” 与 “决策者”
下一篇: SpringBoot 集成 FTP 与 SFTP 实战
梵高的代码色盘
博客等级 码龄5年 188粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值