Java树形菜单系统设计与实现
ruoyi实现
根据用户 ID 查询菜单树
java
复制代码
public List<SysMenu> selectMenuTreeByUserId(String useNo) {
List<SysMenu> menus = null;
if (SecurityUtils.isAdmin(useNo))
{
// 管理员查询所有权限
menus = menuMapper.selectMenuTreeAll();
}
else
{
// 不是管理员,需要查询路由
menus = menuMapper.selectMenuTreeByUseNo(useNo);
}
return getChildPerms(menus, 0);
}
根据给定的父节点ID构建出树形结构的子菜单。
java
复制代码
// 根据给定的父节点ID从平面菜单列表中筛选并构建出树形结构的子菜单。
public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) {
List<SysMenu> returnList = new ArrayList<SysMenu>();
for (SysMenu t : list) {
if (t.getParentId() == parentId) {
recursionFn(list, t);
returnList.add(t);
}
}
return returnList;
}
递归地为当前菜单节点构建完整的子树结构
java
复制代码
// 递归地为当前菜单节点构建完整的子树结构,设置其所有子节点及其后代节点。
private void recursionFn(List<SysMenu> list, SysMenu t) {
// 得到子节点列表
List<SysMenu> childList = getChildList(list, t);
t.setChildren(childList);
for (SysMenu tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
查找特定父节点所有直接子节点
java
复制代码
// 从平面菜单列表中查找特定父节点所有直接子节点的方法。
private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t) {
List<SysMenu> tlist = new ArrayList<SysMenu>();
for (SysMenu n : list) {
if (n.getParentId().longValue() == t.getMenuId().longValue()) {
tlist.add(n);
}
}
return tlist;
}
判断是否有子节点
java
复制代码
// 判断是否有子节点
private boolean hasChild(List<SysMenu> list, SysMenu t) {
return getChildList(list, t).size() > 0;
}
简化
java
复制代码
public List<SysMenu> selectMenuTreeByUserId(String useNo) {
List<SysMenu> menus = null;
if (useNo.equals("P059569")) {
// 管理员查询所有权限
return selectMenuTree() ;
} else {
// 不是管理员,需要查询路由
return selectMenuTree() ;
}
}
java
复制代码
// 查询所有菜单并递归子菜单
@Override
public List<SysMenu> selectMenuTree() {
LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
// 设置查询条件
wrapper.in(SysMenu::getMenuType, Arrays.asList("M", "C")) // 菜单类型为目录(M)或菜单(C)
.eq(SysMenu::getStatus, 0) // 状态为0(正常)
.orderByAsc(SysMenu::getParentId, SysMenu::getOrderNum);// 设置排序(先按父ID排序,再按排序号排序)
List<SysMenu> menus = menuMapper.selectList(wrapper);
// 1. 创建菜单映射表并初始化children
// 将菜单列表转换为一个Map,其中:
// - 键(key)是菜单ID(Long类型)
// - 值(value)是菜单对象(SysMenu)
Map<Long, SysMenu> menuMap = menus.stream()
// peek()是一个中间操作,用于对每个元素执行操作但不改变流内容
// 这里对每个菜单对象执行初始化children列表的操作
.peek(menu -> menu.setChildren(new ArrayList<>()))
// 终止操作,将流转换为Map
// Collectors.toMap()需要两个参数:
// 1. SysMenu::getMenuId - 键提取函数,从菜单对象获取菜单ID作为Map的键
// 2. Function.identity() - 值提取函数,直接使用菜单对象本身作为Map的值
.collect(Collectors.toMap(SysMenu::getMenuId, Function.identity()));
// 2. 构建父子关系
menus.forEach(menu -> {
if (menu.getParentId() != 0) {// 如果不是根菜单(parentId=0的是根菜单)
SysMenu parent = menuMap.get(menu.getParentId());
if (parent != null) {
parent.getChildren().add(menu);// 将当前菜单添加到父菜单的children列表中
}
}
});
// 3. 返回根节点并排序
return menus.stream()
// 1.筛选出所有根菜单(parentId == 0的菜单)
.filter(menu -> menu.getParentId() == 0)
// 2.对每个根菜单进行处理
.peek(root ->
// 对当前根菜单的子菜单列表进行排序
// 使用Comparator.comparingInt根据orderNum字段进行升序排序
root.getChildren().sort(Comparator.comparingInt(SysMenu::getOrderNum)))
// 3.对所有根菜单进行升序排序
.sorted(Comparator.comparingInt(SysMenu::getOrderNum))
// 4.将处理后的Stream收集为List
.collect(Collectors.toList());
}