vue-element-admin改为从后台拿动态路由(菜单)- 上
改为从后台拿动态路由,大概如下步骤:
1、后台增加接口,返回动态路由数据
2、前端增加请求动态路由接口请求
3、修改 src/route/index.js 去掉原有的动态路由,增加组件名和组件对象映射 map
4、修改 src/store/modules/permission.js 修改当前 权限判断处理方法 generateRoutes
一、后台增加接口
1、后台随便添加一个 Controller 随便加一个接口,添加如下代码。正常 str 内容应该从数据库中查询得到,为了避免信息量过多这里直接写一个 json 返回
@RequestMapping(value = "/getPermission", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody @ApiOperation(value = "得到当前登录用户所有的权限(Route 菜单 + Permission 按钮)", notes = "得到当前登录用户所有的权限(Route 菜单 + Permission 按钮)") public Response<User> getPermission() throws Exception { String str = "[\n" + " {\n" + " component: 'layout',\n" + " path: '/interface_test',\n" + " name: 'interface_test',\n" + " meta: { title: '接口测试', icon: 'el-icon-data-line' },\n" + " redirect: '/interface_test/test_case',\n" + " alwaysShow: true,\n" + " children: [\n" + " {\n" + " path: 'public_step',\n" + " name: 'public_step',\n" + " meta: { title: '公共步骤' },\n" + " component: 'public_step'\n" + " }\n" + " ]\n" + " }]"; JSONArray jsonObject = JSONArray.parseArray(str); Map<String, Object> retMap = new HashMap<>(); retMap.put("routes", jsonObject); Response response = Response.success(retMap); return response; }
2、使用 postman 等工具请求接口,返回如下。其中 code、data 可能跟你的包装有所不同,关键就是返回 routes 下的内容
{ "code": 0, "msg": "请求成功", "data": { "routes": [ { "redirect": "/interface_test/test_case", "path": "/interface_test", "component": "layout", "children": [ { "path": "public_step", "component": "public_step", "meta": { "title": "公共步骤" }, "name": "public_step" } ], "meta": { "icon": "el-icon-data-line", "title": "接口测试" }, "name": "interface_test", "alwaysShow": true } ] } }
二、前端增加接口请求
1、前端打开 src/api/role.js 文件,插入刚增加的接口请求,代码如下
export function getPermission() { return request({ url: '/manage/role/getPermission', method: 'get' }) }
三、去掉原有的动态路由,增加组件名和组件对象映射 map
我这里后续的代码是,将从后台请求回来的路由和 route/index.js 中的动态路由组合后一起做为当前路由返回,所以这里要删除之前增加的动态路由,如果你是替换那就不用管。
1、打开 src/route/index.js 文件
去掉之前引入的 router 组件
从 asyncRoutes 动态路由中删除之前的定义,只保留 404。如果你是替换 asyncRoutes 动态路由,那一定要在最后添加一个 404,要不然输入一个不存在的 url 后不会显示 404,而是一个白屏。
2、组件名和组件对象映射 map
由于后台请求回来的数据不是组件对象而是组件名称,所以要将名称转为 组件对象,这里定义的就是名称和对象的对应关系。代码如下
// 组件名 和 组件对象 映射表,用于后续根据后台传过来的 组件名 替换成 组件对象 使用 export const componentMap = { 'layout': require('@/layout').default, 'test_case': () => import('@/views/functional_test/test_case_manage/test_case').then(m => m.default), 'public_step': () => import('@/views/functional_test/test_data_manage/public_step').then(m => m.default) }
注:由于是通过组件名称对应,所以后台添加的组件名,一定要跟这里定义个名称一样。
四、权限判断处理方法 generateRoutes
1、打开 src/store/modules/permission.js 修改如下
增加 api 引用
修改 generateRoutes 权限判断
代码如下
const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { // 从后台请求到的路由 getPermission().then(response => { // 整理后台返回的路由 let accessedRoutes = response.data.routes.filter(item => { return pruningRoutes(item) }) accessedRoutes = accessedRoutes.concat(asyncRoutes) // 合并异步路由(例如将404页面合并入可访问路由) accessedRoutes = filterAsyncRoutes(accessedRoutes, roles) // 通过递归根据角色过滤异步路由 commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) }) }) } } /** * 整理后台返回的路由 * @param route 路由 * @returns {{children}|*} */ function pruningRoutes(route) { // 路由中有 component 属性,将组件字符串转换为组件对象 if (route.component && typeof route.component === 'string') { route.component = componentMap[route.component] } // 路由中有 props 属性,将 props 字符串转换为 props 对象 if (route.props && typeof route.props === 'string') { route.props = JSON.parse(route.props) } // 路由中有 children,循环递归处理 children if (route.children && route.children.length > 0) { for (let i = 0; i < route.children.length; i++) { pruningRoutes(route.children[i]) } return route } else { delete route.children } }
代码讲解
改动如下:
五、重启后效果如下
六、后续 - 数据库设计
这次只定义了 role、role_route、route、route_meta 表,后续的用户角色对应表、资源路由对应表等还没创建。表结构如下
CREATE TABLE `role` ( `name` varchar(50) NOT NULL COMMENT '角色名称', `desc` varchar(50) NOT NULL COMMENT '角色描述', `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='角色信息表'; CREATE TABLE `role_route` ( `role_id` bigint(20) NOT NULL COMMENT '角色 id', `route_id` bigint(20) NOT NULL COMMENT '路由信息', `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=74 DEFAULT CHARSET=utf8 COMMENT='角色对应路由信息表'; CREATE TABLE `route` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', `path` varchar(255) NOT NULL COMMENT '路由匹配的路径,注意根节点前要加/', `name` varchar(255) NOT NULL COMMENT '路由的名称', `component` varchar(255) NOT NULL COMMENT '对应加载的组件', `redirect` varchar(255) DEFAULT NULL COMMENT '重定向的路由路径', `hidden` bit(1) NOT NULL COMMENT '在菜单中是否隐藏。true:隐藏,默认 false', `always_show` bit(1) NOT NULL COMMENT '是否始终显示根菜单。true:无论有没有子节点都显示,false:必须有子节点才显示', `props` varchar(255) DEFAULT NULL COMMENT '传递数据的 props 属性', `route_meta_id` bigint(20) NOT NULL COMMENT '元信息 id', `parent_id` bigint(20) NOT NULL COMMENT '父分类的 id', `sort` int(11) NOT NULL COMMENT '排序', `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8 COMMENT='路由信息表'; CREATE TABLE `route_meta` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', `title` varchar(255) NOT NULL COMMENT '页面标题', `icon` varchar(255) DEFAULT NULL COMMENT '图标', `no_cache` bit(1) NOT NULL COMMENT '是否禁用缓存页面。true:禁止缓存页面(默认值为false)', `affix` bit(1) NOT NULL COMMENT '标签视图中是否可关闭。true:不允许关闭(默认 false)', `breadcrumb` bit(1) NOT NULL COMMENT '是否显示面包屑。false:不在面包屑中显示(默认值为 true)', `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8 COMMENT='路由 Meta 信息表';