소스 검색

增加 get-routers 接口的相关方法,未完全完成

YunaiV 4 년 전
부모
커밋
cf93019ce1

+ 1 - 1
ruoyi-ui/src/api/login.js

@@ -18,7 +18,7 @@ export function login(username, password, code, uuid) {
 // 获取用户详细信息
 export function getInfo() {
   return request({
-    url: '/getInfo',
+    url: '/get-info',
     method: 'get'
   })
 }

+ 2 - 2
ruoyi-ui/src/api/menu.js

@@ -3,7 +3,7 @@ import request from '@/utils/request'
 // 获取路由
 export const getRouters = () => {
   return request({
-    url: '/getRouters',
+    url: '/get-routers',
     method: 'get'
   })
-}
+}

+ 4 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysAuthController.http

@@ -13,6 +13,10 @@ Content-Type: application/json
 GET {{baseUrl}}/get-info
 Authorization: Bearer {{token}}
 
+### 请求 /get-routers 接口 => 成功
+GET {{baseUrl}}/get-routers
+Authorization: Bearer {{token}}
+
 ### 请求 /druid/xxx 接口 => 失败 TODO 临时测试
 GET http://127.0.0.1:8080/druid/123
 Authorization: Bearer {{token}}

+ 10 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysAuthController.java

@@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.controller.auth;
 
 import cn.iocoder.dashboard.common.pojo.CommonResult;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetInfoRespVO;
+import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetRouterRespVO;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginReqVO;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginRespVO;
 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
@@ -12,6 +13,8 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 
+import java.util.List;
+
 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId;
 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds;
@@ -39,4 +42,11 @@ public class SysAuthController {
         return success(respVO);
     }
 
+    @ApiOperation("获得菜单 Vue 路由")
+    @GetMapping("get-routers")
+    public CommonResult<List<SysAuthGetRouterRespVO>> getRouters() {
+        List<SysAuthGetRouterRespVO> respVOList = authService.getRouters(getLoginUserId(), getLoginUserRoleIds());
+        return success(respVOList);
+    }
+
 }

+ 84 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/SysAuthGetRouterRespVO.java

@@ -0,0 +1,84 @@
+package cn.iocoder.dashboard.modules.system.controller.auth.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 路由配置信息
+ *
+ * @author ruoyi
+ */
+@Data
+public class SysAuthGetRouterRespVO {
+
+    /**
+     * 菜单编号
+     */
+    private Long menuId;
+    /**
+     * 父菜单编号
+     */
+    private Long parentId;
+
+    /**
+     * 路由名字
+     */
+    private String name;
+
+    /**
+     * 路由地址
+     */
+    private String path;
+
+    /**
+     * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
+     */
+    private boolean hidden;
+
+    /**
+     * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+     */
+    private String redirect;
+
+    /**
+     * 组件地址
+     */
+    private String component;
+
+    /**
+     * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+     */
+    private Boolean alwaysShow;
+
+    /**
+     * 其他元素
+     */
+    private MetaVO meta;
+
+    /**
+     * 子路由
+     */
+    private List<SysAuthGetRouterRespVO> children;
+
+    @Data
+    public static class MetaVO {
+
+        /**
+         * 设置该路由在侧边栏和面包屑中展示的名字
+         */
+        private String title;
+
+        /**
+         * 设置该路由的图标,对应路径src/assets/icons/svg
+         */
+        private String icon;
+
+        /**
+         * 设置为true,则不会被 <keep-alive>缓存
+         */
+        private boolean noCache;
+
+    }
+
+}

+ 3 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysAuthConvert.java

@@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.convert.auth;
 
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetInfoRespVO;
+import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetRouterRespVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
@@ -27,4 +28,6 @@ public interface SysAuthConvert {
         return respVO;
     }
 
+    SysAuthGetRouterRespVO convertTreeNode(SysMenuDO menu);
+
 }

+ 0 - 17
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/permission/SysMenuDO.java

@@ -1,7 +1,6 @@
 package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission;
 
 import cn.iocoder.dashboard.framework.mybatis.core.BaseDO;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
@@ -9,8 +8,6 @@ import lombok.EqualsAndHashCode;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * 菜单权限表
@@ -95,18 +92,4 @@ public class SysMenuDO extends BaseDO {
      */
     private String icon;
 
-    // TODO 芋艿:非存储字段,需要提出
-
-    /**
-     * 父菜单名称
-     */
-    @TableField(exist = false)
-    private String parentName;
-
-    /**
-     * 子菜单
-     */
-    @TableField(exist = false)
-    private List<SysMenuDO> children = new ArrayList<SysMenuDO>();
-
 }

+ 20 - 0
src/main/java/cn/iocoder/dashboard/modules/system/enums/permission/MenuIdEnum.java

@@ -0,0 +1,20 @@
+package cn.iocoder.dashboard.modules.system.enums.permission;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Menu 编号枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum MenuIdEnum {
+
+    /**
+     * 根节点
+     */
+    ROOT(0L);
+
+    private final Long id;
+
+}

+ 14 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthService.java

@@ -2,7 +2,9 @@ package cn.iocoder.dashboard.modules.system.service.auth;
 
 import cn.iocoder.dashboard.framework.security.core.service.SecurityFrameworkService;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetInfoRespVO;
+import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetRouterRespVO;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -28,4 +30,16 @@ public interface SysAuthService extends SecurityFrameworkService {
      */
     SysAuthGetInfoRespVO getInfo(Long userId, Set<Long> roleIds);
 
+    /**
+     * 获得用户的菜单 Vue 路由
+     *
+     * 这里传输 roleIds 参数的原因,是该参数是从 LoginUser 缓存中获取到的,而我们校验权限时也是从 LoginUser 缓存中获取 roleIds
+     * 通过这样的方式,保持一致
+     *
+     * @param userId 用户编号
+     * @param roleIds 用户拥有的角色编号数组
+     * @return 菜单 Vue 路由
+     */
+    List<SysAuthGetRouterRespVO> getRouters(Long userId, Set<Long> roleIds);
+
 }

+ 38 - 2
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java

@@ -5,12 +5,14 @@ import cn.hutool.core.util.StrUtil;
 import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetInfoRespVO;
+import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthGetRouterRespVO;
+import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO;
-import cn.iocoder.dashboard.modules.system.enums.user.UserStatus;
-import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
 import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
+import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum;
+import cn.iocoder.dashboard.modules.system.enums.user.UserStatus;
 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
 import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService;
 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
@@ -234,4 +236,38 @@ public class SysAuthServiceImpl implements SysAuthService {
         return SysAuthConvert.INSTANCE.convert(user, roleList, menuList);
     }
 
+    @Override
+    public List<SysAuthGetRouterRespVO> getRouters(Long userId, Set<Long> roleIds) {
+        // TODO 芋艿:去除 F 的类型,去除 禁用 的
+        List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(roleIds);
+        // 转换成 Tree 结构返回
+        return buildRouterTree(menuList);
+    }
+
+    private static List<SysAuthGetRouterRespVO> buildRouterTree(List<SysMenuDO> menuList) {
+        // 排序,保证菜单的有序性
+        menuList = new ArrayList<>(menuList); // 使用 ArrayList 套一下,因为 menuList 是不可修改的 List
+        menuList.sort(Comparator.comparing(SysMenuDO::getOrderNum));
+        // 构建菜单树
+        // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
+        Map<Long, SysAuthGetRouterRespVO> treeNodeMap = new LinkedHashMap<>();
+        menuList.forEach(menu -> treeNodeMap.put(menu.getMenuId(), SysAuthConvert.INSTANCE.convertTreeNode(menu)));
+        // 处理父子关系
+        treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach((childNode) -> {
+            // 获得父节点
+            SysAuthGetRouterRespVO parentNode = treeNodeMap.get(childNode.getParentId());
+            if (parentNode == null) {
+                log.error("[buildRouterTree][resource({}) 找不到父资源({})]", childNode.getMenuId(), childNode.getParentId());
+                return;
+            }
+            // 将自己添加到父节点中
+            if (parentNode.getChildren() == null) {
+                parentNode.setChildren(new ArrayList<>());
+            }
+            parentNode.getChildren().add(childNode);
+        });
+        // 获得到所有的根节点
+        return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId()));
+    }
+
 }

+ 5 - 0
src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 
 import java.util.*;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -17,6 +18,10 @@ public class CollectionUtils {
         return new HashSet<>(Arrays.asList(objs));
     }
 
+    public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
+        return from.stream().filter(predicate).collect(Collectors.toList());
+    }
+
     public static <T, U> List<U> convertList(List<T> from, Function<T, U> func) {
         return from.stream().map(func).collect(Collectors.toList());
     }