后端樹形結構

案例

在后端開發中,樹形結構數據的查詢和處理是一個常見的需求,比如部門管理、分類目錄展示等場景。接下來,我們以一個部門管理系統為例,詳細介紹如何實現后端的樹查詢功能。

案例背景

假設我們正在開發一個公司的內部管理系統,其中部門管理模塊需要展示部門之間的層級關系。部門數據以樹形結構存儲,每個部門都有自己的上級部門(根部門的上級部門 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,避免調用方NPEreturn 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、節點名稱等)。通過添加levelisLeaf字段,可以讓每個節點攜帶更多與業務相關的信息。比如level字段表示部門在樹形結構中的層級,前端拿到數據后,就可以根據層級來設置不同的縮進樣式,直觀展示部門的層級關系;isLeaf字段表示該節點是否為葉子節點(即是否有子節點),這在前端進行交互操作時很有用,例如可以根據是否為葉子節點來決定是否顯示展開 / 收縮按鈕。
  • 方便業務處理:在實際業務中,很多操作需要依賴這些額外的信息。比如在權限管理中,可能不同層級的部門有不同的權限;在數據統計時,可能需要區分葉子節點和非葉子節點進行不同的計算。將這些字段直接附加到樹形結構的節點中,在后續業務邏輯處理時,就無需再通過復雜的查詢或計算來獲取,提高開發效率。
  • 增強數據通用性:添加擴展字段使樹形結構數據更具通用性和靈活性。即使當前業務不需要這些字段,未來如果有新的功能需求,比如添加部門層級相關的篩選功能,或者根據葉子節點狀態進行特殊展示等,已經存在的擴展字段就能直接使用,而不需要對數據結構和代碼進行大規模修改。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/87808.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/87808.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/87808.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

高效溝通04-RIDE說服模型

高效溝通專欄–組織運轉的命脈與個人成功的基石 目錄 1. RIDE模型的核心理念2. RIDE模型的應用場景3. RIDE模型使用步驟4. RIDE模型示例與練習4.1 應用RIDE模型:4.2 練習:你來試試!5. 總結RIDE模型是一種結構化的說服框架,旨在幫助你在溝通(尤其是書面溝通或需要清晰邏輯…

利用selenium獲取網頁數據,腳本加載慢問題的解決辦法

問題&#xff1a;最近在寫一個腳本去獲取一個網站的數據&#xff0c;用到一個表格中的數據&#xff0c;條目是1000條&#xff0c;需要逐條去獲取網站上對應的數據&#xff0c;遇到的問題是腳本運行后&#xff0c;很久才開始打開驅動瀏覽器。經過很多次嘗試&#xff0c;主要原因…

Ubuntu查看本機代理的實操指南

快速確認代理狀態的必要性在Ubuntu系統中&#xff0c;代理設置是跨境訪問、企業內網連接、開發調試的重要配置。無論是排查網絡卡頓、驗證代理是否生效&#xff0c;還是確保特定應用走代理通道&#xff0c;快速查看當前代理狀態都是關鍵步驟。圖形界面查看&#xff0c;可視化操…

三格電子——雙通道 CAN(FD)轉以太網

【SG-CAN(FD)NET-210】 一、功能描述 CANFD 完全向下兼容 CAN &#xff0c;以下統稱 CAN(FD) 。 SG-CAN(FD)NET-210 是一款用來把 CANFD 總線數據轉為網口數據的設 備。 網口支持 TCP Sever 、 TCP Client 、 UDP Sever 、 UDP Client 四種模式。 可以通過軟件配置…

【一起來學AI大模型】卷積神經網絡(CNN):視覺識別的革命性架構

一、CNN的核心思想與生物啟示 卷積神經網絡&#xff08;Convolutional Neural Networks&#xff09;是受生物視覺皮層啟發的深度學習架構&#xff0c;專門用于處理網格狀拓撲數據&#xff08;如圖像、視頻、音頻&#xff09;。其核心創新在于&#xff1a; 局部感受野&#xff…

創建和編輯Crontab的方法

計劃任務&#xff0c;在 Linux 中一般使用Crontab&#xff0c;通過crontab命令&#xff0c;我們可以在固定的間隔時間執行指定的系統指令或 Shell 腳本。時間間隔的單位可以是分鐘、小時、日、月、周及以上的任意組合。這個命令非常適合周期性的日志分析或數據備份等工作。 創建…

在職場中如何培養創新思維?

芯片研發人員&#xff0c;授權發明專利40&#xff0c;聊聊技術層面的創新&#xff0c; 創新的本質&#xff0c;是舊有知識的創造性組合&#xff0c; 不存在無中生有的創新&#xff0c; 你必須建立本領域的知識體系&#xff0c;對過往各種創新&#xff0c;爛熟于心&#xff0…

設備健康管理平臺功能深度對比:中訊燭龍如何以預測性維護重構工業運維范式?

全球制造業因非計劃停機每年損失超千億美元?&#xff0c;而搭載預測性維護系統的企業&#xff0c;設備可用率可提升至99.8%??。 在工業4.0與智能制造浪潮下&#xff0c;設備健康管理平臺已從“可選工具”升級為“核心生產力工具”。面對市場上功能繁雜的解決方案&#xff0c…

YOLOv11 架構優化:提升目標檢測性能

YOLOv11 作為目標檢測領域的最新成果&#xff0c;其架構優化是提升性能的關鍵。本文將詳細探討 YOLOv11 的架構改進&#xff0c;以及這些改進如何幫助模型在實時應用中實現更高的準確性和效率。 一、架構改進 &#xff08;一&#xff09;C3K2 塊 C3K2 塊是對 CSP 塊的增強&a…

特別放送:關于一個無法修復的系統級Bug

大家好&#xff0c;我是阿威。 熟悉我的朋友都知道&#xff0c;我的博客基本只聊三件事&#xff1a;代碼、架構和偶爾的職業生涯吐槽。但今天&#xff0c;我想破個例。起因是上周熬夜排查一個線上問題&#xff0c;一個分布式系統&#xff0c;流量洪峰一來&#xff0c;某個下游…

云原生-集群管理

1.集群管理命令&#xff1a;a.如何管理集群&#xff1f;-kubectl是用于控制Kubernetes集群的命令行工具b.語法格式&#xff1a;-kubectl [command] [TYPE] [NAME] [flages]command:子命令&#xff0c;如create、get、descrbe、deletetype&#xff1a;資源類型&#xff…

基于Linux下的vscode c/c++開發環境搭建詳細教程

vscode是文本編輯而非集成開發環境&#xff0c;需要經過配置才能在其上編譯執行代碼。本教程將具體詳解在linux上配置Visual Studio Code使用GCC C 編譯器&#xff08;g&#xff09;和GDB調試器的方法&#xff08;GCC是GNU 編譯器集合&#xff0c;GDB則是 GNU調試器&#xff09…

【EGSR2025】材質+擴散模型+神經網絡相關論文整理隨筆

MatSwap: Light-aware material transfers in images 介紹任務&#xff1a;輸入一張拍攝圖像、示例材質紋理圖像&#xff08;這里跟BRDF無關&#xff0c;通常我們講到材質一般指的是SVBRDF&#xff0c;但是這里的材質指的只是紋理&#xff09;、用戶為拍攝圖像指定的遮罩區域&…

WebRTC 雙向視頻通話

WebRTC 雙向視頻通話 一、項目概述 WebRTC&#xff08;Web Real - Time Communication&#xff09;是一種支持瀏覽器之間進行實時通信的技術&#xff0c;它使得在網頁上實現音視頻通話、文件共享等功能變得更加容易。為了體驗這個技術&#xff0c;所以我實現了webrtc - local…

Paimon lookup核心過程:分級查找、二分和緩存創建

LookupLevels LookupLevels 在 Paimon 中扮演著**“帶緩存的、基于 Key 的數據查找引擎”**的角色。它的核心使命是&#xff1a;當需要根據主鍵&#xff08;Key&#xff09;查找某條數據時&#xff0c;能夠高效地在 LSM-Tree 的多層&#xff08;Levels&#xff09;數據文件中定…

Ruby大會演講實錄:Baklib 如何用 AI 重構內容管理賽道

“2015 年成都 Ruby 大會時&#xff0c;我們還在做大數據項目&#xff1b;2025 年的今天&#xff0c;Baklib 已服務 800 多家企業。” 在 RubyConf China 2025 的演講臺上&#xff0c;Baklib 創始人Song以十年對比開篇&#xff0c;講述了從技術愛好者到企業服務創業者的蛻變&am…

408第三季part2 - 計算機網絡 - 傳輸層II

理解第一次和第二次握手是不能攜帶數據&#xff0c;只能消耗一個序號后面揮手也有第一次和第三次題目建立連接是1000&#xff0c;FIN揮手是5001&#xff0c;這兩個是不會帶數據的所以字節數范圍是1001-50005000-10011 4000c再次理解還可以叫快速重傳題目服務器想要100確認號客…

揭秘圖像LLM:從像素到語言的智能轉換

圖像LLM是怎么工作 圖像LLM(多模態大語言模型)的核心是將圖像轉化為語言模型能理解的“語言”,并與文本深度融合。以下結合CLIP、DALL-E、GPT-4V等主流模型,通過具體例子說明其工作機制: 一、圖像→特征向量:從像素到“密碼” 例子:識別“戴墨鏡的貓” 視覺編碼器提取…

十、K8s集群資源合理化分配

十、K8s集群資源合理化分配 文章目錄 十、K8s集群資源合理化分配1、K8s 資源限制 ResourceQuota1.1 什么是ResourceQuota&#xff1f;1.2 ResourceQuota通常用于如下場景&#xff1a;1.3 基于租戶和團隊的資源限制1.4 基于命名空間的資源限制 2、K8s 資源限制 LimitRange2.1 設…

Android 13 設置界面會判斷當前屏幕的大小,如果是大屏,則為左右屏顯示

1.前言 在13.0的系統rom定制化開發中,在某些時候,在大屏設備中,設置新增了左右分屏的功能,就是 左邊顯示主菜單,右邊顯示一級菜單的功能,某些情況下不需要,接下來關閉這個功能 2.設置界面會判斷當前屏幕的大小,如果是大屏,則為左右屏顯示的核心類 packages/apps/Sett…