java構建樹形列表(帶children屬性)
阿新 • • 發佈:2022-03-30
構建的方式是通過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;
}