一个树型通用接口
Posted kstrive
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个树型通用接口相关的知识,希望对你有一定的参考价值。
项目中难免遇到使用树型结构,如部门、菜单等。
它们有共同的属性: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.
以上是关于一个树型通用接口的主要内容,如果未能解决你的问题,请参考以下文章