项目中难免遇到使用树型结构,如部门、菜单等。
它们有共同的属性: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": "调度中心"
}
]
}
至此,可以方便实现树结构JSON的返回。over.