沈阳做网站推广,共享经济型网站开发,商机创业网,网页转图片前言
这篇文中#xff0c;我一共会用两种方式来实现目录树的数据结构#xff0c;两种写法逻辑是一样的#xff0c;只是一种适合新手理解#xff0c;一种看着简单明了但是对于小白不是很好理解。在这里我会很详细的讲解每一步代码#xff0c;主要是方便新人看懂#xff0…
前言
这篇文中我一共会用两种方式来实现目录树的数据结构两种写法逻辑是一样的只是一种适合新手理解一种看着简单明了但是对于小白不是很好理解。在这里我会很详细的讲解每一步代码主要是方便新人看懂弥补曾经自己学习过程中的苦恼。提醒如果第一种写法理解不了或则看不懂可以看第二种写法通过第二种写法去理解第一种的写法两种写法逻辑是一样的。后面我也会详细去讲解。
一、什么是目录结构
就是在实际开发过程中总会遇到菜单或则是权限这个时候就涉及到后端返回数据给前端的时候不能一个集合把数据一股脑的全部扔给前端总要把数据整理好做成像书目录一样的结构返回给前端。就像以下图示一样 二、目录树结构实现写法
1、准备阶段
①创建数据表
PS如果是练习可以不用创建数据库数据全部通过java代码来创建也可以
CREATE TABLE permission_directory (
id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键ID,
parent_id int(11) NOT NULL DEFAULT 0 COMMENT 父目录ID,
menu_name varchar(255) NOT NULL COMMENT 菜单名称,
menu_level int(11) NOT NULL COMMENT 菜单等级,
route varchar(255) NOT NULL COMMENT 路由,
PRIMARY KEY (id) COMMENT 主键,
UNIQUE KEY parent_id (parent_id,menu_name,menu_level,route) COMMENT 唯一索引包含父目录ID、菜单名称、菜单等级和路由
) ENGINEInnoDB DEFAULT CHARSETutf8 COMMENT 存储引擎为InnoDB字符集为utf8;
②向表中插入数据
INSERT INTO permission_directory (parent_id, menu_name, menu_level, route) VALUES
(1, 首页, 0, /index),
(2, 系统设置, 0, /user/manage),
(3, 操作手册, 0, /role/manage),
(4, 菜单管理, 2, /menu/manage),
(5, 用户管理, 2, /system/setting),
(6, 日志管理, 3, /log/manage),
(7, 定时任务, 3, /task/schedule),
(8, API接口文档, 3, /api/documentation),
(9, 操作手册, 8, /operation/manual);
③创建菜单对象PermissionDirectory类
PS这里我用了Data注解就不用封装属性了如果没写Data注解就把每个属性封装以下也就是get()和set()方法
Data
public class PermissionDirectory {MyAnnotation(主键id)private int id;MyAnnotation(父目录id)private int parentId;MyAnnotation(菜单名称)private String menuName;MyAnnotation(菜单等级)private int menuLevel;MyAnnotation(路由)private String route;
}
④创建存储菜单对象PermissionDirectoryResVO类
Data
public class PermissionDirectoryResVO {MyAnnotation(主键id)private Integer id;MyAnnotation(父目录id)private Integer parentId;MyAnnotation(菜单名称)private String menuName;MyAnnotation(菜单等级)private Integer menuLevel;MyAnnotation(路由)private String route;MyAnnotation(用于存储当前目录下面的全部子集)private ListPermissionDirectoryResVO authMenuList;
}
2、逻辑代码实现
这里关于如何去连接数据库啊等等一系列都省略了关键就是目录树的逻辑讲解
①第一种写法 public ListPermissionDirectoryResVO searchMenu() {ListPermissionDirectoryResVO directoryTree new ArrayList();ListPermissionDirectory menuList permissionDirectoryMapper.getMenuList();if (CollectionUtil.isNotEmpty(menuList)){ListPermissionDirectoryResVO pdr menuList.stream().map(PermissionDirectory - {PermissionDirectoryResVO permissionDirectoryResVO new PermissionDirectoryResVO();BeanUtils.copyProperties(PermissionDirectory,permissionDirectoryResVO);return permissionDirectoryResVO;}).collect(Collectors.toList());pdr.forEach(e -{ListPermissionDirectoryResVO pdrList getChildrenList(e.getId(),pdr);e.setAuthMenuList(pdrList ! null ? pdrList : null);});ListPermissionDirectoryResVO parentNodes pdr.stream().filter(e - e.getParentId().equals(0)).collect(Collectors.toList());directoryTree.addAll(parentNodes);}return directoryTree;}* 获取全部子集* param id* param list* return*/public static ListPermissionDirectoryResVO getChildrenList(Integer id, ListPermissionDirectoryResVO list){return list.stream().filter(t- t.getParentId().equals(id)).collect(Collectors.toList());}
}
第一种写法代码详细解
第一步创建存储最终结果数据的集合容器ListPermissionDirectoryResVO directoryTree new ArrayList();第二步获取需要整理成树状结构的所有数据ListPermissionDirectory menuList permissionDirectoryMapper.getMenuList();PS这里我是通过查询数据获取的数据练习的话可以new一些数据出来存入集合中就行了第三步判断获取的数据是否为空如果为空的话就没有去整理成树结构的必要了数据都没有if (CollectionUtil.isNotEmpty(menuList)){ .... }PS:这里我用的是糊涂类提供的方法进行判断如果小白在写的过程中发现报错找不到这个方法或则这个类就换一种写法第四步将获取的PermissionDirectory数据全部赋值给PermissionDirectoryResVOListPermissionDirectoryResVO pdr menuList.stream().map(PermissionDirectory - {PermissionDirectoryResVO permissionDirectoryResVO new PermissionDirectoryResVO();BeanUtils.copyProperties(PermissionDirectory,permissionDirectoryResVO);return permissionDirectoryResVO;}).collect(Collectors.toList());具体解释如下menuList.stream()将menuList集合转换为一个流(Stream)map(PermissionDirectory - {...})这个简单理解就是循环menuList集合然后遍历集合中的每一个PermissionDirectory元素BeanUtils.copyProperties(PermissionDirectory,permissionDirectoryResVO)将PermissionDirectory对象的属性值复制到permissionDirectoryResVO对象中。这样authMenuResVO对象就具有了与AuthMenu对象相同的属性值。return permissionDirectoryResVO将转换后的permissionDirectoryResVO对象作为结果返回给调用者。collect(Collectors.toList())将处理后的流中的元素收集到一个新的列表中并返回该列表因此这段代码的作用是将原始列表menuList中的每个元素转换为AuthMenuResVO类型的对象并将转换后的对象存储在一个新的列表permissionDirectoryResVO中。第五步写一个获取子集的方法体public static ListPermissionDirectoryResVO getChildrenList(Integer id, ListPermissionDirectoryResVO list){return list.stream().filter(t- t.getParentId().equals(id)).collect(Collectors.toList());}具体解释如下forEach(e - {...})是list对象的一个方法用于遍历该列表或集合中的每个元素并对每个元素执行一段操作。e - {...}是一个Lambda表达式表示对每个元素执行的操作相当于e就是PermissionDirectoryResVO元素对象因此这段代码就是通过传递一个主键id和一个PermissionDirectoryResVO集合对象参数然后遍历循环PermissionDirectoryResVO对象集合把每一个对象的父目录id和传递过来的参数id进行对比如果父目录id等于参数id就把这个对象收集到新的集合中最后作为参数返回。第六步遍历全部数据利用递归思想获取全部的子集pdr.forEach(e -{ListPermissionDirectoryResVO pdrList getChildrenList(e.getId(),pdr);e.setAuthMenuList(pdrList ! null ? pdrList : null);});具体解释如下ListPermissionDirectoryResVO pdrList getChildrenList(e.getId(),pdr);这一步通过调用第五步写好的方法已经获取到了全部子集就是说如果所有数据一集目录有三个分别是1、2、3那么当循环完的时候会有3个pdrList集合每个集合中分别装有1目录下的数据、2目录下的数据、3目录下的数据。当每一次循环的时候都会对pdr集合中的元素进行一次判断e.setAuthMenuList(pdrList ! null ? pdrList : null);使用三目运算符如果pdrList集合不为空就表示当前元素有子集然把pdrList集合赋值给元素的authMenuList属性如果为空就表示没有子集赋值空就可以。当集合遍历完毕数据情况看图①实例第七步获取所有顶点数据ListPermissionDirectoryResVO parentNodes pdr.stream().filter(e - e.getParentId().equals(0)).collect(Collectors.toList());directoryTree.addAll(parentNodes);具体解释如下判断pdr集合中父目录id为0的数据然后赋值给新的parentNodes最后把这个集合存进directoryTree集合容器中 图①
②第二种写法 public ListPermissionDirectoryResVO searchMenu() {ListPermissionDirectoryResVO directoryTree new ArrayList();ListPermissionDirectory menuList permissionDirectoryMapper.getMenuList();ListPermissionDirectoryResVO pdr new ArrayList();if (CollectionUtil.isNotEmpty(menuList)){for (PermissionDirectory permissionDirectory : menuList){PermissionDirectoryResVO permissionDirectoryResVO new PermissionDirectoryResVO();permissionDirectoryResVO.setId(permissionDirectory.getId());permissionDirectoryResVO.setParentId(permissionDirectory.getParentId());permissionDirectoryResVO.setMenuName(permissionDirectory.getMenuName());permissionDirectoryResVO.setMenuLevel(permissionDirectory.getMenuLevel());permissionDirectoryResVO.setRoute(permissionDirectory.getRoute());pdr.add(permissionDirectoryResVO);}}for (PermissionDirectoryResVO e : pdr){ListPermissionDirectoryResVO pdrList getChildrenList(e.getId(),pdr);e.setAuthMenuList(pdrList ! null ? pdrList : null);}for (PermissionDirectoryResVO e : pdr){if (e.getParentId().equals(0)){directoryTree.add(e);}}return directoryTree;}* 获取全部子集* param id* param list* return*/public static ListPermissionDirectoryResVO getChildrenList(Integer id, ListPermissionDirectoryResVO list){ListPermissionDirectoryResVO pdr new ArrayList();for (PermissionDirectoryResVO per : list){if (per.getParentId().equals(id)){pdr.add(per);}}return pdr;}
}
最终结果
{code: 200,msg: 操作成功,data: [{id: 3,parentId: 0,menuName: 操作手册,menuLevel: 1,route: /role/manage,authMenuList: [{id: 8,parentId: 3,menuName: API接口文档,menuLevel: 2,route: /api/documentation,authMenuList: [{id: 9,parentId: 8,menuName: 操作手册,menuLevel: 3,route: /operation/manual,authMenuList: []}]},{id: 7,parentId: 3,menuName: 定时任务,menuLevel: 2,route: /task/schedule,authMenuList: []},{id: 6,parentId: 3,menuName: 日志管理,menuLevel: 2,route: /log/manage,authMenuList: []}]},{id: 2,parentId: 0,menuName: 系统设置,menuLevel: 1,route: /user/manage,authMenuList: [{id: 5,parentId: 2,menuName: 用户管理,menuLevel: 2,route: /system/setting,authMenuList: []},{id: 4,parentId: 2,menuName: 菜单管理,menuLevel: 2,route: /menu/manage,authMenuList: []}]},{id: 1,parentId: 0,menuName: 首页,menuLevel: 1,route: /index,authMenuList: []}]
}