項目中難免遇到使用樹型結構,如部門、菜單等。
它們有共同的屬性:id,name,parentId,因此抽象出一個接口,然後使用一個工具類實現列表轉樹的功能。
(其它這個是在另一個項目找到的,非原創,在此共享一下)
看源碼:
1、樹型結構接口TreeObject.java
import java.util.List; /** * 這個是列表樹形式顯示的接口 */ public interface TreeObject { Object getId(); void setId(Object id); Object getParentId(); void setParentId(Object parentId); String getName(); void setName(String name); List getChildren(); void setChildren(List children); }
2、樹型處理工具類TreeUtil.java
import org.apache.commons.lang3.StringUtils; import java.util.*; /** * 把一個list集合,裡面的bean含有 parentId 轉為樹形式 * */ public class TreeUtil { /** * 判斷兩個父ID是否相同 * @param p1 * @param p2 * @return */ private boolean isEqualsParentId(Object p1,Object p2){ if(p1!=null && p1!=null){ return p1.equals(p2); }else if(p1==null && p2 == null) { return true; }else if(p1==null && p2 != null) { if("".equals(p2.toString())){ return true; }else{ return false; } }else if(p1!=null && p2 == null) { if("".equals(p1.toString())){ return true; }else{ return false; } }else{ return false; } } /** * 根據父節點的ID獲取所有子節點,該方法頂級節點必須為空 * @param list 分類表 * @param parentId 傳入的父節點ID * @return String */ public List getChildTreeObjects(List<TreeObject> list,Object parentId) { List returnList = new ArrayList(); if(list!=null&&list.size()>0) { for (Iterator<TreeObject> iterator = list.iterator(); iterator.hasNext(); ) { TreeObject t = (TreeObject) iterator.next(); // 一、根據傳入的某個父節點ID,遍歷該父節點的所有子節點 if (isEqualsParentId(t.getParentId(), parentId)) { recursionFn(list, t); returnList.add(t); } } } return returnList; } /** * 根據父節點的ID獲取所有子節點,該方法頂級節點可以不為空,非樹直接返回 * @param list 分類表 * @return String */ public List<TreeObject> getChildTreeObjects(List<TreeObject> list) { if(list!=null&&list.size()>0) { List<TreeObject> topList=new ArrayList<>(); List<TreeObject> subList=new ArrayList<>(); Map<String,String> idMap=new HashMap<>(); for (Iterator<TreeObject> iterator = list.iterator(); iterator.hasNext(); ) { //歸並所有list的id集合 TreeObject t = (TreeObject) iterator.next(); idMap.put(t.getId().toString(), t.getId().toString()); } for (Iterator<TreeObject> iterator = list.iterator(); iterator.hasNext(); ) { //獲取最頂級的list TreeObject t = (TreeObject) iterator.next(); if(t.getParentId()==null|| StringUtils.isEmpty(t.getParentId().toString())){ topList.add(t); }else{ String id=idMap.get(t.getParentId().toString()); if(StringUtils.isEmpty(id)){ topList.add(t); }else{ subList.add(t); } } } if(topList!=null&&topList.size()>0&&subList!=null&&subList.size()>0){ List<TreeObject> resultList=new ArrayList<>(); for (TreeObject t:topList) { //將兒子級別的list歸並到頂級中 List<TreeObject> subOneList=new ArrayList<>(); for (TreeObject sub:subList) { // 一、根據傳入的某個父節點ID,遍歷該父節點的所有子節點 if (isEqualsParentId(sub.getParentId(), t.getId())) { recursionFn(subList, sub); subOneList.add(sub); } } t.setChildren(subOneList); resultList.add(t); } return resultList; }else{ return list; } } return list; } /** * 遞歸列表 * @param list * @param t */ private void recursionFn(List<TreeObject> list, TreeObject t) { List<TreeObject> childList = getChildList(list, t);// 得到子節點列表 t.setChildren(childList); for (TreeObject tChild : childList) { if (hasChild(list, tChild)) {// 判斷是否有子節點 //returnList.add(TreeObject); Iterator<TreeObject> it = childList.iterator(); while (it.hasNext()) { TreeObject n = (TreeObject) it.next(); recursionFn(list, n); } } } } // 得到子節點列表 private List<TreeObject> getChildList(List<TreeObject> list, TreeObject t) { List<TreeObject> tlist = new ArrayList<TreeObject>(); Iterator<TreeObject> it = list.iterator(); while (it.hasNext()) { TreeObject n = (TreeObject) it.next(); if (isEqualsParentId(n.getParentId(),t.getId())) { tlist.add(n); } } return tlist; } List<TreeObject> returnList = new ArrayList<TreeObject>(); /** * 根據父節點的ID獲取所有子節點 * @param list 分類表 * @param parentId 傳入的父節點ID * @param prefix 子節點前綴 */ public List<TreeObject> getChildTreeObjects(List<TreeObject> list, Object parentId,String prefix){ if(list == null) return null; for (Iterator<TreeObject> iterator = list.iterator(); iterator.hasNext();) { TreeObject node = (TreeObject) iterator.next(); // 一、根據傳入的某個父節點ID,遍歷該父節點的所有子節點 if (isEqualsParentId(node.getParentId(),parentId)) { recursionFn(list, node,prefix); } // 二、遍歷所有的父節點下的所有子節點 /*if (node.getParentId()==0) { recursionFn(list, node); }*/ } return returnList; } private void recursionFn(List<TreeObject> list, TreeObject node,String p) { List<TreeObject> childList = getChildList(list, node);// 得到子節點列表 if (hasChild(list, node)) {// 判斷是否有子節點 returnList.add(node); Iterator<TreeObject> it = childList.iterator(); while (it.hasNext()) { TreeObject n = (TreeObject) it.next(); n.setName(p+n.getName()); recursionFn(list, n,p+p); } } else { returnList.add(node); } } // 判斷是否有子節點 private boolean hasChild(List<TreeObject> list, TreeObject t) { return getChildList(list, t).size() > 0 ? true : false; } }
3、使用示例
以菜單為例,菜單對象實現TreeObject接口
(@ApiModel、@ApiModelProperty不需要的,是用於生成API文檔的)
import com.mjwon.core.tree.TreeObject; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.util.List; @ApiModel(value = "菜單樹對象") public class MenuTreeDto implements Serializable, TreeObject { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "菜單ID", example = "1", required = true) private String id; @ApiModelProperty(value = "菜單名稱", example = "菜單", required = true) private String menuName; @ApiModelProperty(value = "菜單類型", example = "1", required = true) private Short menuType; @ApiModelProperty(value = "菜單代碼", example = "1", required = true) private String menuCode; @ApiModelProperty(value = "父節點ID", example = "2", required = true) private String parentId; @ApiModelProperty(value = "排序", example = "2", required = false) private Long sortNo; @ApiModelProperty(value = "展開狀態", example = "1/0", required = true) private Short expand; @ApiModelProperty(value = "是否為葉子", example = "0/1", required = true) private Short isShow; @ApiModelProperty(value = "權限標識", example = "task.scheduled", required = true) private String permission; @ApiModelProperty(value = "備注", example = "備注", required = false) private String comt; @ApiModelProperty(value = "是否啟用", example = "1/0", required = false) private Short enable; @ApiModelProperty(value = "節點圖標CSS類名", example = "fa fas", required = false) private String iconcls; @ApiModelProperty(value = "請求地址", example = "app.syslog", required = false) private String request; @ApiModelProperty(value = "子部門", example = "父節點", required = false) private List children; @Override public Object getId() { return this.id; } @Override public void setId(Object id) { this.id = (String) id; } @Override public Object getParentId() { return this.parentId; } @Override public void setParentId(Object parentId) { this.parentId = (String) parentId; } @Override public String getName() { return this.menuName; } @Override public void setName(String name) { this.menuName = name; } @Override public List getChildren() { return this.children; } @Override public void setChildren(List children) { this.children = children; } public void setId(String id) { this.id = id; } public String getMenuName() { return menuName; } public void setMenuName(String menuName) { this.menuName = menuName; } public Short getMenuType() { return menuType; } public void setMenuType(Short menuType) { this.menuType = menuType; } public void setParentId(String parentId) { this.parentId = parentId; } public Long getSortNo() { return sortNo; } public void setSortNo(Long sortNo) { this.sortNo = sortNo; } public Short getExpand() { return expand; } public void setExpand(Short expand) { this.expand = expand; } public Short getIsShow() { return isShow; } public void setIsShow(Short isShow) { this.isShow = isShow; } public String getPermission() { return permission; } public void setPermission(String permission) { this.permission = permission; } public String getComt() { return comt; } public void setComt(String comt) { this.comt = comt; } public Short getEnable() { return enable; } public void setEnable(Short enable) { this.enable = enable; } public String getIconcls() { return iconcls; } public void setIconcls(String iconcls) { this.iconcls = iconcls; } public String getRequest() { return request; } public void setRequest(String request) { this.request = request; } public String getMenuCode() { return menuCode; } public void setMenuCode(String menuCode) { this.menuCode = menuCode; } }
查詢出菜單對的所有數據,然後轉為樹結構即可
List dtoList = BeanMapper.mapList(menuList,MenuTreeDto.class); if(dtoList!=null && dtoList.size()>0) { TreeUtil treeUtil = new TreeUtil(); List<MenuTreeDto> treeList = treeUtil.getChildTreeObjects(dtoList, parentId); return treeList; }
生成樹的結構示例:菜單樹JSON
{ "success": true, "message": "請求成功", "data": [ { "id": "1", "menuName": "系統管理", "menuType": 1, "menuCode": "sys", "parentId": "0", "sortNo": 50, "expand": 0, "isShow": 1, "permission": "sys", "comt": "test", "enable": 1, "iconcls": "fa fa-angle-right", "request": "#", "children": [ { "id": "16", "menuName": "用戶角色", "menuType": 1, "menuCode": "user.role", "parentId": "1", "sortNo": 11, "expand": 0, "isShow": 0, "permission": "user.role", "comt": null, "enable": 1, "iconcls": "fa fa-users", "request": "app.sys.userroles", "children": null, "name": "用戶角色" }, { "id": "17", "menuName": "權限管理", "menuType": 1, "menuCode": "sys.access", "parentId": "1", "sortNo": 12, "expand": 0, "isShow": 1, "permission": "sys.access", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "app.sys.auth", "children": null, "name": "權限管理" }, { "id": "18", "menuName": "系統日志", "menuType": 1, "menuCode": "sys.syslog", "parentId": "1", "sortNo": 22, "expand": 1, "isShow": 1, "permission": "sys.syslog", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "app.syslog", "children": null, "name": "系統日志" }, { "id": "19", "menuName": "業務日志", "menuType": 1, "menuCode": "sys.log.business", "parentId": "1", "sortNo": 999, "expand": 1, "isShow": 1, "permission": "sys.log.business", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "app.businesslog", "children": null, "name": "業務日志" }, { "id": "2", "menuName": "用戶管理", "menuType": 1, "menuCode": "sys.user", "parentId": "1", "sortNo": 1, "expand": 0, "isShow": 1, "permission": "sys.user", "comt": null, "enable": 1, "iconcls": "fa fa-user", "request": "app.user", "children": null, "name": "用戶管理" }, { "id": "3", "menuName": "部門管理", "menuType": 1, "menuCode": "sys.dept", "parentId": "1", "sortNo": 2, "expand": 0, "isShow": 1, "permission": "sys.dept", "comt": null, "enable": 1, "iconcls": "fa fa-users", "request": "app.dept", "children": null, "name": "部門管理" }, { "id": "4", "menuName": "菜單管理", "menuType": 1, "menuCode": "sys.menu", "parentId": "1", "sortNo": 3, "expand": 0, "isShow": 1, "permission": "sys.menu", "comt": null, "enable": 1, "iconcls": "fa fa-bars", "request": "app.menu", "children": null, "name": "菜單管理" }, { "id": "5", "menuName": "角色管理", "menuType": 1, "menuCode": "sys.role", "parentId": "1", "sortNo": 4, "expand": 0, "isShow": 1, "permission": "sys.role", "comt": null, "enable": 1, "iconcls": "fa fa-cog", "request": "app.role", "children": null, "name": "角色管理" }, { "id": "6", "menuName": "會話管理", "menuType": 1, "menuCode": "sys.session", "parentId": "1", "sortNo": 6, "expand": 0, "isShow": 0, "permission": "sys.session", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "main.sys.session.list", "children": null, "name": "會話管理" }, { "id": "7", "menuName": "字典管理", "menuType": 1, "menuCode": "sys.dic", "parentId": "1", "sortNo": 7, "expand": 0, "isShow": 1, "permission": "sys.dic", "comt": null, "enable": 1, "iconcls": "fa fa-book", "request": "app.dictindex", "children": null, "name": "字典管理" }, { "id": "8", "menuName": "業務參數", "menuType": 1, "menuCode": "sys.param", "parentId": "1", "sortNo": 8, "expand": 0, "isShow": 0, "permission": "sys.param", "comt": null, "enable": 1, "iconcls": "fa fa-wrench", "request": "main.sys.param.list", "children": null, "name": "業務參數" }, { "id": "20", "menuName": "數據權限", "menuType": 1, "menuCode": "sys.dataauth", "parentId": "1", "sortNo": 20, "expand": 1, "isShow": 1, "permission": "sys.dataauth", "comt": null, "enable": 1, "iconcls": "fa fa-users", "request": "app.dataauth", "children": null, "name": "數據權限" } ], "name": "系統管理" }, { "id": "9", "menuName": "調度中心", "menuType": 1, "menuCode": "task", "parentId": "0", "sortNo": 2, "expand": 0, "isShow": 0, "permission": "task", "comt": null, "enable": 1, "iconcls": "fa fa-angle-right", "request": "#", "children": [ { "id": "10", "menuName": "任務組管理", "menuType": 1, "menuCode": "task.group", "parentId": "9", "sortNo": 1, "expand": 0, "isShow": 0, "permission": "task.group", "comt": null, "enable": 1, "iconcls": "fa fa-tasks", "request": "main.task.group.list", "children": null, "name": "任務組管理" }, { "id": "11", "menuName": "任務管理", "menuType": 1, "menuCode": "task.scheduler", "parentId": "9", "sortNo": 2, "expand": 0, "isShow": 0, "permission": "task.scheduler", "comt": null, "enable": 1, "iconcls": "fa fa-table", "request": "main.task.scheduler.list", "children": null, "name": "任務管理" }, { "id": "12", "menuName": "調度管理", "menuType": 1, "menuCode": "task.scheduled", "parentId": "9", "sortNo": 3, "expand": 0, "isShow": 0, "permission": "task.scheduled", "comt": null, "enable": 1, "iconcls": "fa fa-user", "request": "main.task.scheduled.list", "children": null, "name": "調度管理" }, { "id": "13", "menuName": "調度日志", "menuType": 1, "menuCode": "task.log", "parentId": "9", "sortNo": 4, "expand": 0, "isShow": 0, "permission": "task.log", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "main.task.log.list", "children": null, "name": "調度日志" }, { "id": "15", "menuName": "角色權限", "menuType": 1, "menuCode": "role.access", "parentId": "9", "sortNo": 11, "expand": 1, "isShow": 1, "permission": "role.access", "comt": null, "enable": 1, "iconcls": "fa fa-list", "request": "app.sys.roleaccess", "children": null, "name": "角色權限" } ], "name": "調度中心" } ] } View Code至此,可以方便實現樹結構JSON的返回。over.