微信公众号:潇雷
当努力到一定程度,幸运自与你不期而遇。
后台管理系统是web开发必备的一个项目,因此有必要对系统的一些基本功能做个梳理,今天要看的内容是如何递归生成树形结构菜单,效果图如下:
菜单分为一级菜单、二级菜单、复杂的菜单甚至包含三级菜单和四级菜单,这些数据在表里面都是在一个菜单目录表里。
表的核心设计如下:
字段 | 名称 | 备注 |
---|---|---|
id | int | 主键id |
parent_id | int | 一级菜单为0 ,其他菜单指向父类的id |
menu_path | varchar | 资源路径 |
sort | int | 排序 |
menu_button | tinyint | 是否作为目录展示,或者隐藏等需求 |
思路比较统一:
1、首先找到菜单数据的所有数据
2、然后找到所有的一级菜单,将它的子树拼接上
3、子树也会有子菜单,需要递归拼接子树的子菜单。
首先对原先的实体类,我们需要增加一个字段存放子菜单的列表,加上注解表示该字段不在数据库中拥有。
@Override
public List<ChildMenuVO> listWithTree() {
//1、查出所有菜单
List<CategoryEntity> categoryEntities = categoryDao.selectList(null);
//2、组装成父子的树形结构
List<ChildMenuVO> childMenuVOS =treeMenu(categoryEntities);
return childMenuVOS;
}
private List<ChildMenuVO> treeMenu(List<CategoryEntity> categoryEntities) {
List<ChildMenuVO> childMenuVOS=new ArrayList<>();
for (int i = 0; i < categoryEntities.size(); i++) {
CategoryEntity categoryEntity=categoryEntities.get(i);
//如果父id为0 的话,就不执行后续方法
if(0!=categoryEntity.getParentCid().intValue()){
continue;
}
ChildMenuVO childMenuVO = new ChildMenuVO();
BeanUtils.copyProperties(categoryEntity,childMenuVO);
//递归判断 当前menu 是否有子节点,如果有则set
childMenuVO.setChild(subMenu(categoryEntity,categoryEntities));
childMenuVOS.add(childMenuVO);
}
return childMenuVOS;
}
private List<ChildMenuVO> subMenu(CategoryEntity parentMenu, List<CategoryEntity> categoryEntities) {
List<ChildMenuVO> childMenuVOS =new ArrayList<>();
//遍历所有目录
for (int i = 0; i < categoryEntities.size(); i++) {
CategoryEntity subCategory=categoryEntities.get(i);
if(subCategory.getParentCid().equals(parentMenu.getCatId())){
ChildMenuVO childMenuVO = new ChildMenuVO();
BeanUtils.copyProperties(subCategory,childMenuVO);
childMenuVO.setChild(subMenu(subCategory,categoryEntities));
childMenuVOS.add(childMenuVO);
}
}
return childMenuVOS;
}
public List<CategoryEntity> listWithTree() {
//1、查出所有菜单
List<CategoryEntity> categoryEntities = categoryDao.selectList(null);
//2、组装成父子的树形结构
//2.1 找到所有的一级分类
List<CategoryEntity> level1Menus = categoryEntities.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid() == 0;
}).map(menu->{
menu.setChildren(getChildrens(menu,categoryEntities));
return menu;
}).sorted((menu1,menu2)->{
return (menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort());
})
.collect(Collectors.toList());
return level1Menus;
}
//递归找到当前菜单的子菜单
private List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid().equals(root.getCatId());
}).map(categoryEntity -> {
categoryEntity.setChildren(getChildrens(categoryEntity,all));
return categoryEntity;
}).sorted((menu1,menu2)->{
return (menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort());
}).collect(Collectors.toList());
return children;
}
不得不说java8的stream流极大的简洁了代码,后续也会记录java8的文章,效果也达到了,stream流有点像sql,可以做出排序、过滤、判断等各种简洁的操作。
今天的分享就到这里,有兴趣可以关注,后续更多内容干货敬请期待。
文章浏览阅读2.9k次。在线上有一张表很大,积累了几年的消费数据,现在需要把这张表几年前的数据给清掉,数据量将近1亿,直接按年份将其中的数据delete,你会发现删了几小时都没有返回。这是因为每执行一次delete,需要同时将该行的删除操作记录作为事务记录在日志中保存以便进行回滚。最终采用的方案是:(1)抽取需要保留的数据到备份表中,(2)truncate旧表(3)备份表中的数据再插入truncate表我的执行实操如下:..._mysql 数据量大了后删除卡主
文章浏览阅读3k次,点赞3次,收藏11次。1、挂载命令(mount)首先简单的介绍一下Linux的挂载命令mount,也是在正常使用情况下的挂载磁盘的命令,其参数也有很多,这里简单的介绍一下。平常使用到的命令格式:mount [-t vfstype] [-o options] device dir[e.g.]: mount -t ntfs -o remount,rw /dev/sdb1 /media/imaginemiracle/Disk参数简介:<1> [-t typedef]:用来指定文件系统的类型,若不指定则由moun_ubuntu 系统 tf 卡挂载的分区为 只读分区
文章浏览阅读3.5k次。青龙脚本 小黄鸟配合虚拟机抓变量 软件集
文章浏览阅读1k次。CMake构建Makefile深度解析:从底层原理到复杂项目_cmake源码分析
文章浏览阅读438次。继上次C#制作高仿360安全卫士窗体<一>发布之后响应还不错,我的博客放肆雷特也来了不少的新朋友,在这里先谢谢大家的支持!我自己也反复看了一下觉得对不起大家,写的非常乱而且很少文字介绍。在这里先说明一下,我是一个纯粹想搞技术的,文笔较差。我也想锻炼自己所以才会慢慢的将自己的所学分享出来。一来可以锻炼自己的文笔,二来可以分享知识留给像我一样喜欢这些东西的朋友。所以以后如果缺少介..._winform仿360软件
文章浏览阅读3.1k次。在项目上线以后,用户开始使用时候,总是会遇到各种各样的bug,特别是crash,所以我们就需要收集这些bug,然后去逐步的修改,盘查问题所在,保障在以后的版本里不会出现相同的问题。大部分人的做法是抓取到APP的Crash信息,然后保存到本地,在一个特定的条件下,将统计到的信息发送给服务器。这也是解决办法的一种方式,但是这个分析的过程就需要我们自己做了,这个过程里就会发现会产出很多重复的错误代码,然..._移动端收集bug平台
文章浏览阅读801次。react 条件渲染 为什么我们不能使用If-Else以及三元运算符如何提供帮助 (Why We Can’t Use If-Else and How the Ternary Operator can Help)One of the great strengths of the React.js framework is its modular design philosophy. When we..._react when choose 实现 else 效果
文章浏览阅读72次。前面一课说了简单的整型数据和浮点型数据,但是没有说char字符类型,今天我们来说说char字符类型。【Java Char型】在Java中提供了字符类型,与C/C++类似,Java中字符是经过编码的;Exp: 编码值==65的字符是'A';在Java中,使用的是Unicode编码格式。通常情况下,我们认为Unicode是16 bit的编码规则。但是很多童鞋们,还是不明白这个东西..._阅读下面的代码,回答下列问题。printwriter filedata = new printwriter(“da
文章浏览阅读3.2w次。https://zhidao.baidu.com/question/513074388.html关掉打开的PDF文件所在的我的电脑文件夹,再保存即可!不用每次另存为!_adobe acrobat pro dc无法保存
文章浏览阅读1.4k次。collisionFilter 碰撞过滤器1、Matter.js 创建的物体可以为它们设置碰撞规则,如哪些物体相互应该碰撞,而哪些物体相互之间则不应该发生碰撞。2、Body(刚体)提供了一个 collisionFilter 属性,其值是一个 json 数组,可选值有:group,category,mask。默认值如下:collisionFilter: { catego..._matter.js
文章浏览阅读586次。the raven
文章浏览阅读1.5k次,点赞3次,收藏2次。现在开始最乱的代码显示登陆窗口,按钮跳转注册窗口, 搭这个框架,大大小小写了12个脚本,咱们前两篇写了7个,还有5个,其中包含一个存取名称密码的记录数据的脚本(dataMgr)using UnityEngine;using System.Collections;/// /// 登陆场景UI控制器/// public class UILoginScen_"login(m_context, m_prefs.getstring(\"user_key\", null));"