diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java index 61e3bcb20..620d2cbd4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java @@ -97,6 +97,10 @@ public class SysMenuController extends BaseController { return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } + else if (!menuService.checkRouteConfigUnique(menu)) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } menu.setCreateBy(SecurityUtils.getUsername()); return toAjax(menuService.insertMenu(menu)); } @@ -121,6 +125,10 @@ public class SysMenuController extends BaseController { return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); } + else if (!menuService.checkRouteConfigUnique(menu)) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } menu.setUpdateBy(SecurityUtils.getUsername()); return toAjax(menuService.updateMenu(menu)); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java index 532aaa8d9..de625f38c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java @@ -122,4 +122,13 @@ public interface SysMenuMapper * @return 结果 */ public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId); + + /** + * 根据路由路径或名称查询菜单信息(用于唯一性校验) + * + * @param path 路由地址 + * @param routeName 路由名称 + * @return 匹配的菜单列表 + */ + public List selectMenusByPathOrRouteName(@Param("path") String path, @Param("routeName") String routeName); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java index 1061849c0..73938304c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java @@ -141,4 +141,12 @@ public interface ISysMenuService * @return 结果 */ public boolean checkMenuNameUnique(SysMenu menu); + + /** + * 校验路由组合是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean checkRouteConfigUnique(SysMenu menu); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java index 075ee538b..464395777 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -8,6 +8,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.Constants; @@ -32,8 +34,12 @@ import com.ruoyi.system.service.ISysMenuService; @Service public class SysMenuServiceImpl implements ISysMenuService { + private static final Logger log = LoggerFactory.getLogger(SysMenuServiceImpl.class); + public static final String PREMISSION_STRING = "perms[\"{0}\"]"; + public static final Long MENU_ROOT_ID = 0L; + @Autowired private SysMenuMapper menuMapper; @@ -138,7 +144,7 @@ public class SysMenuServiceImpl implements ISysMenuService { menus = menuMapper.selectMenuTreeByUserId(userId); } - return getChildPerms(menus, 0); + return getChildPerms(menus, MENU_ROOT_ID); } /** @@ -193,7 +199,7 @@ public class SysMenuServiceImpl implements ISysMenuService childrenList.add(children); router.setChildren(childrenList); } - else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) + else if (menu.getParentId().intValue() == MENU_ROOT_ID && isInnerLink(menu)) { router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setPath("/"); @@ -345,6 +351,47 @@ public class SysMenuServiceImpl implements ISysMenuService return UserConstants.UNIQUE; } + /** + * 校验路由名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkRouteConfigUnique(SysMenu menu) + { + Long menuId = StringUtils.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 = menuMapper.selectMenusByPathOrRouteName(path, routeName); + for (SysMenu sysMenu : sysMenuList) + { + if (sysMenu.getMenuId().longValue() != menuId.longValue()) + { + 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 UserConstants.NOT_UNIQUE; + } + else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == MENU_ROOT_ID) + { + log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName()); + return UserConstants.NOT_UNIQUE; + } + else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName)) + { + log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName()); + return UserConstants.NOT_UNIQUE; + } + } + } + return UserConstants.UNIQUE; + } + /** * 获取路由名称 * @@ -384,12 +431,12 @@ public class SysMenuServiceImpl implements ISysMenuService { String routerPath = menu.getPath(); // 内链打开外网方式 - if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) + if (menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu)) { routerPath = innerLinkReplaceEach(routerPath); } // 非外链并且是一级目录(类型为目录) - if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) + if (MENU_ROOT_ID == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) && UserConstants.NO_FRAME.equals(menu.getIsFrame())) { routerPath = "/" + menu.getPath(); @@ -415,7 +462,7 @@ public class SysMenuServiceImpl implements ISysMenuService { component = menu.getComponent(); } - else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) + else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu)) { component = UserConstants.INNER_LINK; } @@ -434,30 +481,30 @@ public class SysMenuServiceImpl implements ISysMenuService */ public boolean isMenuFrame(SysMenu menu) { - return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) + return menu.getParentId().intValue() == MENU_ROOT_ID && UserConstants.TYPE_MENU.equals(menu.getMenuType()) && menu.getIsFrame().equals(UserConstants.NO_FRAME); } /** - * 是否为内链组件 + * 是否为parent_view组件 * * @param menu 菜单信息 * @return 结果 */ - public boolean isInnerLink(SysMenu menu) + public boolean isParentView(SysMenu menu) { - return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); + return menu.getParentId().intValue() != MENU_ROOT_ID && UserConstants.TYPE_DIR.equals(menu.getMenuType()); } /** - * 是否为parent_view组件 + * 是否为内链组件 * * @param menu 菜单信息 * @return 结果 */ - public boolean isParentView(SysMenu menu) + public boolean isInnerLink(SysMenu menu) { - return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()); + return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); } /** @@ -467,7 +514,7 @@ public class SysMenuServiceImpl implements ISysMenuService * @param parentId 传入的父节点ID * @return String */ - public List getChildPerms(List list, int parentId) + public List getChildPerms(List list, long parentId) { List returnList = new ArrayList(); for (Iterator iterator = list.iterator(); iterator.hasNext();) diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml index e6be3aefd..bc80401bf 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -130,7 +130,12 @@ + +