一、项目背景
由于最近项目中需要实现展示菜单功能,菜单是需要多级,并且级数不固定。像这种需求,一般就是用递归实现了,可以从第一级一直往下查,一直查询到为空为止。
二、数据库实体类字段
- 两个实体类,一个是对应数据库的实体类,VO是返回给前端的实体类
public class RcMenu {
private Integer menuId; //菜单ID
private String menuName;//菜单名称
private Boolean status; //菜单状态
private String level; //菜单级别
private Integer parentId; //父类ID
private Integer sortOrder; //排序
}
public class RcMenuVO {
private Integer menuId; //菜单ID
private String menuName;//菜单名称
private Boolean status; //菜单状态
private String level; //菜单级别
private Integer parentId; //父类ID
private Integer sortOrder; //排序
//存放子菜单目录
private List<RcMenuVO> children;
}
三、项目中代码实现
/**
* 对象实体类转换
* @param rcMenu
* @return
*/
private RcMenuVO rcMenuTORcMenuVO(RcMenu rcMenu) {
RcMenuVO rcMenuVO = new RcMenuVO();
BeanUtils.copyProperties(rcMenu, rcMenuVO);
return rcMenuVO;
}
/**
* 根据一级递归调用子级
* reversed方法 表示数字越大靠前
* @param menuList
* @param rootMenuList
* @return
*/
private void findSubCategory(List<RcMenu> menuList, List<RcMenuVO> rootMenuList) {
// 遍历一级
for (RcMenuVO rcMenuVO : rootMenuList) {
List<RcMenuVO> rcMenuVOList = new ArrayList<>();
// 查找子级
for (RcMenu rcMenu : menuList) {
// 判断当前目录是否是子父级关系
if (rcMenuVO.getMenuId().equals(rcMenu.getParentId())) {
rcMenuVOList.add(rcMenuTORcMenuVO(rcMenu));
}
// 递归调用,不管有几级菜单,都能够适用
findSubCategory(menuList, rcMenuVOList);
// 类目显示排序,
rcMenuVOList.sort(Comparator.comparing(RcMenuVO::getSortOrder));
}
// 最后把查到的子级保存到一级目录中
rcMenuVO.setChildren(rcMenuVOList);
}
}
/**
* 各级菜单列表展示
* @param menu
* @param pageObject
* @return
*/
public List<RcMenuVO> queryMenuList(RcMenu menu, PageObject pageObject) {
List<RcMenu> menuList = null;
Page<RcMenu> page = PageHelper.startPage(pageObject.getPageNum(), pageObject.getPageSize());
// 将用户页面提交的参数拷贝到查询条件去
SpringBeanUtils.copyPropertiesIgnoreNull(pageObject, page);
//先查出全部菜单
menuList = menuMapper.queryMenuList(menu);
//获取一级菜单 0代表一级菜单 .reversed()
List<RcMenuVO> rootMenuList = menuList.stream()
.filter(e -> e.getParentId().equals(0))
.map(this::rcMenuTORcMenuVO)
.sorted(Comparator.comparing(RcMenuVO::getSortOrder))
.collect(Collectors.toList());
//查找字节点
findSubCategory(menuList,rootMenuList);
// 将真实分页信息拷贝到用户页面
SpringBeanUtils.copyPropertiesIgnoreNull(page, pageObject);
//返回值
return rootMenuList;
}
/**
* 根据菜单id 查找子菜单
* @param menuId
* @return
*/
public List<RcMenuVO> queryMenuById(RcMenu menu) {
//先查出菜单
List<RcMenu> menuList = menuMapper.queryMenuList(menu);
//获取一级菜单 0代表一级菜单 .reversed()
List<RcMenuVO> rootMenuList = menuList.stream()
.filter(e -> e.getParentId().equals(0))
.map(this::rcMenuTORcMenuVO)
.sorted(Comparator.comparing(RcMenuVO::getSortOrder))
.collect(Collectors.toList());
//查找字节点
findSubCategory(menuList,rootMenuList);
//返回值
List<RcMenuVO> rootMenu = new ArrayList<RcMenuVO>();
for (int i = 0; i < rootMenuList.size(); i++) {
if (rootMenuList.get(i).getMenuId().equals(menu.getMenuId())) {
RcMenuVO rcMenuVO = rootMenuList.get(i);
rootMenu.add(rcMenuVO);
}
}
return rootMenu;
}
四、返回的result值 如下:
{
"successful": true,
"data": [
{
"menuId": 1,
"menuName": "菜单",
"createTime": "2020-05-22",
"status": "启用",
"level": "一级菜单",
"parentId": 0,
"sortOrder": 0,
"children": [
{
"menuId": 2,
"menuName": "菜单111",
"createTime": "2020-05-22",
"level": "二级菜单",
"parentId": 1,
"sortOrder": 1,
"status": "停用"
},
{
"menuId": 3,
"menuName": "菜单222",
"createTime": "2020-05-22",
"level": "二级菜单",
"parentId": 1,
"sortOrder": 2,
"status": "启用"
}
]
}
],
"page": null,
"resultHint": "{\"message\":\"数据查询成功\"}",
"errorPage": "",
"draw": 0,
"recordsTotal": 0,
"recordsFiltered": 0,
"type": "info"
}