項目中難免遇到使用樹型結構,如部門、菜單等。
它們有共同的屬性: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

至此,可以方便實現樹結構JSON的返回。over.