一. 前言

本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动的情况下,无缝接入后台接口实现动态权限菜单的加载。

在进行接下来的工作前,我们需要对原生的vue-element-admin项目改造,移除mock连通后台接口,具体可参考我这篇文章 vue-element-admin移除mock接入后台搭建youlai-mall管理平台,如果在过程中有遇到问题,欢迎下方留言。

二. 前端调整

至于上文提到的对vue-element-admin几乎不做改动便可实现我们此篇文章的目的是不是我在扯,决定权给各位,我把对vue-element-admin项目改动的地方通过比对工具比对截图放上来。

先声明vue-element-admin此次改动的地方除了一个获取权限菜单的接口之外,剩余的改动全在 src/store/modules/permission.js 文件中。

看到了吗,可以说仅对vue-element-admin做两处改动,再加上对getRoutes调用后台接口返回的菜单数据的分析,就可以理解和实现动态权限菜单的加载了。

改动代码片段 + 注释说明

  1. import {list as getRoutes} from '@/api/admin/menu'
  2. import Layout from '@/layout'
  3. generateRoutes({commit}, roles) {
  4. return new Promise(resolve => {
  5. // 请求后台数据替换src/router/index.js的asyncRoutes异步路由
  6. getRoutes({mode: 3}).then(response => {
  7. // filterAsyncRoutes方法作权限过滤和数据转换,roles为登录用户角色ID集合,如:[1,2]
  8. let accessedRoutes = filterAsyncRoutes(response.data, roles)
  9. commit('SET_ROUTES', accessedRoutes)
  10. resolve(accessedRoutes)
  11. })
  12. })
  13. }
  14. // 递归权限过滤和数据转换
  15. export function filterAsyncRoutes(routes, roles) {
  16. const res = []
  17. routes.forEach(route => {
  18. const tmp = {...route}
  19. if (hasPermission(roles, tmp)) {
  20. const component = tmp.component
  21. if (route.component) {
  22. if (component == 'Layout') {
  23. tmp.component = Layout
  24. } else {
  25. // 接口组件字符串转换成组件对象
  26. tmp.component = (resolve) => require([`@/views/${component}`], resolve)
  27. }
  28. if (tmp.children) {
  29. tmp.children = filterAsyncRoutes(tmp.children, roles)
  30. }
  31. }
  32. res.push(tmp)
  33. }
  34. })
  35. return res
  36. }

三. 后端接口

1. 接口数据分析

接下来通过后台接口替换配置在src/router/index.js文件中asyncRoutes异步路由。

首先分析下异步路由的数据结构:

通过对上图异步路由的数据观察和了解,得出以下几点:

  1. path在子路由中前面没有反斜杠'/'
  2. 根菜单的alwaysShow为true
  3. component组件需通过import完成编译时导入,接口只能返回组件路径字符串,所以这里在接口请求完成后必须有一个组件路径字符串到组件对象的转换过程
  4. meta的roles属性对应的是有该路由访问权限角色唯一标识的集合,这里我使用的是角色ID

2. 接口实现

完成以上的数据分析,接下来就是接口的具体实现了,有关SQL和完整代码请点击 有来商城 youlai-mall 拉取即可,以下仅仅贴出关键代码和分析。

SysMenuMapper

获取菜单列表和对应访问权限的角色ID的集合

SysMenuServiceImpl

将菜单转换成路由,递归生成父子结构树

SysMenuController

REST对外提供接口

3. 接口测试

使用接口测试工具测试, http://localhost:9999/youlai-admin/menus?mode=3 ,这里通过网关方式访问,详情请知悉有来商城 youlai-mall项目。

完整返回数据,看看是不是很匹配asyncRoutes异步路由的数据格式了

  1. {
  2. "code": "00000",
  3. "data": [{
  4. "path": "/admin",
  5. "component": "Layout",
  6. "alwaysShow": true,
  7. "name": "系统管理",
  8. "meta": {
  9. "title": "系统管理",
  10. "icon": "documentation",
  11. "roles": [2, 1]
  12. },
  13. "children": [{
  14. "path": "user",
  15. "component": "admin/user",
  16. "alwaysShow": false,
  17. "name": "用户管理",
  18. "meta": {
  19. "title": "用户管理",
  20. "icon": "user",
  21. "roles": [1]
  22. }
  23. }, {
  24. "path": "role",
  25. "component": "admin/role",
  26. "alwaysShow": false,
  27. "name": "角色管理",
  28. "meta": {
  29. "title": "角色管理",
  30. "icon": "peoples",
  31. "roles": [2, 1]
  32. }
  33. }, {
  34. "path": "dept",
  35. "component": "admin/dept",
  36. "alwaysShow": false,
  37. "name": "部门管理",
  38. "meta": {
  39. "title": "部门管理",
  40. "icon": "tree",
  41. "roles": [1, 2]
  42. }
  43. }, {
  44. "path": "menu",
  45. "component": "admin/menu",
  46. "alwaysShow": false,
  47. "name": "菜单管理",
  48. "meta": {
  49. "title": "菜单管理",
  50. "icon": "tree-table",
  51. "roles": [1, 2]
  52. }
  53. }, {
  54. "path": "dict",
  55. "component": "admin/dict",
  56. "alwaysShow": false,
  57. "name": "字典管理",
  58. "meta": {
  59. "title": "字典管理",
  60. "icon": "education",
  61. "roles": [1, 2]
  62. }
  63. }]
  64. }],
  65. "msg": "一切ok"
  66. }

最后要做的就是将组件(component)路径字符串转换成组件对象即可,再次贴出在上文permission.js改造的代码:

  1. if (component == 'Layout') {
  2. tmp.component = Layout
  3. } else {
  4. // 接口组件字符串转换成组件对象
  5. tmp.component = (resolve) => require([`@/views/${component}`], resolve)
  6. }

有一点需要注意的是上面组件动态导入不能使用import,如下:

  1. tmp.component = () => import(`@/views/${component}`)

不然会报以下错误

  1. Error: Cannot find module '@/views/***'

原因是webpack不支持import导入了,但是之前确实是可以的,所以有些让人想不通,这里使用require动态导入组件即可。

4. 菜单权限测试

参看当前用户拥有的角色ID为2

用户管理要求只有角色ID为1才能有其访问权限

测试下用户登录控制台能否看到“用户管理”菜单

怎么样,只拥有角色ID为2的角色是看不到需要角色ID为1才能访问的“用户管理”菜单的,也就证明了我们成功通过接入后台接口实现了权限菜单的动态加载的目的。

四. 结语

其实有个问题值得去思考下的。为什么我们在从后台获取全部菜单列表的时候需要关联查询出有对应访问权限的角色ID的集合,而不是说动态传入当前登录用户的信息去查询该用户拥有的菜单集合呢?这其实是两种实现方式,区别在于第一种每个用户都要获取全部菜单数据,而第二种方式针对每个用户加载其拥有权限的菜单数据。单看的话第二种方式肯定优于第一种,但这里我们选用的是第一种加载全部菜单数据。如果你结合缓存去看的话自然就想的通了,所有用户共享缓存的同一份菜单数据,还是说缓存针对每个用户存放一份菜单缓存又或者用户每次都去请求数据库。后面计划把菜单数据存放到缓存Redis中然后做一个分析比较。

附完整代码:

有来商城后端:youlai-mall

有来商城前端:youlai-mall-admin-web

写了这么多其实也是想给自己的项目打个广告,更希望对大家有所帮助,对于技术人来说少走弯路真的很重要,喜欢的朋友给个star,对我来说这份帮助更是自己继续下去的动力,所以谢谢了。有啥问题下方留言,或直接联系我(微信号:haoxianrui)。

vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单的更多相关文章

  1. Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  2. Vue + Element UI 实现权限管理系统(动态加载菜单)

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  3. 【技术贴】第二篇 :解决使用maven jetty启动后无法加载修改过后的静态资源

    之前写过第一篇:[技术贴]解决使用maven jetty启动后无法加载修改过后的静态资源 一直用着挺舒服的,直到今天,出现了又不能修改静态js,jsp等资源的现象.很是苦闷. 经过调错处理之后,发现是 ...

  4. vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录

    一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...

  5. 新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚

    新书上线 大家好,笔者的新书<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>已上线,此书内容充实.材质优良,乃家中必备垫桌脚 ...

  6. Android中插件开发篇之----动态加载Activity(免安装运行程序)

    一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析 ...

  7. Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  8. 【Android编程实战】源码级免杀_Dex动态加载技术_Metasploit安卓载荷傀儡机代码复现

    /文章作者:MG193.7 CNBLOG博客ID:ALDYS4 QQ:3496925334/ 在读者阅读本文章前,建议先阅读笔者之前写的一篇对安卓载荷的分析文章 [逆向&编程实战]Metasp ...

  9. 中文分词实战——基于jieba动态加载字典和调整词频的电子病历分词

    分词是自然语言处理中最基本的一个任务,这篇小文章不介绍相关的理论,而是介绍一个电子病历分词的小实践. 开源的分词工具中,我用过的有jieba.hnlp和stanfordnlp,感觉jieba无论安装和 ...

随机推荐

  1. js利用canvas绘制爱心

    js代码如下: var cav = document.getElementById("a").getContext("2d"); function draw(x ...

  2. mysql基础测试题

    mysql基础测试题:https://www.cnblogs.com/wupeiqi/articles/5729934.html 如何创建表? 就这样类推?如何提取我们想要的元素呢? 综合提取呢?

  3. 数据 恢复----判断Raid盘序及校验方向

    重组Raid(如何判断校验方向及盘序) 1. 常规左异结构[backward parity(反向奇偶校验--(静态))] 校验块:校验块从最后一块物理盘开始写起,然后依次往前面的盘中写入,当写到第一块 ...

  4. Python定时任务轻量解决方案---Schedule

    写后端的同学们可能都知道,工作中可能需要周期性执行一些任务,俗称定时任务.Linux环境下,可以借助于系统自带的crontab完成定时任务.但是很多时候,开发的同学们可能并没有权限去操作crontab ...

  5. JavaScript设计模式之策略模式【组合委托】

    前言:语言只是工具,思想才是核心 今天要总结的是 策略模式 策略在开发中的应用非常广泛,所以也是非常常见且使用的设计模式. 在实际开发中,往往在实现一个功能时,有多种解决方案可行. 常见场景: 解压: ...

  6. Wireshark中遇到的epoch time

    使用Wireshark分析DNS时遇到的Epoch time 首先看一下Wireshark分析DNS的情况(如下图): 这是协议树的第一项,第一项中的第五行出现了Epoch Time,查阅资料之后才知 ...

  7. Hyperledger Fabric【区块链学习一】

    Hyperledger Fabric 学习 什么是区块链 什么是区块链在我们没有接触的时候,只知道它是一个去中心化的存储方式.当我们发生交易,或者动作的时候我们会将记录通知给所有参与者共同维护,达到去 ...

  8. A distributional code for value in dopamine-based reinforcement learning

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Nature 2020 汇报PPT: 链接:https://pan.baidu.com/s/1RWx6miX6iZUNgNfV9B69FQ ...

  9. Protocol buffers--python 实践 简介以及安装与使用

    简介: Protocol Buffers以下简称pb,是google开发的一个可以序列化 反序列化object的数据交换格式,类似于xml,但是比xml 更轻,更快,更简单.而且以上的重点突出一个跨平 ...

  10. 从 BIO、NIO 聊到 Netty,最后还要实现个 RPC 框架!

    大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 觉得不错的话,欢迎 star!ღ( ´・ᴗ・` )比心 Netty 从入门到实战系列文章地址:https://github.com/Snai ...