用户登录成功后根据用户名获取菜单数据,后台封装前端需要的路由格式
1.后端封装路由组件 1.1 RouterVo 实体类import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 路由需要的数据格式
*/
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class RouterVo {
private String path;
private Boolean hidden;
private String name;
private String component;
private boolean alwaysShow;
private Meta meta;
@Data
@AllArgsConstructor
public class Meta {
private String title;
private String icon;
private Object[] roles;
}
private List<RouterVo> children = new ArrayList<>();
}
1.2 封装成树结构
/**
* 根据用户名查询菜单树 --》这里是下面前端调用的getMenus service层实现
*
* @param username
*/
@Override
public List<RouterVo> selectMenusByUsername(String username) {
Users one = userDao.selectOne(new QueryWrapper<Users>().eq("username", username));
//根据userId查询菜单
List<Permissions> menuList = permissionsDao.selectPermitsByUser(one.getId());
List<Permissions> collect = menuList.stream().filter(item -> item != null && !item.getMenuType().equals(2)).collect(Collectors.toList());
//组装成路由数据
return MenuUtils.makeRouter(collect, 0);
}
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
//构造树形工具
public class MenuUtils {
/**
* 生成路由数据格式
*/
public static List<RouterVo> makeRouter(List<Permissions> menuList, Integer pid) {
//接受生产的路由数据
List<RouterVo> list = new ArrayList<>();
//组装数据
Optional.ofNullable(menuList).orElse(new ArrayList<>())
.stream()
.filter(item -> item != null && item.getParentPermissId() == pid)
.forEach(item -> {
RouterVo router = new RouterVo();
router.setName(item.getName()); //name前端标识
router.setPath(item.getUrl()); //url
router.setHidden("1".equals(item.getHidden())); // hidden:0否;1是
//判断是否是一级菜单
if (item.getParentPermissId() == 0L) {
router.setComponent("Layout");
router.setAlwaysShow(true);
} else {
router.setComponent(item.getUrl());
router.setAlwaysShow(false);
}
//设置meta
router.setMeta(router.new Meta(
item.getPermissionName(),
item.getMenuIcon(),
item.getPerms().split(",")
));
//设置children
List<RouterVo> children = makeRouter(menuList, item.getId());
router.setChildren(children);
list.add(router);
});
return list;
}
}
2.前端获取到后台返回的路由数据
2.1 router.beforeEach拦截路由进行封装
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// 从store里面获取用户信息, VUEX每次刷新页面都会丢失数据,所以permits放在了sessionStorage中
// const hasGetUserInfo = store.getters.name
// 从store里面获取权限信息
const hasPermits = store.getters.permits && store.getters.permits.length > 0
if (hasPermits) {
// 如果权限存在,直接放行
next()
} else {
// 如果不存在,从服务器获取数据
try {
// 从服务器获取用户信息
const { permits } = await store.dispatch('user/getInfo')
//-----------这里是动态路由:从服务器获取菜单、路由信息------------------
const accessRoutes = await store.dispatch('menu/generateRoutes', permits)
let obj = { path: '*', redirect: '/404', hidden: true }
//把返回的数据添加到路由
accessRoutes.push(obj)
router.addRoutes(accessRoutes);
next({ ...to, replace: true })
//-----------------------------------------------------------------
// next()
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
// 判断路由是否在白名单中
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
2.2新建menu.js中递归封装component
import { constantRoutes } from '@/router'
import { getMenus } from '@/api/user'
import Layout from '@/layout'
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param permits
*/
export function filterAsyncRoutes(routes, permits) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(permits, tmp)) {
//动态找到页面路径
const component = tmp.component
if (route.component) {
//判断是否是一级菜单
if (component == 'Layout') {
tmp.component = Layout
} else {
tmp.component = (resolve) => require([`@/views${component}`], resolve)
}
}
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, permits)
}
res.push(tmp)
}
})
return res
}
/**
* Use meta.role to determine if the current user has permission
* @param permits
* @param route
*/
function hasPermission(permits, route) {
if (route.meta && route.meta.permits) {
return permits.some(permit => route.meta.permits.includes(permit))
} else {
return true
}
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
//获取路由数据
generateRoutes({ commit }, permits) {
return new Promise((resolve, reject) => {
getMenus().then(res => {
let accessedRoutes
if (res.code == 200) {
accessedRoutes = filterAsyncRoutes(res.data, permits)
}
//把返回的数据存到vuex里面
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
}).catch(error => {
reject(error)
})
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
sideBar中修改引用的路由,从vuex中获取
<template>
<div :class="{'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="true"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
el-menu>
el-scrollbar>
div>
template>
<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'
export default {
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'sidebar',
'permission_routes'
]),
routes() {
return this.$router.options.routes
},
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},
isCollapse() {
return !this.sidebar.opened
}
}
}
script>
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)