栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

动态路由前后端vue+springboot实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态路由前后端vue+springboot实现

动态路由

用户登录成功后根据用户名获取菜单数据,后台封装前端需要的路由格式

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 children = new ArrayList<>();

}
1.2 封装成树结构
   
    @Override
    public List selectMenusByUsername(String username) {
        Users one = userDao.selectOne(new QueryWrapper().eq("username", username));
        //根据userId查询菜单
        List menuList = permissionsDao.selectPermitsByUser(one.getId());
        List 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 makeRouter(List menuList, Integer pid) {
        //接受生产的路由数据
        List 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 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 {
    
    // 判断路由是否在白名单中
    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'


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
}


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中获取




转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/830887.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号