在使用 CAS 进行单点登录时,获取到用户的相关数据(例如菜单或权限),一般是通过后端从 CAS 服务器中获取用户信息,并在后端进行解析后,传递给前端去加载。在 JeecgBoot 这种场景下,如果你已经从 CAS 获取到了菜单数据,那么如何将这些菜单正确加载到前端主要涉及以下几个步骤。
目录
1. 后端获取菜单数据
通常,后端会通过 CAS 返回的用户身份信息(比如用户 ID、角色)去调用后端的 API(如用户菜单服务)获取用户的菜单和权限数据。如果菜单数据已经从 CAS 服务器成功返回给后端,确保以下两件事:
- 后端数据格式一致性:确保从 CAS 服务器返回的菜单数据结构与 Jeecg 前端期待的数据格式一致。
- 后端 API 正确返回:如果前端是通过后端 API 来获取菜单,请确保 API 路由正确并返回给前端正确的菜单数据。
例如,假设后端 API 返回如下格式的数据:
{
"menu": [
{
"id": 1,
"title": "Dashboard",
"icon": "dashboard",
"path": "/dashboard",
"children": []
},
{
"id": 2,
"title": "User Management",
"icon": "user",
"path": "/user-management",
"children": [
{
"id": 3,
"title": "Create User",
"path": "/user-management/create"
}
]
}
]
}
2. 前端接收并渲染菜单
在 JeecgBoot 中,前端菜单通常是基于 React
或 Vue
的组件来动态渲染的。如果从后端返回了菜单数据,可以通过以下步骤加载到前端页面中。
前端的主要步骤
-
请求菜单数据:通过 API 请求从后端获取菜单数据。
-
处理和存储菜单数据:将菜单数据存储在前端状态管理系统中,例如
Redux
或Vuex
,以便后续动态渲染菜单。 -
动态渲染菜单:使用前端框架的组件,将获取到的菜单数据渲染出来。
例子(React)
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Menu } from "antd";
const DynamicMenu = () => {
const [menuItems, setMenuItems] = useState([]);
// 模拟 API 请求
useEffect(() => {
axios.get("/api/getMenu") // 替换为实际的后端 API
.then((response) => {
setMenuItems(response.data.menu); // 假设后端返回的数据格式符合这个格式
})
.catch((error) => {
console.error("Error fetching menu data", error);
});
}, []);
// 动态生成菜单
const renderMenuItems = (items) => {
return items.map((item) => {
if (item.children && item.children.length > 0) {
return (
<Menu.SubMenu key={item.id} title={item.title} icon={item.icon}>
{renderMenuItems(item.children)}
</Menu.SubMenu>
);
}
return (
<Menu.Item key={item.id}>
<a href={item.path}>{item.title}</a>
</Menu.Item>
);
});
};
return (
<Menu mode="vertical">
{renderMenuItems(menuItems)}
</Menu>
);
};
export default DynamicMenu;
在上述代码中:
- 使用
axios
向后端请求菜单数据,并将其存储在menuItems
状态中。 - 使用递归的方式
renderMenuItems
动态渲染多层级的菜单结构。
例子(Vue)
如果使用 Vue
,你可以通过 axios
请求数据,并使用 v-for
进行动态渲染:
<template>
<el-menu>
<template v-for="item in menuItems">
<el-submenu v-if="item.children && item.children.length" :key="item.id" :index="item.id">
<template slot="title">{{ item.title }}</template>
<el-menu-item v-for="child in item.children" :key="child.id" :index="child.id">
<router-link :to="child.path">{{ child.title }}</router-link>
</el-menu-item>
</el-submenu>
<el-menu-item v-else :key="item.id" :index="item.id">
<router-link :to="item.path">{{ item.title }}</router-link>
</el-menu-item>
</template>
</el-menu>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
menuItems: []
};
},
created() {
axios.get("/api/getMenu")
.then(response => {
this.menuItems = response.data.menu;
})
.catch(error => {
console.error("Error fetching menu data", error);
});
}
};
</script>
3. 菜单数据格式匹配
确保从 CAS 或后端返回的菜单数据格式与前端渲染期望的菜单结构一致。通常,菜单数据会包含以下字段:
- id: 菜单项的唯一标识符。
- title: 菜单项显示的名称。
- icon: 菜单项的图标(如果有)。
- path: 路由路径。
- children: 子菜单项(如果是嵌套菜单)。
如果后端返回的数据结构不符合前端的要求,你可能需要在前端做一些数据预处理。
例如,假设后端返回的数据结构如下:
{
"menuList": [
{
"menuId": 1,
"menuName": "Dashboard",
"menuUrl": "/dashboard",
"subMenuList": []
},
{
"menuId": 2,
"menuName": "User Management",
"menuUrl": "/user-management",
"subMenuList": [
{
"menuId": 3,
"menuName": "Create User",
"menuUrl": "/user-management/create"
}
]
}
]
}
你可以在前端转换为适合渲染的数据格式:
const transformMenuData = (data) => {
return data.menuList.map(item => ({
id: item.menuId,
title: item.menuName,
path: item.menuUrl,
children: item.subMenuList ? transformMenuData(item.subMenuList) : []
}));
};
然后将其传递到渲染函数:
useEffect(() => {
axios.get("/api/getMenu")
.then((response) => {
const transformedMenu = transformMenuData(response.data);
setMenuItems(transformedMenu);
})
.catch((error) => {
console.error("Error fetching menu data", error);
});
}, []);
4. 权限控制(可选)
在某些情况下,CAS 还可能返回用户的权限数据,你可以根据用户的权限来动态加载或隐藏某些菜单项。确保前端在处理菜单时,有一层权限判断逻辑,根据用户的角色或权限来渲染不同的菜单。
总结
- 确保后端正确获取到菜单数据。
- 使用前端请求后端 API 获取菜单。
- 动态渲染菜单,确保数据格式与前端渲染格式一致。
- (可选)实现权限控制,隐藏或显示特定菜单项。
通过这些步骤,应该可以成功加载从 CAS 返回的菜单并在前端正确显示。