1. 程式人生 > 其它 >java構建樹形列表(帶children屬性)

java構建樹形列表(帶children屬性)

構建的方式是通過id欄位與父id欄位做關聯,通過遞迴構建children欄位來達到構建樹形列表的目的。

1. 資料庫指令碼

選單許可權表

create table sys_menu (
  menu_id           bigint(20)      not null auto_increment    comment '選單ID',
  menu_name         varchar(50)     not null                   comment '選單名稱',
  parent_id         bigint(20)      default 0                  comment '父選單ID',
  order_num         int(4)          default 0                  comment '顯示順序',
  path              varchar(200)    default ''                 comment '路由地址',
  component         varchar(255)    default null               comment '元件路徑',
  query             varchar(255)    default null               comment '路由引數',
  is_frame          int(1)          default 1                  comment '是否為外鏈(0是 1否)',
  is_cache          int(1)          default 0                  comment '是否快取(0快取 1不快取)',
  menu_type         char(1)         default ''                 comment '選單型別(M目錄 C選單 F按鈕)',
  visible           char(1)         default 0                  comment '選單狀態(0顯示 1隱藏)',
  status            char(1)         default 0                  comment '選單狀態(0正常 1停用)',
  perms             varchar(100)    default null               comment '許可權標識',
  icon              varchar(100)    default '#'                comment '選單圖示',
  create_by         varchar(64)     default ''                 comment '建立者',
  create_time       datetime                                   comment '建立時間',
  update_by         varchar(64)     default ''                 comment '更新者',
  update_time       datetime                                   comment '更新時間',
  remark            varchar(500)    default ''                 comment '備註',
  primary key (menu_id)
) engine=innodb auto_increment=2000 comment = '選單許可權表';

2. 實體類

選單許可權實體類 SysMenu

package com.xx.common.core.domain.entity;

import java.util.ArrayList;
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 選單許可權表 sys_menu
 * 
 * @author michael
 * @date 2020/07/08
 * @version 1.0
 */
public class SysMenu extends BaseEntity {
    private static final long serialVersionUID = 1L;

    /** 選單ID */
    private Long menuId;

    /** 選單名稱 */
    private String menuName;

    /** 父選單名稱 */
    private String parentName;

    /** 父選單ID */
    private Long parentId;

    /** 顯示順序 */
    private String orderNum;

    /** 路由地址 */
    private String path;

    /** 元件路徑 */
    private String component;

    /** 是否為外鏈(0是 1否) */
    private String isFrame;

    /** 型別(M目錄 C選單 F按鈕) */
    private String menuType;

    /** 顯示狀態(0顯示 1隱藏) */
    private String visible;

    /** 選單狀態(0顯示 1隱藏) */
    private String status;

    /** 許可權字串 */
    private String perms;

    /** 選單圖示 */
    private String icon;

    /** 子選單 */
    private List<SysMenu> children = new ArrayList<SysMenu>();

    public Long getMenuId() {
        return menuId;
    }

    public void setMenuId(Long menuId) {
        this.menuId = menuId;
    }

    @NotBlank(message = "選單名稱不能為空")
    @Size(min = 0, max = 50, message = "選單名稱長度不能超過50個字元")
    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName;
    }

    public String getParentName() {
        return parentName;
    }

    public void setParentName(String parentName) {
        this.parentName = parentName;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    @NotBlank(message = "顯示順序不能為空")
    public String getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(String orderNum) {
        this.orderNum = orderNum;
    }

    @Size(min = 0, max = 200, message = "路由地址不能超過200個字元")
    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Size(min = 0, max = 200, message = "元件路徑不能超過255個字元")
    public String getComponent() {
        return component;
    }

    public void setComponent(String component) {
        this.component = component;
    }

    public String getIsFrame() {
        return isFrame;
    }

    public void setIsFrame(String isFrame) {
        this.isFrame = isFrame;
    }

    @NotBlank(message = "選單型別不能為空")
    public String getMenuType() {
        return menuType;
    }

    public void setMenuType(String menuType) {
        this.menuType = menuType;
    }

    public String getVisible() {
        return visible;
    }

    public void setVisible(String visible) {
        this.visible = visible;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    @Size(min = 0, max = 100, message = "許可權標識長度不能超過100個字元")
    public String getPerms() {
        return perms;
    }

    public void setPerms(String perms) {
        this.perms = perms;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public List<SysMenu> getChildren() {
        return children;
    }

    public void setChildren(List<SysMenu> children) {
        this.children = children;
    }
    
    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("menuId", getMenuId())
            .append("menuName", getMenuName())
            .append("parentId", getParentId())
            .append("orderNum", getOrderNum())
            .append("path", getPath())
            .append("component", getComponent())
            .append("isFrame", getIsFrame())
            .append("menuType", getMenuType())
            .append("visible", getVisible())
            .append("status ", getStatus())
            .append("perms", getPerms())
            .append("icon", getIcon())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .toString();
    }
}

基類 BaseEntity

package com.xx.common.core.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * Entity基類
 * 
 * @author michael
 * @date 2020/07/02
 * @version 1.0
 */
public class BaseEntity implements Serializable {
    
    private static final long serialVersionUID = 1L;

    /** 搜尋值 */
    private String searchValue;

    /** 建立者 */
    private String createBy;

    /** 建立時間 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /** 更新者 */
    private String updateBy;

    /** 更新時間 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

    /** 備註 */
    private String remark;

    /** 開始時間 */
    @JsonIgnore
    private String beginTime;

    /** 結束時間 */
    @JsonIgnore
    private String endTime;

    /** 請求引數 */
    private Map<String, Object> params;

    public String getSearchValue() {
        return searchValue;
    }

    public void setSearchValue(String searchValue) {
        this.searchValue = searchValue;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getBeginTime() {
        return beginTime;
    }

    public void setBeginTime(String beginTime) {
        this.beginTime = beginTime;
    }

    public String getEndTime() {
        return endTime;
    }

    public void setEndTime(String endTime) {
        this.endTime = endTime;
    }

    public Map<String, Object> getParams() {
        if (params == null) {
            params = new HashMap<>();
        }
        return params;
    }

    public void setParams(Map<String, Object> params) {
        this.params = params;
    }
}

Treeselect樹結構實體類

package com.xx.common.core.domain;

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.nova.common.core.domain.entity.SysDept;
import com.nova.common.core.domain.entity.SysMenu;

/**
 * Treeselect樹結構實體類
 * 
 * @author michael
 * @date 2020/07/02
 * @version 1.0
 */
public class TreeSelect implements Serializable {
    
    private static final long serialVersionUID = 1L;

    /** 節點ID */
    private Long id;

    /** 節點名稱 */
    private String label;

    /** 子節點 */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<TreeSelect> children;

    public TreeSelect() {

    }

    public TreeSelect(SysMenu menu) {
        this.id = menu.getMenuId();
        this.label = menu.getMenuName();
        this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<TreeSelect> getChildren() {
        return children;
    }

    public void setChildren(List<TreeSelect> children) {
        this.children = children;
    }
}

3. 構建樹形結構方法

/**
 * 構建前端所需要下拉樹結構
 *
 * @param menus 選單列表
 * @return 下拉樹結構列表
*/
@Override
public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus) {
    List<SysMenu> menuTrees = buildMenuTree(menus);
    return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
}

/**
 * 構建前端所需要樹結構
 * 
 * @param menus 選單列表
 * @return 樹結構列表
 */
@Override
public List<SysMenu> buildMenuTree(List<SysMenu> menus) {
    List<SysMenu> returnList = new ArrayList<SysMenu>();
    List<Long> tempList = new ArrayList<Long>();
    for (SysMenu dept : menus) {
        tempList.add(dept.getMenuId());
    }
    for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();) {
        SysMenu menu = (SysMenu) iterator.next();
        // 如果是頂級節點, 遍歷該父節點的所有子節點
        if (!tempList.contains(menu.getParentId())) {
            recursionFn(menus, menu);
            returnList.add(menu);
        }
    }
    if (returnList.isEmpty()) {
        returnList = menus;
    }
    return returnList;
}


/**
 * 遞迴列表
 * 
 * @param list
 * @param t
 */
private void recursionFn(List<SysMenu> list, SysMenu t) {
    // 得到子節點列表
    List<SysMenu> childList = getChildList(list, t);
    t.setChildren(childList);
    for (SysMenu tChild : childList) {
        if (hasChild(list, tChild)) {
            recursionFn(list, tChild);
        }
    }
}


/**
 * 得到子節點列表
 */
private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t) {
    List<SysMenu> tlist = new ArrayList<SysMenu>();
    Iterator<SysMenu> it = list.iterator();
    while (it.hasNext()) {
        SysMenu n = (SysMenu)it.next();
        if (n.getParentId().longValue() == t.getMenuId().longValue()) {
            tlist.add(n);
        }
    }
    return tlist;
}

/**
 * 判斷是否有子節點
 */
private boolean hasChild(List<SysMenu> list, SysMenu t) {
    return getChildList(list, t).size() > 0 ? true : false;
}