业务实战篇:java树形结构工具实战
前言
嗨,大家好!辜负了大家的期望!多久才再次打开博客!这次打开,我会以技术结合业务为大家分享真正的干货。让大家真正的意义上将技术用到业务上,而不是纯粹的技术分享,或者业务演说。希望持续关注。后面会对spring 、mybatis、springboot、dubbo、springcloud、redis、mq、es等一系列的技术结合业务范畴进行展开,非常实用的工具和业务型通用技术简介。
回顾
之前的 java树形结构工具,再次做下回顾,发现很多人私信我,联系不到我,不知道该如何使用该工具;我重新拿出来对该工具进行业务实战演练,希望帮助到将用到这个工具的伙伴们;
1)树形结构工具代码
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 描述:基层树形结构实体类--ID AND PARENTID AND CHILDSLIST
* 作者: xfz
* 时间:2016年7月2日
* 版本号:1.0
*/
public class BaseTreeObj<E, ID extends Serializable> implements Serializable {
private static final long serialVersionUID = 1L;
private ID id;
private ID parentId;
private List<E> childsList = new ArrayList<E>();
public void setId(ID id) {
this.id = id;
}
public ID getId() {
return id;
}
public ID getParentId() {
return parentId;
}
public void setParentId(ID parentId) {
this.parentId = parentId;
}
public List<E> getChildsList() {
return childsList;
}
public void setChildsList(List<E> childsList) {
this.childsList = childsList;
}
}
在这里插入代码片
package com.asop.core.utils.tree;
import java.io.Serializable;
import java.util.List;
/**
* 描述:树形结构服务类
* 作者: xfz
* 时间:2016年7月2日
* 版本号:1.0
*/
public interface TreeInterface<T extends BaseTreeObj<T, ID>, ID extends Serializable> {
/**
* 获得指定节点下所有归档
*
* @param list
* @param parentId
* @return
* @author xfz
* 上午1:09:49
*/
public List<T> getChildTreeObjects(List<T> list, ID parentId);
/**
* 递归列表
*
* @param list
* @param t
* @author xfz
* 上午1:11:57
*/
public void recursionFn(List<T> list, T t);
/**
* 获得指定节点下的所有子节点
*
* @param list
* @param t
* @return
* @author xfz
* 上午1:12:55
*/
public List<T> getChildList(List<T> list, T t);
/**
* 判断是否还有下一个子节点
*
* @param list
* @param t
* @return
* @author xfz
* 上午1:13:43
*/
public boolean hasChild(List<T> list, T t);
}
在这里插入代码片
package com.asop.core.utils.tree;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 描述:获得树形的服务实现 作者: xfz
* <p>
* 时间:2016年7月2日
* <p>
* 版本号:1.0
*/
public class TreeService<T extends BaseTreeObj<T, ID>, ID extends Serializable> implements
TreeInterface<T, ID> {
public List<T> getChildTreeObjects(List<T> list, ID parentId) {
List<T> returnList = new ArrayList<T>();
for (T res : list) {
/**
* 判断第一个对象是否为第一个节点
*
*/
if (((Comparable) res.getParentId()).compareTo(parentId) == 0) {
/**
* 相等--说明第一个节点为父节点--递归下面的子节点
*/
recursionFn(list, res);
returnList.add(res);
}
}
return returnList;
}
/**
* 递归列表
*
* @param list
* @param t
* @author xfz
* <p>
* 上午1:11:57
*/
public void recursionFn(List<T> list, T t) {
List<T> childsList = getChildList(list, t);
/**
* 设置他的子集对象集
*/
t.setChildsList(childsList);
/**
* 迭代--这些子集的对象--时候还有下一级的子级对象
*/
for (T nextChild : childsList) {
/**
* 下一个对象,与所有的资源集进行判断
*/
if (hasChild(list, nextChild)) {
/**
* 有下一个子节点,递归
*/
Iterator<T> it = childsList.iterator();
while (it.hasNext()) {
T node = it.next();
/**
* 所有的对象--跟当前这个childsList 的对象子节点
*/
recursionFn(list, node);
}
}
}
}
/**
* 获得指定节点下的所有子节点
*
* @param list
* @param t
* @return
* @author xfz
* <p>
* 上午1:12:55
*/
public List<T> getChildList(List<T> list, T t) {
List<T> childsList = new ArrayList<T>();
for (T child : list) {
/**
* 判断集合的父ID是否等于上一级的id
*/
if (((Comparable) child.getParentId()).compareTo(t.getId()) == 0) {
childsList.add(child);
}
}
return childsList;
}
/**
* 判断是否还有下一个子节点
*
* @param list
* @param t
* @return
* @author xfz
* <p>
* 上午1:13:43
*/
public boolean hasChild(List<T> list, T t) {
return getChildList(list, t).size() > 0 ? true : false;
}
}
老铁们喜欢静态工具,附上静态工具代码:
import com.asop.core.utils.tree.BaseTreeObj;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 描述:树形结构服务类
* 作者: xfz
* 时间:2016年7月2日
* 版本号:1.0
*/
public class TreeUtil {
/**
* 获得指定节点下所有归档
*
* @param list
* @param parentId
* @return
* @author xfz
* 上午1:09:49
*/
public static <T extends BaseTreeObj<T, ID>, ID extends Serializable> List<T> getChildTreeObjects(List<T> list, ID parentId) {
List<T> returnList = new ArrayList<T>();
for (T res : list) {
/**
* 判断第一个对象是否为第一个节点
*
*/
if (((Comparable) res.getParentId()).compareTo(parentId) == 0) {
/**
* 相等--说明第一个节点为父节点--递归下面的子节点
*/
recursionFn(list, res);
returnList.add(res);
}
}
return returnList;
}
/**
* 递归列表
*
* @param list
* @param t
* @author xfz
* 上午1:11:57
*/
public static <T extends BaseTreeObj<T, ID>, ID extends Serializable> void recursionFn(List<T> list, T t) {
List<T> childsList = getChildList(list, t);
/**
* 设置他的子集对象集
*/
t.setChildsList(childsList);
/**
* 迭代--这些子集的对象--时候还有下一级的子级对象
*/
for (T nextChild : childsList) {
/**
* 下一个对象,与所有的资源集进行判断
*/
if (hasChild(list, nextChild)) {
/**
* 有下一个子节点,递归
*/
Iterator<T> it = childsList.iterator();
while (it.hasNext()) {
T node = it.next();
/**
* 所有的对象--跟当前这个childsList 的对象子节点
*/
recursionFn(list, node);
}
}
}
}
/**
* 获得指定节点下的所有子节点
*
* @param list
* @param t
* @return
* @author xfz
* 上午1:12:55
*/
public static <T extends BaseTreeObj<T, ID>, ID extends Serializable> List<T> getChildList(List<T> list, T t) {
List<T> childsList = new ArrayList<T>();
for (T child : list) {
/**
* 判断集合的父ID是否等于上一级的id
*/
if (((Comparable) child.getParentId()).compareTo(t.getId()) == 0) {
childsList.add(child);
}
}
return childsList;
}
/**
* 判断是否还有下一个子节点
*
* @param list
* @param t
* @return
* @author xfz
* 上午1:13:43
*/
public static <T extends BaseTreeObj<T, ID>, ID extends Serializable> boolean hasChild(List<T> list, T t) {
return getChildList(list, t).size() > 0 ? true : false;
}
}
树形结构场景应用
在实际应用中,我们很多项目很多业务模块经常用到树形结构呈现;经常出现在:结构关系中是父子级关系;如:表结构、前端页面父子级标签等等;
今天我们主要讲解关于结构,父子级关系的应用场景;
我想很多人经常用到表结构有父子级别的关系,经常需要递归遍历他们之间的关系处理。例如:机构表(含id,parentId)、菜单表(含id,parentId)或者说是机构表(含code、parentCode)等业务需要的递归关系;
只要是父子级关系应用,我们都常会有需求:
1)获取树形结构列表;
2)指定某个节点获取该节点下的列表(要求组装成树形列表返回不含当前节点);
3)指定某个节点获取含该节点下的列表(要求组装成树形列表返回);
4)指定某个节点获取该节点下的列表;
5)校验某个节点下是否还有子节点;
只要有以上的需求,我们的工具就能发挥到实际的应用。那我们该怎么实现呢??下面请看,树形结构实战段落…
树形结构实战
假设我们有一个菜单表 如下:
CREATE TABLE `sys_menu` (
`id` bigint(20) NOT NULL,
`tenant_id` bigint(20) DEFAULT NULL COMMENT '租户ID',
`del_flag` varchar(4) DEFAULT '0' COMMENT '删除标识(0-正常,1-删除) 默认0',
`sort` tinyint(4) DEFAULT '0' COMMENT '排序(升序)默认0',
`create_user` varchar(50) DEFAULT NULL COMMENT '创建用户',
`update_user` varchar(50) DEFAULT NULL COMMENT '修改用户',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remarks` varchar(250) DEFAULT NULL COMMENT '备注',
`app_id` bigint(20) DEFAULT NULL COMMENT '应用ID',
`parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID,一级菜单为0',
`name` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '菜单名称',
`code` varchar(50) NOT NULL COMMENT '菜单编号',
`route_url` varchar(200) DEFAULT NULL COMMENT '后端URL',
`view_url` varchar(200) DEFAULT NULL COMMENT '前端菜单URL',
`permission` varchar(500) DEFAULT NULL COMMENT '菜单权限标识(多个用逗号分隔,如:user:list,user:create)',
`type` int(11) NOT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
`icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
`status` tinyint(4) DEFAULT '1' COMMENT '状态 0:禁用 1:正常, 默认1',
PRIMARY KEY (`id`),
UNIQUE KEY `code` (`code`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='菜单表';
继承BaseTreeObj实现菜单树类(该类是为了展示给前端呈现的VO):
package com.asop.system.pojo.vo;
import com.asop.core.utils.tree.BaseTreeObj;
/**
* 菜单树形
*/
public class MenuTree extends BaseTreeObj<MenuTree, Long> {
/**
* 代码
*/
private String code;
/**
* 名称
*/
private String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这边省略大家各自实现的domain层、dao层、service层。。。。。。。。。。
1)获取树形结构列表;
/**
* 获取菜单树形列表
*/
@Test
public void testFindMenuTree() {
/**
* 1.获取所有的菜单列表[一般做了缓存获取等]
*/
List<MenuTree> menuTrees = new ArrayList<>();
List<SysMenu> menuList = sysMenuService.selectList(null);
convertMenuList(menuTrees, menuList);
/**
* 2.组装树形结构
*/
TreeInterface<MenuTree, Long> menuTreeService = new TreeService<>();
List<MenuTree> treeList = menuTreeService.getChildTreeObjects(menuTrees, 0L);
System.out.println(JSON.toJSONString(treeList));
}
2)指定某个节点获取该节点下的列表(要求组装成树形列表返回不含当前节点)
/**
* 获取指定某个节点下的所有菜单树形列表
*/
@Test
public void testFindMenuTreeByOne() {
/**
* 1.获取所有的菜单列表[一般做了缓存获取等]
*/
List<MenuTree> menuTrees = new ArrayList<>();
List<SysMenu> menuList = sysMenuService.selectList(null);
convertMenuList(menuTrees, menuList);
TreeInterface<MenuTree, Long> menuTreeService = new TreeService<>();
/**
* 2.指定某个节点,获取这个节点下的树形列表
*/
SysMenu res = sysMenuService.selectById(1L);
MenuTree menuTree = new MenuTree();
convertMenu(res, menuTree);
/**
* 3.组装树形结构
*/
List<MenuTree> treeList = menuTreeService.getChildTreeObjects(menuTrees, res.getId());
System.out.println(JSON.toJSONString(treeList));
}
3)指定某个节点获取含该节点下的列表(要求组装成树形列表返回)
/**
* 获取指定某个节点下的所有菜单树形列表
*/
@Test
public void testFindMenuTreeByOneIncludeOne() {
/**
* 1.获取所有的菜单列表[一般做了缓存获取等]
*/
List<MenuTree> menuTrees = new ArrayList<>();
List<SysMenu> menuList = sysMenuService.selectList(null);
convertMenuList(menuTrees, menuList);
TreeInterface<MenuTree, Long> menuTreeService = new TreeService<>();
/**
* 2.指定某个节点,获取这个节点下的树形列表
*/
SysMenu res = sysMenuService.selectById(1L);
MenuTree menuTree = new MenuTree();
convertMenu(res, menuTree);
/**
* 3.组装树形结构
*/
List<MenuTree> treeList = menuTreeService.getChildTreeObjects(menuTrees, res.getId());
/**
* 4.设置某个节点下的所有子节点
*/
menuTree.setChildsList(treeList);
System.out.println(JSON.toJSONString(menuTree));
}
4)指定某个节点获取该节点下的列表
/**
* 获取指定菜单某个节点下的子节点
*/
@Test
public void testFindMenuChildByOne() {
/**
* 1.获取所有的菜单列表[一般做了缓存获取等]
*/
List<MenuTree> menuTrees = new ArrayList<>();
List<SysMenu> menuList = sysMenuService.selectList(null);
convertMenuList(menuTrees, menuList);
TreeInterface<MenuTree, Long> menuTreeService = new TreeService<>();
/**
* 2.指定某个节点,获取这个节点下的树形列表
*/
SysMenu res = sysMenuService.selectById(1L);
MenuTree menuTree = new MenuTree();
convertMenu(res, menuTree);
/**
* 3.组装树形结构
*/
List<MenuTree> treeList = menuTreeService.getChildList(menuTrees, menuTree);
System.out.println(JSON.toJSONString(treeList));
}
总结
树形结构工具,就是这么简单方便使用,想替换成静态工具的老铁们,可以直接使用上述直接替换业务代码中的实现部分;
好了,今天的分享就到这,敬请期待明天的技术篇章分享,帮助到你的记得点个赞,加入收藏!后面持续干货分享!!感谢老铁的阅读。。。。