From 8a87c7aa4e16e19ad42b6d1160a215266dba762e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 9 Jan 2026 13:19:21 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=8F=9C=E5=8D=95=E8=B7=AF=E7=94=B1=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E5=92=8C=E5=90=8D=E7=A7=B0=E7=9A=84=E6=A0=A1=E9=AA=8C=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/system/SysMenuController.java | 4 ++ .../org/dromara/system/domain/SysMenu.java | 10 ++-- .../system/service/ISysMenuService.java | 9 ++++ .../service/impl/SysMenuServiceImpl.java | 47 ++++++++++++++++++- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java index d1b5b9bd5..9d95880e8 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java @@ -137,6 +137,8 @@ public class SysMenuController extends BaseController { return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (!menuService.checkRouteConfigUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); } return toAjax(menuService.insertMenu(menu)); } @@ -156,6 +158,8 @@ public class SysMenuController extends BaseController { return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } else if (menu.getMenuId().equals(menu.getParentId())) { return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } else if (!menuService.checkRouteConfigUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); } return toAjax(menuService.updateMenu(menu)); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java index 2df55962b..5fe0de585 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java @@ -130,11 +130,11 @@ public class SysMenu extends BaseEntity { public String getRouterPath() { String routerPath = this.path; // 内链打开外网方式 - if (getParentId() != 0L && isInnerLink()) { + if (!Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) { routerPath = innerLinkReplaceEach(routerPath); } // 非外链并且是一级目录(类型为目录) - if (0L == getParentId() && SystemConstants.TYPE_DIR.equals(getMenuType()) + if (Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(getMenuType()) && SystemConstants.NO_FRAME.equals(getIsFrame())) { routerPath = "/" + this.path; } @@ -152,7 +152,7 @@ public class SysMenu extends BaseEntity { String component = SystemConstants.LAYOUT; if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) { component = this.component; - } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) { + } else if (StringUtils.isEmpty(this.component) && !Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) { component = SystemConstants.INNER_LINK; } else if (StringUtils.isEmpty(this.component) && isParentView()) { component = SystemConstants.PARENT_VIEW; @@ -164,7 +164,7 @@ public class SysMenu extends BaseEntity { * 是否为菜单内部跳转 */ public boolean isMenuFrame() { - return getParentId() == 0L && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME); + return Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME); } /** @@ -178,7 +178,7 @@ public class SysMenu extends BaseEntity { * 是否为parent_view组件 */ public boolean isParentView() { - return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType); + return !Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(menuType); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java index f972691be..8888c3c39 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java @@ -160,4 +160,13 @@ public interface ISysMenuService { * @return 结果 */ boolean checkMenuNameUnique(SysMenuBo menu); + + /** + * 校验路由组合是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkRouteConfigUnique(SysMenuBo menu); + } 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 bbba6a01e..b048d2a81 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 @@ -6,6 +6,7 @@ import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; +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; @@ -29,13 +30,17 @@ import org.dromara.system.service.ISysMenuService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; /** * 菜单 业务层处理 * * @author Lion Li */ +@Slf4j @RequiredArgsConstructor @Service public class SysMenuServiceImpl implements ISysMenuService { @@ -353,6 +358,46 @@ public class SysMenuServiceImpl implements ISysMenuService { return !exist; } + /** + * 校验路由名称是否唯一 + * + * @param menuBo 菜单信息 + * @return 结果 + */ + @Override + public boolean checkRouteConfigUnique(SysMenuBo menuBo) { + SysMenu menu = MapstructUtils.convert(menuBo, SysMenu.class); + long menuId = ObjectUtil.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); + Long parentId = menu.getParentId(); + String path = menu.getPath(); + String routeName = StringUtils.isEmpty(menu.getRouteName()) ? path : menu.getRouteName(); + List sysMenuList = baseMapper.selectList( + new LambdaQueryWrapper() + .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .and(w -> + w.eq(SysMenu::getPath, path) + .or().eq(SysMenu::getRouteName, path) + .or().eq(SysMenu::getRouteName, routeName))); + for (SysMenu sysMenu : sysMenuList) { + if (sysMenu.getMenuId() != menuId) { + Long dbParentId = sysMenu.getParentId(); + String dbPath = sysMenu.getPath(); + String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName(); + if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == dbParentId.longValue()) { + log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName()); + return false; + } else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == Constants.TOP_PARENT_ID) { + log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName()); + return false; + } else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName)) { + log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName()); + return false; + } + } + } + return true; + } + /** * 根据父节点的ID获取所有子节点 *