java之TreeUtils生成一切對象樹形結構案例
項目中經(jīng)常會遇到各種需要以樹形結構展示的功能,比較常見的,如菜單樹,分類樹,部門樹等等,如果為每種類型都遍歷遞歸生成樹形結構返回給前端,顯得有些冗余且麻煩,并且其實邏輯都是一致的,只是遍歷的對象不同而已,故其實可以通過面向接口思維,來實現(xiàn)這種通用工具類的實現(xiàn)。
TreeNode用來表示每個樹節(jié)點的抽象,即需要生成樹的對象需要實現(xiàn)此接口。
/**
* 樹節(jié)點父類,所有需要使用{@linkplain TreeUtils}工具類形成樹形結構等操作的節(jié)點都需要實現(xiàn)該接口
*
* @param <T> 節(jié)點id類型
*/
public interface TreeNode<T> {
/**
* 獲取節(jié)點id
*
* @return 樹節(jié)點id
*/
T id();
/**
* 獲取該節(jié)點的父節(jié)點id
*
* @return 父節(jié)點id
*/
T parentId();
/**
* 是否是根節(jié)點
*
* @return true:根節(jié)點
*/
boolean root();
/**
* 設置節(jié)點的子節(jié)點列表
*
* @param children 子節(jié)點
*/
void setChildren(List<? extends TreeNode<T>> children);
/**
* 獲取所有子節(jié)點
*
* @return 子節(jié)點列表
*/
List<? extends TreeNode<T>> getChildren();
}
TreeUtils用來生成樹形結構,以及獲取所有葉子節(jié)點等操作
/**
* 樹形結構工具類
*
* @author meilin.huang
* @version 1.0
* @date 2019-08-24 1:57 下午
*/
public class TreeUtils {
/**
* 根據(jù)所有樹節(jié)點列表,生成含有所有樹形結構的列表
*
* @param nodes 樹形節(jié)點列表
* @param <T> 節(jié)點類型
* @return 樹形結構列表
*/
public static <T extends TreeNode<?>> List<T> generateTrees(List<T> nodes) {
List<T> roots = new ArrayList<>();
for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
T node = ite.next();
if (node.root()) {
roots.add(node);
// 從所有節(jié)點列表中刪除該節(jié)點,以免后續(xù)重復遍歷該節(jié)點
ite.remove();
}
}
roots.forEach(r -> {
setChildren(r, nodes);
});
return roots;
}
/**
* 從所有節(jié)點列表中查找并設置parent的所有子節(jié)點
*
* @param parent 父節(jié)點
* @param nodes 所有樹節(jié)點列表
*/
@SuppressWarnings("all")
public static <T extends TreeNode> void setChildren(T parent, List<T> nodes) {
List<T> children = new ArrayList<>();
Object parentId = parent.id();
for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
T node = ite.next();
if (Objects.equals(node.parentId(), parentId)) {
children.add(node);
// 從所有節(jié)點列表中刪除該節(jié)點,以免后續(xù)重復遍歷該節(jié)點
ite.remove();
}
}
// 如果孩子為空,則直接返回,否則繼續(xù)遞歸設置孩子的孩子
if (children.isEmpty()) {
return;
}
parent.setChildren(children);
children.forEach(m -> {
// 遞歸設置子節(jié)點
setChildren(m, nodes);
});
}
/**
* 獲取指定樹節(jié)點下的所有葉子節(jié)點
*
* @param parent 父節(jié)點
* @param <T> 實際節(jié)點類型
* @return 葉子節(jié)點
*/
public static <T extends TreeNode<?>> List<T> getLeafs(T parent) {
List<T> leafs = new ArrayList<>();
fillLeaf(parent, leafs);
return leafs;
}
/**
* 將parent的所有葉子節(jié)點填充至leafs列表中
*
* @param parent 父節(jié)點
* @param leafs 葉子節(jié)點列表
* @param <T> 實際節(jié)點類型
*/
@SuppressWarnings("all")
public static <T extends TreeNode> void fillLeaf(T parent, List<T> leafs) {
List<T> children = parent.getChildren();
// 如果節(jié)點沒有子節(jié)點則說明為葉子節(jié)點
if (CollectionUtils.isEmpty(children)) {
leafs.add(parent);
return;
}
// 遞歸調(diào)用子節(jié)點,查找葉子節(jié)點
for (T child : children) {
fillLeaf(child, leafs);
}
}
}
具體使用方式之聲明樹節(jié)點對象
@Getter
@Setter
public class ResourceListVO implements TreeNode<Long> {
private Long id;
private Long pid;
private Integer type;
private String name;
private String icon;
private String code;
private Integer status;
private List<ResourceListVO> children;
@Override
public Long id() {
return this.id;
}
@Override
public Long parentId() {
return this.pid;
}
@Override
public boolean root() {
return Objects.equals(this.pid, 0L);
}
@Override
public void setChildren(List children) {
this.children = children;
}
}
具體使用方式之調(diào)用
/**
* 獲取賬號的資源樹
*/
public List<ResourceListVO> listByAccountId(Long accountId) {
return TreeUtils.generateTrees(BeanUtils.copyProperties(mapper.selectByAccountId(userId), ResourceListVO.class));
}
通過使用TreeUtils工具可以統(tǒng)一方便地生成一切對象的樹形結構以及其他一些對樹的操作,避免對每個對象都用特定代碼生成。使用起來就是幾個字簡潔方便爽歪歪biu特否。
補充知識:TreeUtil 數(shù)據(jù)庫菜單生成無限級樹形結構
1、項目需求:
從數(shù)據(jù)庫從加載所有的菜單出來,菜單中有
id,parentId,name字段
希望能有一個工具幫我進行樹形結構重組;
實例類:
package com.lming.chcservice.util;
import lombok.Data;
import java.util.List;
@Data
public class TreeNode {
/**
* 節(jié)點id
*/
private String id;
/**
* 父節(jié)點 默認0為根節(jié)點
*/
private String parentId;
/**
* 節(jié)點名稱
*/
private String name;
/**
* 是否有子節(jié)點
*/
private boolean hasChild;
public TreeNode(String id, String parentId, String name) {
this.id = id;
this.parentId = parentId;
this.name = name;
}
}
工具類:
package com.lming.chcservice.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 樹形結構工具類
*
* 將一組list對象轉成樹形結構
* 該list需符合設定的字段類型
*
*/
public class TreeUtil {
public static Map<String,Object> mapArray = new LinkedHashMap<String, Object>();
public List<TreeNode> menuCommon;
public List<Object> list = new ArrayList<Object>();
public List<Object> treeMenu(List<TreeNode> menu){
this.menuCommon = menu;
for (TreeNode treeNode : menu) {
Map<String,Object> mapArr = new LinkedHashMap<String, Object>();
if(treeNode.getParentId().equals("0")){
setTreeMap(mapArr,treeNode);
list.add(mapArr);
}
}
return list;
}
public List<?> menuChild(String id){
List<Object> lists = new ArrayList<Object>();
for(TreeNode a:menuCommon){
Map<String,Object> childArray = new LinkedHashMap<String, Object>();
if(a.getParentId() .equals(id)){
setTreeMap(childArray,a);
lists.add(childArray);
}
}
return lists;
}
private void setTreeMap(Map<String,Object> mapArr,TreeNode treeNode){
mapArr.put("id", treeNode.getId());
mapArr.put("name", treeNode.getName());
mapArr.put("parentId", treeNode.getParentId());
List<?> childrens = menuChild(treeNode.getId());
if(childrens.size()>0){
mapArr.put("hasChild",true);
}
else{
mapArr.put("hasChildren",false);
}
mapArr.put("childrens", menuChild(treeNode.getId()));
}
public static void main(String[] args){
List<TreeNode> treeNodeList = new ArrayList<>();
TreeNode treeNode1 = new TreeNode("1","0","首頁");
TreeNode treeNode2 = new TreeNode("2","0","訂單");
TreeNode treeNode3 = new TreeNode("3","1","預約");
TreeNode treeNode4 = new TreeNode("4","2","捐獻");
TreeNode treeNode5 = new TreeNode("5","4","我的訂單");
TreeNode treeNode6 = new TreeNode("6","5","個人中心");
TreeNode treeNode7 = new TreeNode("7","6","個人中心2");
TreeNode treeNode8 = new TreeNode("8","99","個人中心3");
treeNodeList.add(treeNode1);
treeNodeList.add(treeNode6);
treeNodeList.add(treeNode5);
treeNodeList.add(treeNode3);
treeNodeList.add(treeNode4);
treeNodeList.add(treeNode2);
treeNodeList.add(treeNode7);
treeNodeList.add(treeNode8);
TreeUtil treeUtil = new TreeUtil();
System.out.print(JsonUtil.toJson(treeUtil.treeMenu(treeNodeList)));
}
}
測試結果:
[
{
"id": "1",
"name": "首頁",
"parentId": "0",
"hasChild": true,
"childrens": [
{
"id": "3",
"name": "預約",
"parentId": "1",
"hasChildren": false,
"childrens": []
}
]
},
{
"id": "2",
"name": "訂單",
"parentId": "0",
"hasChild": true,
"childrens": [
{
"id": "4",
"name": "捐獻",
"parentId": "2",
"hasChild": true,
"childrens": [
{
"id": "5",
"name": "我的訂單",
"parentId": "4",
"hasChild": true,
"childrens": [
{
"id": "6",
"name": "個人中心",
"parentId": "5",
"hasChild": true,
"childrens": [
{
"id": "7",
"name": "個人中心2",
"parentId": "6",
"hasChildren": false,
"childrens": []
}
]
}
]
}
]
}
]
}
]
實力類不一致怎么辦? 自己寫一個實體轉換類,將類的對象屬性轉換成上面的實體類,然后在調(diào)用,當然最快的方式直接修改實體類即可用。
以上這篇java之TreeUtils生成一切對象樹形結構案例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
IDEA創(chuàng)建Java?Web項目的超詳細圖文教學
IDEA是程序員們常用的java集成開發(fā)環(huán)境,也是被公認為最好用的java開發(fā)工具,下面這篇文章主要給大家介紹了關于IDEA創(chuàng)建Java?Web項目的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-12-12
java8 stream中Collectors.toMap空指針問題及解決
這篇文章主要介紹了java8 stream中Collectors.toMap空指針問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
Java實現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法示例
這篇文章主要介紹了Java實現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法,涉及java針對數(shù)組的遍歷、判斷、輸出等相關操作技巧,需要的朋友可以參考下2017-12-12
Mybatis批量插入index out of range錯誤的解決(較偏的錯誤)
這篇文章主要介紹了Mybatis批量插入index out of range錯誤的解決(較偏的錯誤),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

