我們在實際開發中,肯定會用到樹結構,如部門樹、選單樹等等。Java後臺利用遞迴思路進行構建樹形結構資料,返回給前端,能以下拉選單等形式進行展示。今天,我們們就來說說怎麼樣將List集合轉換成TreeList。
一、jar依賴
為了簡化程式碼,引入Lombok的Jar包,可省略實體類set()、get()方法。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
</dependency>
二、樹節點資料類
/**
* TreeNode 樹節點 (定義每一個節點的資訊,即每一個節點對應一條資料資訊)
*/
@Data
public class TreeNode {
/** 節點ID */
private Integer id;
/** 父節點ID:頂級節點為0 */
private Integer parentId;
/** 節點名稱 */
private String label;
/** 子節點 */
private List<TreeNode> children;
public TreeNode(Integer id, Integer parentId, String label) {
this.id = id;
this.parentId = parentId;
this.label = label;
}
}
三、構建樹形類
理解思路(個人):
1、首先獲取所有的根節點(頂級節點),即根節點的parentId = 0。
2、根據每一個根節點,與所有節點集合(資料)進行判斷,當前節點是否為其下的子節點。
3、若是,則遞迴呼叫構建樹形;若不是,則表明該節點不屬於其下子節點。
4、應繼續迴圈判斷節點父子關係,直到所有節點與根節點判斷完畢。
/**
* BuildTree 構建樹形結構
*/
public class TreeBuild {
// 儲存參與構建樹形的所有資料(通常資料庫查詢結果)
public List<TreeNode> nodeList = new ArrayList<>();
/**
* 構造方法
* @param nodeList 將資料集合賦值給nodeList,即所有資料作為所有節點。
*/
public TreeBuild(List<TreeNode> nodeList){
this.nodeList = nodeList;
}
/**
* 獲取需構建的所有根節點(頂級節點) "0"
* @return 所有根節點List集合
*/
public List<TreeNode> getRootNode(){
// 儲存所有根節點(所有根節點的資料)
List<TreeNode> rootNodeList = new ArrayList<>();
// treeNode:查詢出的每一條資料(節點)
for (TreeNode treeNode : nodeList){
// 判斷當前節點是否為根節點,此處注意:若parentId型別是String,則要採用equals()方法判斷。
if (0 == treeNode.getParentId()) {
// 是,新增
rootNodeList.add(treeNode);
}
}
return rootNodeList;
}
/**
* 根據每一個頂級節點(根節點)進行構建樹形結構
* @return 構建整棵樹
*/
public List<TreeNode> buildTree(){
// treeNodes:儲存一個頂級節點所構建出來的完整樹形
List<TreeNode> treeNodes = new ArrayList<TreeNode>();
// getRootNode():獲取所有的根節點
for (TreeNode treeRootNode : getRootNode()) {
// 將頂級節點進行構建子樹
treeRootNode = buildChildTree(treeRootNode);
// 完成一個頂級節點所構建的樹形,增加進來
treeNodes.add(treeRootNode);
}
return treeNodes;
}
/**
* 遞迴-----構建子樹形結構
* @param pNode 根節點(頂級節點)
* @return 整棵樹
*/
public TreeNode buildChildTree(TreeNode pNode){
List<TreeNode> childTree = new ArrayList<TreeNode>();
// nodeList:所有節點集合(所有資料)
for (TreeNode treeNode : nodeList) {
// 判斷當前節點的父節點ID是否等於根節點的ID,即當前節點為其下的子節點
if (treeNode.getParentId().equals(pNode.getId())) {
// 再遞迴進行判斷當前節點的情況,呼叫自身方法
childTree.add(buildChildTree(treeNode));
}
}
// for迴圈結束,即節點下沒有任何節點,樹形構建結束,設定樹結果
pNode.setChildren(childTree);
return pNode;
}
}
四、測試案例
/**
* TreeController 樹控制層
* 方式:傳遞所有資料集合作為引數,呼叫buildTree()構建樹形。
*/
@RestController
@RequestMapping("/tree")
public class TreeController {
@GetMapping("/treeTest")
public AjaxResult treeTest(){
// 模擬測試資料(通常為資料庫的查詢結果)
List<TreeNode> treeNodeList = new ArrayList<>();
treeNodeList.add(new TreeNode(1,0,"頂級節點A"));
treeNodeList.add(new TreeNode(2,0,"頂級節點B"));
treeNodeList.add(new TreeNode(3,1,"父節點是A"));
treeNodeList.add(new TreeNode(4,2,"父節點是B"));
treeNodeList.add(new TreeNode(5,2,"父節點是B"));
treeNodeList.add(new TreeNode(6,3,"父節點的ID是3"));
// 建立樹形結構(資料集合作為引數)
TreeBuild treeBuild = new TreeBuild(treeNodeList);
// 原查詢結果轉換樹形結構
treeNodeList = treeBuild.buildTree();
// AjaxResult:個人封裝返回的結果體
return AjaxResult.success("測試資料",treeNodeList);
}
}
結果:
{
"msg”:“ 測試資料”,
"code": 200,
"data": [
{
"id": 1,
"parentId": 0,
"label":"頂級節點A",
"children": [
{
"id": 3,
"parentId": 1,
"label":“ 父節點是A"
"children": [
"id": 6,
"parentId": 3,
"label":“ 父節點的ID是3
}
]
}
]
},
{
"id": 2,
"parentId": 0,
"labe1":“ 頂級節點B",
"children": [{
"id": 4,
"parentId": 2,
"label":“ 父節點是B"
},
{
"id": 5,
"parentId": 2,
"label":" 父節點是B
}
]
}
]
}
本文介紹Java後臺構建樹形結構資料的設計思路及實現,如有不對可以或更好的方案,歡迎指出和討論。