介绍
系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成,而不是固定在系统中。不同的用户根据其权限会看到不同的路由,访问不同的页面。对应各部门不同的权限。
效果
[
{
"id": 1,
"menuName": "用户管理",
"path": "/user",
"icon": null,
"child": [
{
"id": 2,
"menuName": "个人中心",
"path": "/info",
"icon": null,
"child": [
{
"id": 7,
"menuName": "修改密码",
"path": "/alterPassword",
"icon": null
}
]
},
{
"id": 3,
"menuName": "添加用户",
"path": "/addUser",
"icon": null
}
]
},
{
"id": 4,
"menuName": "系统管理",
"path": "/sysManange",
"icon": null,
"child": [
{
"id": 5,
"menuName": "站点配置",
"path": "/siteConfig",
"icon": null
}
]
}
]
用户表设计
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL COMMENT '编号',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用户名',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES (1, 'dpc520');
SET FOREIGN_KEY_CHECKS = 1;
角色表设计
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(11) NOT NULL COMMENT '编号',
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '角色名称',
`role_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '权限字符串',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
INSERT INTO `role` VALUES (1, '超级管理员', 'admin');
SET FOREIGN_KEY_CHECKS = 1;
菜单表设计
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
`menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '菜单名称',
`parent_id` int(11) NULL DEFAULT NULL COMMENT '父亲ID',
`path` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '路由路径',
`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '图标',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
INSERT INTO `menu` VALUES (1, '用户管理', 0, '/user', NULL);
INSERT INTO `menu` VALUES (2, '个人中心', 1, '/info', NULL);
INSERT INTO `menu` VALUES (3, '添加用户', 1, '/addUser', NULL);
INSERT INTO `menu` VALUES (4, '系统管理', 0, '/sysManange', NULL);
INSERT INTO `menu` VALUES (5, '站点配置', 4, '/siteConfig', NULL);
INSERT INTO `menu` VALUES (7, '修改密码', 2, '/alterPassword', NULL);
SET FOREIGN_KEY_CHECKS = 1;
用户与角色关联
对应不同用户的身份
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`user_id` int(11) NOT NULL COMMENT '用户id',
`role_id` int(11) NOT NULL COMMENT '角色id',
PRIMARY KEY (`user_id`, `role_id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Fixed;
INSERT INTO `user_role` VALUES (1, 1);
SET FOREIGN_KEY_CHECKS = 1;
角色与菜单关联
对应不同角色查看不同菜单的权限
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `role_menu`;
CREATE TABLE `role_menu` (
`role_id` int(11) NOT NULL COMMENT '角色ID',
`menu_id` int(11) NOT NULL COMMENT '菜单ID',
PRIMARY KEY (`role_id`, `menu_id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Fixed;
INSERT INTO `role_menu` VALUES (1, 1);
INSERT INTO `role_menu` VALUES (1, 2);
INSERT INTO `role_menu` VALUES (1, 3);
INSERT INTO `role_menu` VALUES (1, 4);
INSERT INTO `role_menu` VALUES (1, 5);
INSERT INTO `role_menu` VALUES (1, 7);
SET FOREIGN_KEY_CHECKS = 1;
SQL语句
根据用户ID,查出对应的角色,根据角色查出对应的菜单
SELECT m.id ,m.menu_name ,m.parent_id,m.path,m.icon FROM user u
LEFT JOIN user_role ur ON ur.user_id=u.id
LEFT JOIN role r ON ur.role_id=r.id
LEFT JOIN role_menu rm ON rm.role_id=r.id
LEFT JOIN menu m ON rm.menu_id=m.id
WHERE u.id=1 ORDER BY m.parent_id ASC
查出数据
后端根据id和parent_id进行菜单的匹配
控制器
@RestController
@RequestMapping("/menu")
@RequiredArgsConstructor
public class MenuController {
private final IMenuService menuService;
@GetMapping("/getMenu")
public List<Menu> getMenu(){
return menuService.getMenuList();
}
}
实体类
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("menu")
public class Menu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 菜单ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 菜单名称
*/
@TableField("menu_name")
private String menuName;
/**
* 父亲ID
*/
@TableField("parent_id")
@JsonIgnore // 不返回该字段
private Integer parentId;
/**
* 路由路径
*/
@TableField("path")
private String path;
/**
* 菜单图标
*/
@TableField("icon")
private String icon;
/**
* 子菜单
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@TableField(exist=false)
List<Menu> child;
}
业务层
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {
private final MenuMapper mapper;
/**
* 获取菜单列表
* @return 返回构建好的菜单列表(包含顶级菜单及其子菜单)
*/
@Override
public List<Menu> getMenuList() {
// 从数据库获取所有菜单列表
List<Menu> list = mapper.getMenuList();
// 创建一个返回给前端的菜单列表
List<Menu> returnList = new ArrayList<Menu>();
// 遍历数据库中获取的菜单列表
for (Iterator<Menu> iterator = list.iterator(); iterator.hasNext();)
{
// 获取当前菜单
Menu t = iterator.next();
// 判断是否为顶级菜单(ParentId 为 0)
if (t.getParentId() == 0)
{
// 如果是顶级菜单,查找并设置其子菜单
recursionFn(list, t);
// 将该菜单加入到返回列表
returnList.add(t);
}
}
// 返回构建好的菜单列表
return returnList;
}
/**
* 递归查找并设置子菜单
* @param list 菜单列表
* @param t 当前菜单(可能是父菜单)
*/
private void recursionFn(List<Menu> list, Menu t)
{
// 获取当前菜单的所有子菜单
List<Menu> childList = getChildList(list, t);
// 设置当前菜单的子菜单
t.setChild(childList);
// 遍历子菜单,递归处理每个子菜单的子菜单
for (Menu tChild : childList)
{
if (hasChild(list, tChild))
{
// 如果子菜单还有子菜单,递归调用
recursionFn(list, tChild);
}
}
}
/**
* 获取某个菜单的所有子菜单
* @param list 菜单列表
* @param t 当前菜单(父菜单)
* @return 当前菜单的子菜单列表
*/
private List<Menu> getChildList(List<Menu> list, Menu t)
{
// 存储当前菜单的子菜单
List<Menu> tlist = new ArrayList<Menu>();
// 使用迭代器遍历菜单列表
Iterator<Menu> it = list.iterator();
while (it.hasNext())
{
// 获取当前菜单
Menu n = it.next();
// 如果菜单的 ParentId 等于当前菜单的 ID,表示该菜单是当前菜单的子菜单
if (n.getParentId() == t.getId())
{
// 将子菜单添加到子菜单列表中
tlist.add(n);
}
}
// 返回子菜单列表
return tlist;
}
/**
* 判断一个菜单是否有子菜单
* @param list 菜单列表
* @param t 当前菜单(父菜单)
* @return 如果当前菜单有子菜单则返回 true,否则返回 false
*/
private boolean hasChild(List<Menu> list, Menu t)
{
// 如果获取的子菜单列表的大小大于 0,说明当前菜单有子菜单
return getChildList(list, t).size() > 0;
}
}
数据层
<select id="getMenuList" resultMap="menuList">
SELECT m.id ,m.menu_name ,m.parent_id,m.path,m.icon FROM user u
LEFT JOIN user_role ur ON ur.user_id=u.id
LEFT JOIN role r ON ur.role_id=r.id
LEFT JOIN role_menu rm ON rm.role_id=r.id
LEFT JOIN menu m ON rm.menu_id=m.id
WHERE u.id=1 ORDER BY m.parent_id ASC
</select>
<resultMap id="menuList" type="com.role.web.pojo.Menu" autoMapping="true">
<id property="id" column="id"></id>
<result property="menuName" column="menu_name"></result>
</resultMap>