From 1ecf22d61ef595a34efb669d980e0cd8b82ee2a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E8=BE=9E=E6=9C=AA=E5=AF=92?= <545073804@qq.com> Date: Fri, 13 Mar 2026 15:43:19 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8A=A8=E6=80=81=E8=A7=84=E5=88=92=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=A0=91=E7=9A=84=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/utils/TreeBuildUtils.java | 21 ++++++++ .../service/impl/SysMenuServiceImpl.java | 53 +++++-------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java index 5f60ebff1..491559d90 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java @@ -10,7 +10,9 @@ import lombok.NoArgsConstructor; import org.dromara.common.core.utils.reflect.ReflectUtils; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -28,6 +30,25 @@ public class TreeBuildUtils extends TreeUtil { */ public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + /** + * 使用动态规划构建树形结构 + * + * @param items 节点列表项 + * @param parentId 父节点ID + * @param classifier 动态规划表分类函数 + * @param action 回溯动作 + * @param 节点ID的类型 + * @param 输入节点的类型 + * @return 构建好的树形结构列表 + */ + public static List build(List items, K parentId, Function classifier, BiConsumer>> action) { + // 构建动态规划表 (依据父ID分组) + Map> nodeTreeMaps = items.stream().collect(Collectors.groupingBy(classifier)); + // 回溯构建各级节点关系 + items.forEach(item -> action.accept(item, nodeTreeMaps)); + return nodeTreeMaps.get(parentId); + } + /** * 构建树形结构 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java index 746905fc7..de6ff5e84 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -9,7 +9,6 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.TreeBuildUtils; import org.dromara.common.satoken.utils.LoginHelper; @@ -27,11 +26,7 @@ import org.dromara.system.service.ISysMenuService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * 菜单 业务层处理 @@ -137,7 +132,17 @@ public class SysMenuServiceImpl implements ISysMenuService { .orderByAsc(SysMenu::getParentId) .orderByAsc(SysMenu::getOrderNum)); } - return getChildPerms(menus, Constants.TOP_PARENT_ID); + + return TreeBuildUtils.build(menus, Constants.TOP_PARENT_ID, SysMenu::getParentId, (menu, nodeTreeMaps) -> { + // 将当前节点的菜单ID用作父节点ID + Long menuParentId = menu.getMenuId(); + // 从动态规划表中取出子节点列表 + // 如果不存在子节点,则返回一个空的列表,确保数据在进行JSON序列化时该字段的类型和结构是正确的 + List childMenus = nodeTreeMaps.getOrDefault(menuParentId, Collections.emptyList()); + // 设置子节点 + // 如果存在根节点指向尾节点的情况,则会出现环形依赖。但在菜单表中基本不会出现这种情况... + menu.setChildren(childMenus); + }); } /** @@ -382,38 +387,4 @@ public class SysMenuServiceImpl implements ISysMenuService { return true; } - /** - * 根据父节点的ID获取所有子节点 - * - * @param list 分类表 - * @param parentId 传入的父节点ID - * @return String - */ - private List getChildPerms(List list, Long parentId) { - List returnList = new ArrayList<>(); - for (SysMenu t : list) { - // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 - if (t.getParentId().equals(parentId)) { - recursionFn(list, t); - returnList.add(t); - } - } - return returnList; - } - - /** - * 递归列表 - */ - private void recursionFn(List list, SysMenu t) { - // 得到子节点列表 - List childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId())); - t.setChildren(childList); - for (SysMenu tChild : childList) { - // 判断是否有子节点 - if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) { - recursionFn(list, tChild); - } - } - } - }