Procházet zdrojové kódy

Update 优化 添加菜单路由地址和名称的校验规则

Yue před 1 týdnem
rodič
revize
bec4face1a

+ 4 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-system/src/main/java/com/vber/system/controller/system/SysMenuController.java

@@ -157,6 +157,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));
     }
@@ -176,6 +178,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));
     }

+ 9 - 7
SERVER/VberAdminPlusV3/vber-modules/vber-system/src/main/java/com/vber/system/domain/SysMenu.java

@@ -126,8 +126,8 @@ public class SysMenu extends BaseEntity {
      * 内链域名特殊字符替换
      */
     public static String innerLinkReplaceEach(String path) {
-        return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"},
-                new String[]{"", "", "", "/", "/"});
+        return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":" },
+                new String[] { "", "", "", "/", "/" });
     }
 
     /**
@@ -148,11 +148,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;
         }
@@ -170,7 +170,8 @@ 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;
@@ -182,7 +183,8 @@ 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);
     }
 
     /**
@@ -196,6 +198,6 @@ 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);
     }
 }

+ 8 - 2
SERVER/VberAdminPlusV3/vber-modules/vber-system/src/main/java/com/vber/system/service/ISysMenuService.java

@@ -24,7 +24,6 @@ public interface ISysMenuService {
      */
     List<SysMenuVo> selectMenuList(Long userId);
 
-
     /**
      * 根据用户查询系统菜单列表
      *
@@ -34,7 +33,6 @@ public interface ISysMenuService {
      */
     List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId);
 
-
     /**
      * 根据权限名称查询按钮列表
      *
@@ -178,4 +176,12 @@ public interface ISysMenuService {
      */
     boolean checkMenuNameUnique(SysMenuBo menu);
 
+    /**
+     * 校验路由组合是否唯一
+     *
+     * @param menu 菜单信息
+     * @return 结果
+     */
+    boolean checkRouteConfigUnique(SysMenuBo menu);
+
 }

+ 46 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-system/src/main/java/com/vber/system/service/impl/SysMenuServiceImpl.java

@@ -29,6 +29,8 @@ import com.vber.system.mapper.SysRoleMenuMapper;
 import com.vber.system.mapper.SysTenantPackageMapper;
 import com.vber.system.service.ISysMenuService;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -41,6 +43,7 @@ import java.util.*;
  */
 @RequiredArgsConstructor
 @Service
+@Slf4j
 public class SysMenuServiceImpl implements ISysMenuService {
 
     private final SysMenuMapper baseMapper;
@@ -384,6 +387,49 @@ public class SysMenuServiceImpl implements ISysMenuService {
         return !exist;
     }
 
+    /**
+     * 校验路由名称是否唯一
+     *
+     * @param menuBo 菜单信息
+     * @return 结果
+     */
+    @Override
+    public boolean checkRouteConfigUnique(SysMenuBo menuBo) {
+        SysMenu menu = MapstructUtils.convert(menuBo, SysMenu.class);
+        if (SystemConstants.TYPE_BUTTON.equals(menu.getMenuType())) {
+            return true;
+        }
+        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<SysMenu> sysMenuList = baseMapper.selectList(
+                new LambdaQueryWrapper<SysMenu>()
+                        .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU)
+                        .and(w -> w.eq(SysMenu::getPath, path).or().eq(SysMenu::getPath, routeName)));
+        for (SysMenu sysMenu : sysMenuList) {
+            if (!sysMenu.getMenuId().equals(menuId)) {
+                Long dbParentId = sysMenu.getParentId();
+                String dbPath = sysMenu.getPath();
+                String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName();
+                if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.equals(dbParentId)) {
+                    log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName());
+                    return false;
+                } else if (StringUtils.equalsAnyIgnoreCase(path, dbPath)
+                        && Constants.TOP_PARENT_ID.equals(parentId)
+                        && Constants.TOP_PARENT_ID.equals(dbParentId)) {
+                    log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName());
+                    return false;
+                } else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName)
+                        && sysMenu.getMenuType().equals(menu.getMenuType())) {
+                    log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     /**
      * 根据父节点的ID获取所有子节点
      *