微信公众号:潇雷
当努力到一定程度,幸运自与你不期而遇
1、概述
后台管理系统是web开发必备的一个项目,因此有必要对系统的一些基本功能做个梳理,今天要看的内容是如何递归生成树形结构菜单,效果图如下:
菜单分为一级菜单、二级菜单、复杂的菜单甚至包含三级菜单和四级菜单,这些数据在表里面都是在一个菜单目录表里。
表的核心设计如下:
字段 | 名称 | 备注 |
---|---|---|
id | int | 主键id |
parent_id | int | 一级菜单为0 ,其他菜单指向父类的id |
menu_path | varchar | 资源路径 |
sort | int | 排序 |
menu_button | tinyint | 是否作为目录展示,或者隐藏等需求 |
2、代码实现
思路比较统一:
1、首先找到菜单数据的所有数据
2、然后找到所有的一级菜单,将它的子树拼接上
3、子树也会有子菜单,需要递归拼接子树的子菜单。
首先对原先的实体类,我们需要增加一个字段存放子菜单的列表,加上注解表示该字段不在数据库中拥有。
2.1 基础版实现
@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;
}
2.2 进阶版实现
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,可以做出排序、过滤、判断等各种简洁的操作。
今天的分享就到这里,有兴趣可以关注,后续更多内容干货敬请期待。