
四、若依获取用户角色和权限(GetInfo),获取动态路由(GenerateRouters)以及首页数据加载
登录后,可在控制台看到有如下图所示两个请求伴随着login请求一起发送出去了:那么下面来解析一下这两个请求。
登录后,可在控制台看到有如下图所示两个请求伴随着login请求一起发送出去了:
那么下面来解析一下这两个请求。
一、getInfo(获取用户信息)
获取当前用户的角色和权限信息,存储到Vuex中
- 首先能够看到getInfo的请求类型为GET,请求URL为http://localhost/dev-api/getInfo:
- 前端对应代码流程:
首先要知道,getInfo是在任意页面跳转时都会发送的,因而应在路由配置(全局路由跳转permission.js)中找它。
这里的router.beforeEach
是全局路由管理器。router的使用
由上图可以找到getInfo的入口,紧接着追踪这个方法,发现它封装在user.js中:
再对调用的getInfo()方法进行追踪,发现如下图示:
再进行追踪,进而找到如下代码,用于向后端发送请求: - 后端对应代码流程:
依据request请求中的url,可定位到下图处:
这里user、roles、permissions
在调用时都是同一套逻辑,看是否是管理员角色,若是则给与管理员权限;若不是,再去数据空中查找它对应的角色。(sys_user_role表中记录了user对应的role的多对多关系)
(这里SecurityUtils等是Spring Security的内容,其获取信息的方法是通过获取登陆token令牌中的信息)
然后将此用户的角色通过ajax返回到前端,而后将此角色信息在前端记录一下:
二、getRouters(获取路由信息)
根据权限拿取动态路由,根据动态路由生成左侧菜单。
- 能够看到getRouters的请求类型为GET,请求URL为http://localhost/dev-api/getRouters:
- 前端对应代码流程:
首先看一下路由配置permission.js中的写法:
对其进行追踪,发现又是生成了Promise对象进行异步操作,再执行一个名为getRouters()的方法
追踪getRouters()方法
依据依赖的路径,可以找到用于像后端发送请求的相关代码 - 后端相关代码流程
依据request请求中的url,可定位到后端下图处:
其中Long userId = SecurityUtils.getUserId();
用于获取用户role_id,List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
用于查找用户对应的menu。
可对menuService.selectMenuTreeByUserId(userId)
进行追踪,如下图所示:
若是admin,则给予全部;反之,则根据id权限给与对应menu目录。(将查到的所有记录折叠成多级菜单的形式)
getRouters()最后返回一个menus集合,其中可能有多级菜单。
多级菜单的层级关系设计:
1、从数据库层面:除menu_id外还有parent_id,这样就能够知晓其父子级关系。
2、从代码层面:如何进行的封装?
打个断点,可发现这里的menus是查询到的所有菜单,然后根据parentId:0来进行一级一级的组装。
对getChildPerms进行追踪:
从下图可知,list便是那24条记录,parentId便是0
然后通过for循环依次遍历,去找parentId为0的数据,建立一级菜单,然后再利用recursionFn(list, t);
来递归列表。也就是说if (t.getParentId() == parentId)
会被调用四次,来建立四个一级菜单;每次建立一级菜单时,都会使用递归来建立当前一级菜单下的各级菜单。
递归方法追溯:
这里的t是传送进来的一级菜单,其中getChildList(list,t)
方法用于从list的那24条记录中,找寻属于t这个一级菜单的子菜单,并返回一个List< SysMenu >得结果childList,t.setChildren(childList);
用于将筛选出来的childList菜单们作为t的子菜单,然后再利用for进行遍历,以子菜单中的菜单为父节点,再次构造下一级菜单。
三、获取角色权限和动态路由后的 首页数据加载
在permission.js中的router.beforeEach成功执行并完成router.addRoutes(accessRoutes) // 动态添加可访问路由表
后,前端页面执行登陆成功后的代码:
其中 this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
这一句跳转是跳到当前的根路径,因而在路由(router文件夹)的index.js中去寻找其定义的根路径:
跳转到此根路径下,加载Layout
这个component组件,我们追踪过去:
发现其是引用过来的,故继续追踪:
又因为import Layout from '@/layout'
未明确写出要引用layout文件夹中的哪一个资源,因而默认引用index.vue资源,因此如下图所示,在完成登录功能后,页面往index.vue中进行跳转:
index.vue如下图示:
(注意,下图所框内容,便介绍了为何在登陆后的首页能有那么多的components组件)
(所要跳转的页面如何显示到AppMain.vue上(children嵌套路由))
- 侧边栏的加载
在index.vue中使用的是<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
标签,封装了一个组件,组件位置如下图所示:
所引用的组件就是其中的index.vue,index.vue内把后台数据迭代出来的核心代码如下所示:
(这里的route等信息是后端获取动态路由后,使用commit存储到Vuex中的数据,且一般都是存放在客户端内存) - 点击侧边栏内容,中间内容发生变动,而侧边栏不变的原理?
以及刚加载到首页(默认页面)时,内容来自于何处?
由上图可知,这是登陆成功后,由router
路由文件夹下index.js文件,规定的默认跳转的根目录页面/layout/index.vue
,而后会通过redirect重定向到index页面,而要重定向的index页面是什么呢?一看它下方有children对index页面进行了映射,其最终的component组件是@/views/index
页面,即在加载到首页之后,会自动的向@/views/index
中去跳转。(可打开@/views/index,发现内容与首页显示的一致)
- 点击侧边栏内容,如用户管理后,页面的跳转与显示问题
首先看一下路由,当点击用户管理后,路由的变化如下所示:(默认组件都是该文件夹下的index)
其跳转原理是在数据库中,已经对各个功能的component赋好了值
(< sidebar-item > 的响应在src\layout\components\Sidebar\index.vue
的export default 中有设定,如自定义activeMenu()
内的方法)
更多推荐
所有评论(0)