实现思路:数据库中有菜单表,角色表,用户表,角色和用户映射的表,菜单和角色映射的表五个表,springboot利用jpa操作数据库,提供vue前端获取这些表中的数据,vue前端利用懒加载,对当前登录的用户的角色所拥有的菜单栏进行显示和渲染。
本文参考Evan-Nightly写的"Vue + Spring Boot 项目实战"系列的文章,他那个系列教程写得很棒,我吹爆。后期进阶的部分详细步骤这位老哥没放出来,我这里稍微总结一下,方便基础不好的老哥,也算是给自己查漏补缺。
具体实现:
首先来看菜单表的内容:
这里跳过springboot的操作直接看前端的部分会方便理解一点,我们用vuex存储菜单表的数据,在store/index.js里面定义菜单表的变量,以及该变量的set方法,如下图所示。
这样前端姑且就有了存储每个用户对应角色的菜单数据变量了。接下来看看这个变量从哪被赋值以及具体的数据结构。
前端vue有个router控制路径的跳转,router有个自带的beforeEach方法,在这里面写函数,可以实现一些在路径跳转前的验证逻辑,这些方法都在main.js里写,这里的任务是发送请求给后端,得到菜单栏的数据,然后转一下格式,再调用上面store/index.js定义的set方法,把菜单数据存到前端上去。
在main.js里面写函数,上面的是发请求,下面的是转格式:
const initAdminMenu = (router, store) => {
// 防止重复触发加载菜单操作
if (store.state.adminMenus.length > 0) {
return
}
Axios.get('http://127.0.0.1:8088/api/menu').then(resp => {
if (resp && resp.status === 200) {
//console.log(resp.data.result)
//console.log(resp.data)
var fmtRoutes = formatRoutes(resp.data)
console.log("initmenu......")
console.log(fmtRoutes)
router.addRoutes(fmtRoutes)
store.commit('initAdminMenu', fmtRoutes)
}
})
}
//转格式
const formatRoutes = (routes) => {
let fmtRoutes = []
console.log("=====origin data=====")
console.log(routes)
console.log("=====origin data=====")
routes.forEach(route => {
if (route.children) {
route.children = formatRoutes(route.children)
}
let fmtRoute = {
path: route.path,
component: resolve => {
require(['./components/admin/' + route.component + '.vue'], resolve)
},
name: route.name,
nameZh: route.namezh,
iconCls: route.iconcls,
meta: {
requireAuth: true
},
children: route.children
}
fmtRoutes.push(fmtRoute)
})
console.log("=====processed data=====")
console.log(fmtRoutes)
console.log("=====processed data=====")
return fmtRoutes
}
在beforeEach中调用:
if (store.state.user && to.path.startsWith('/admin')) {
//console.log("first login,initmenu......")
initAdminMenu(router, store)
}
这时候我们已经实现了完整的数据的存储,接下来去写界面,显示渲染这些数据。编写vue文件:AdminMenu,这里面把上面得到的数据作为成员变量,用v-for,循环渲染,具体细节如下。
<template>
<el-menu
:default-active="currentPath"
class="el-menu-admin"
router
mode="vertical"
:collapse="isCollapse">
<div style="height: 80px;"></div>
<!--index 没有用但是必需字段-->
<el-submenu v-for="(item,i) in adminMenus" :key="i" :index="(i).toString()" style="text-align: left">
<span slot="title" style="font-size: 17px;">
<i :class="item.iconCls"></i>
{{item.nameZh}}
</span>
<el-menu-item v-for="child in item.children" :key="child.path" :index="child.path">
<i :class="child.icon"></i>
{{ child.nameZh }}
</el-menu-item>
</el-submenu>
</el-menu>
</template>
<script>
export default {
name: "AdminMenu",
data () {
return {
isCollapse: false
}
},
computed: {
adminMenus () {
return this.$store.state.adminMenus
},
currentPath () {
return this.$route.path
}
}
}
</script>
<style scoped>
.el-menu-admin {
border-radius: 5px;
height: 100%;
}
</style>
这个AdminMenu其实是个小部件,还有个Header小部件,被组装在一起放在AdminIndex.vue里面。
在这里开始仔细分析一下上面数据库菜单表里面的结构,表里component这个字段对应前端中的component,有user/Role,这种就是在user文件夹下的Role.vue组件,为了加快开发速度,可以按着这些值,先做出这些文件夹和组件,组件就显示该组件的名字比如这样:
我还找了个权限最低的角色,只需要显示以下几个组件。
记得要在router/index.js里添加主/admin路径,指向AdminIndex.vue
其他组件的路径不用特地配置,刚才那个渲染神奇得把这些路径的配置解决掉了。我的配置大概是这样的。
到这里前端和数据的交互基本已经完成,剩下的就是后端接口问题了。
流程:连接数据库,写pojo类,写dao接口,写service类,写controller类……,这个没啥特别要提的,就是根据当前登录账号的用户找到他的角色,再找到他的菜单,根据找到的菜单,去看那位男人的git代码就好,强烈建议写完一个类/接口编译一次,有时候错误出在dao层,pojo层,坑得很……
在把后端接口和前端整合在一起签,先测试一下接口是否正确:首先发送登录的请求,记得设置rememberMe为true,接着发请求菜单的请求,返回到的应该是json数组如下图所示: