網(wǎng)站首頁 Vue 正文
*小tip:每次重新啟動前端項目加載困難可以crlt+shift+delete清除瀏覽器緩存后再重新啟動
1.前端改造
首先我們拿到項目,得了解一下目錄結(jié)構(gòu)
他是通過src->router->index.js,根據(jù)路由來進行頁面的跳轉(zhuǎn)
constantRoutes:通用頁面路由
asyncRoutes:動態(tài)路由
1.1參數(shù)講解
各個參數(shù)的意思
有子目錄的目錄,以最常見的table
舉例,table
在這里,ctrl+左鍵
點進去就行
參數(shù)與目錄的對照:
1.2動態(tài)菜單思路
我們要做到的是,根據(jù)后端返回的json對象,動態(tài)的顯示目錄
而vue-element-admin,是寫死了的菜單,所以我們調(diào)用后端接口,實現(xiàn)目錄的拼接,最終達到實現(xiàn)動態(tài)菜單的目的
那么我們就要仿造router目錄下index.js文件,動態(tài)的生成相似的json對象
1.3前端代碼
修改router目錄下的index.js中的asyncRoutes方法,使其為空,要我們動態(tài)的加入菜單
export const asyncRoutes = [
]
首先在src->api>user.js,加入一個接口方法
//這里加一個,根據(jù)data(token)的不同,后臺會返回不同的字符串結(jié)果,動態(tài)菜單完成
export function authMenu(data) {
const jsonData = JSON.stringify(data); // 手動轉(zhuǎn)換為 JSON 字符串
console.log("data數(shù)據(jù)是", jsonData); // 在這里添加打印語句
return request({
url: '/user/selectMenu',
method: 'post',
data: jsonData, // 使用轉(zhuǎn)換后的 JSON 字符串
headers: {
'Content-Type': 'application/json'
}
});
}
修改store/modules/permission.js文件,在 generateRoutes方法里面調(diào)用上面的authMenu接口
import { asyncRoutes, constantRoutes } from '@/router'
import { authMenu } from '@/api/user'// 【新加入】引入請求,后面有文件,先不慌
import Layout from '@/layout'// 【新加入】引入layout
//這里自己寫方法,作用就是向 asyncRoutes 插入路由,達到動態(tài)路由的效果
/**
* 【新加入】后臺查詢的菜單數(shù)據(jù)拼裝成路由格式的數(shù)據(jù)
* @param routes
*/
export function generaMenu(routes, data) {
//data挨個遍歷
data.forEach(item => {
//path不為空的話,就新建一個對象,裝數(shù)據(jù)
if (item.path !== '') {
//這個就仿照目錄的機構(gòu),搭建
const menu = {
path: item.path,
component: Layout, //這個不用寫data里面的內(nèi)容,引用就行了
redirect: item.redirect,
children: [],
meta: { // 使用 title 和 icon 創(chuàng)建 meta 對象
title: item.title,
icon: item.icon
}
}
//遍歷子標簽,并加入到主目錄的children中去
// 判斷是否有子標簽
if (item.children && Array.isArray(item.children) && item.children.length > 0) {
// 遍歷子標簽,并加入到主目錄的 children 中去
item.children.forEach(childItem => {
const menu2 = {
path: childItem.path,
component: (resolve) => require([`@/views${childItem.component}`], resolve),
name: childItem.name,
meta: { // 使用 title 和 icon 創(chuàng)建 meta 對象
title: childItem.title,
icon: childItem.icon
}
}
// 加入到主目錄的 children 中去
menu.children.push(menu2)
})
}
//追加
routes.push(menu)
}
})
//把404加到最后,因為作者說 // 404 page must be placed at the end !!!
const menu3 = {
path: '*',
redirect: '/404',
hidden: true
}
//追加
routes.push(menu3)
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit,rootState },) {
return new Promise(resolve => {
const loadMenuData = [] // 保留加載動態(tài)路由的代碼
// authMenu 調(diào)用可能也需要根據(jù)你的需要來決定是否刪除
authMenu(rootState.user.token).then(response => {
let data = response
if (response.code !== 20000) {
// 錯誤處理邏輯
} else {
data = response.data
Object.assign(loadMenuData, data)
const tempAsyncRoutes = Object.assign([], asyncRoutes)
generaMenu(tempAsyncRoutes, loadMenuData)
let accessedRoutes
accessedRoutes = tempAsyncRoutes || []
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
}
})
}).catch(error => {
console.log(error)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
最后,修改views/login下的index.vue,dispatch 一下(在登錄成功的前提下)
向handleLogin中添加dispatch( "permission/generateRoutes",userRoles)
handleLogin() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.loading = true;
// 假設(shè)有一種方法用于獲取用戶角色,例如 getUserRoles()
const userRoles = ["admin"];
this.$store
.dispatch("user/login", this.loginForm)
.then(() => {
// 將預定義的角色 "admin" 傳遞給 generateRoutes action
return this.$store.dispatch(
"permission/generateRoutes",
userRoles
);
})
.then((accessedRoutes) => {
// 將動態(tài)路由添加到路由器
this.$router.addRoutes(accessedRoutes);
// 導航到指定路徑或默認路徑 ('/')
this.$router.push({
path: this.redirect || "/",
query: this.otherQuery,
});
// 重置加載狀態(tài)
this.loading = false;
})
.catch(() => {
// 在登錄失敗的情況下重置加載狀態(tài)
this.loading = false;
});
} else {
console.log("提交錯誤!!");
return false;
}
});
},
2.后端改造
@Controller層
@Resource
private MenuService menuService;
/**
* 動態(tài)菜單獲取
*/
@PostMapping("/selectMenu")
public MenuResponse selectMenu(@RequestBody VoToken voToken) {
MenuResponse res = new MenuResponse();
try {
// 驗證token的合法和有效性
String tokenValue = JwtUtil.verity(voToken.getToken());
if (tokenValue != null && tokenValue.startsWith(JwtUtil.TOKEN_SUCCESS)) {
// 從令牌中提取實際的用戶名
String username = tokenValue.replaceFirst(JwtUtil.TOKEN_SUCCESS, "");
// 記錄調(diào)用日志
log.info("從令牌中提取的用戶名: {}", username);
// 調(diào)用 MenuService 獲取菜單數(shù)據(jù)
List<VoMenu> menus = menuService.getAllMenus();
// 記錄菜單數(shù)量的日志
log.info("獲取的菜單數(shù)量: {}", menus.size());
// 構(gòu)建響應對象
res.setCode(Constants.STATUS_OK);
res.setMsg(Constants.MESSAGE_OK);
res.setData(menus);
} else {
// 記錄token驗證失敗的日志
log.warn("Token驗證失敗");
// 驗證失敗
res.setCode(Constants.STATUS_FAIL);
res.setMsg(Constants.MESSAGE_FAIL);
}
} catch (Exception e) {
// 記錄處理請求時發(fā)生的異常
log.error("處理請求時發(fā)生異常", e);
// 處理異常
res.setCode(60204);
res.setMsg("返回失敗");
}
return res;
}
@Servicer
package com.mv.servicer;
import com.mv.entity.VO.VoMenu;
import java.awt.*;
import java.util.List;
public interface MenuService {
List<VoMenu> getAllMenus();
}
@ServiceImpl
package com.mv.servicer.Impl;
import com.mv.entity.VO.VoMenu;
import com.mv.mapper.MenuMapper;
import com.mv.servicer.MenuService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.awt.*;
import java.util.List;
@Service
public class MenuServiceImpl implements MenuService {
@Resource
private MenuMapper menuMapper;
@Override
public List<VoMenu> getAllMenus() {
List<VoMenu> allMenus = menuMapper.getAllMenus();
return VoMenu.buildMenuTree(allMenus);
}
// 可以根據(jù)需要添加其他方法
}
@Mapper
package com.mv.mapper;
import com.mv.entity.VO.VoMenu;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MenuMapper {
List<VoMenu> getAllMenus();
}
@Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.mv.mapper.MenuMapper">
<select id="getAllMenus" resultType="com.mv.entity.VO.VoMenu">
SELECT * FROM menus;
</select>
</mapper>
對應數(shù)據(jù)庫的實體類@VoMenus
package com.mv.entity.VO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VoMenu {
private Integer id; // 使用 Integer 類型,與數(shù)據(jù)庫表中的 id 類型匹配
private String path;
private String component;
private String redirect;
private String name;
private String title; // 新增字段 title
private String icon; // 新增字段 icon
private Integer parent_id; // 與數(shù)據(jù)庫表中的 parent_id 類型匹配
private List<VoMenu> children;
// Getters and setters
// Constructors
public Integer getId() {
return id;
}
public Integer getParentId() {
return parent_id;
}
public static List<VoMenu> buildMenuTree(List<VoMenu> menuList) {
Map<Integer, VoMenu> menuMap = new HashMap<>();
for (VoMenu menu : menuList) {
menuMap.put(menu.getId(), menu);
}
List<VoMenu> tree = new ArrayList<>();
for (VoMenu menu : menuList) {
if (menu.getParentId() != null) {
VoMenu parent = menuMap.get(menu.getParentId());
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(menu);
}
} else {
// 如果沒有父菜單,說明是頂級菜單
tree.add(menu);
}
}
return tree;
}
}
后端單方面測試 我使用的是apifox
返回數(shù)據(jù)成功。
3.數(shù)據(jù)庫menus以及前端目錄結(jié)構(gòu)參考
3.1數(shù)據(jù)庫里的父子級菜單
** 我的動態(tài)菜單獲取并沒有設(shè)置權(quán)限,因為我的后臺只有一個管理員admin
3.2.前端目錄結(jié)構(gòu)
位于原項目@/views下的permission文件夾
3.3.前后端互聯(lián)展示
3.3.1后端返回數(shù)據(jù):
{
"code": 20000,
"msg": "成功,",
"data": [
{
"id": 1,
"path": "/permission",
"component": "Layout",
"redirect": "/permission/page",
"name": "Permission",
"title": "Permission",
"icon": "lock",
"parent_id": null,
"children": [
{
"id": 2,
"path": "/permission/page",
"component": "/permission/page",
"redirect": null,
"name": "PagePermission",
"title": "Page Permission",
"icon": null,
"parent_id": 1,
"children": null,
"parentId": 1
},
{
"id": 3,
"path": "/permission/directive",
"component": "/permission/directive",
"redirect": null,
"name": "DirectivePermission",
"title": "Directive Permission",
"icon": null,
"parent_id": 1,
"children": null,
"parentId": 1
},
{
"id": 4,
"path": "/permission/role",
"component": "/permission/role",
"redirect": null,
"name": "RolePermission",
"title": "Role Permission",
"icon": null,
"parent_id": 1,
"children": null,
"parentId": 1
}
],
"parentId": null
}
]
}
3.3.2前端渲染效果:
前后端互聯(lián)完成。
原文鏈接:https://blog.csdn.net/m0_53899978/article/details/134954039
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2022-03-27 C語言中浮點數(shù)的精度丟失問題解決_C 語言
- 2022-05-12 寶塔面板配置SSL證書
- 2022-07-20 用C語言實現(xiàn)掃雷
- 2022-03-03 CSS樣式修改不換行顯示省略號及多行顯示省略號
- 2022-08-27 python基礎(chǔ)篇之pandas常用基本函數(shù)匯總_python
- 2023-01-31 基于C#實現(xiàn)獲取本地磁盤目錄_C#教程
- 2022-10-02 react中使用antd及immutable示例詳解_React
- 2024-03-20 解決(gyp、python等問題):gyp ERR! find VS msvs_version no
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支