1、前端代码实现
1.App.vue
将获取菜单的方法放在全局中,以便每次刷新页面时,能够加载出。this.$store.state.userInfo是登入后存放在Vuex的用户信息
html
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
import { generaMenu } from '@/assets/js/menu'
export default {
created() {
if (this.$store.state.userInfo != null) {
generaMenu()
}
}
}
</script>
2.menu.js(@/assets/js路径下)
javascript
import Layout from '@/layout/index.vue'
import router from '@/router'
import store from '@/store'
import axios from 'axios'
import Vue from 'vue'
export function generaMenu() {
axios.get('/api/admin/user/menus').then(({ data }) => {
if (data.flag) {
let userMenus = data.data;
userMenus.forEach((item) => {
if (item.icon != null) {
item.icon = 'iconfont ' + item.icon
}
if (item.component == 'Layout') {
item.component = Layout
}
if (item.children && item.children.length > 0) {
item.children.forEach((route) => {
route.icon = 'iconfont ' + route.icon;
route.component = loadView(route.component)
})
}
})
store.commit('saveUserMenus', userMenus);
userMenus.forEach((item) => {
router.addRoute(item)
})
} else {
Vue.prototype.$message.error(data.message);
router.push({ path: '/login' })
}
})
}
export const loadView = (view) => {
return (resolve) => require([`@/views${view}`], resolve)
}
3.SideBar.vue(侧边栏)
html
<template>
<div>
<el-menu
class="side-nav-bar"
router
:collapse="this.$store.state.collapse"
:default-active="this.$route.path"
background-color="#304156"
text-color="#BFCBD9"
active-text-color="#409EFF">
<template v-for="route of this.$store.state.userMenus">
<template v-if="route.name && route.children && !route.hidden">
<el-submenu :key="route.path" :index="route.path">
<template slot="title">
<i :class="route.icon" />
<span>{{ route.name }}</span>
</template>
<template v-for="(item, index) of route.children">
<el-menu-item v-if="!item.hidden" :key="index" :index="item.path">
<i :class="item.icon" />
<span slot="title">{{ item.name }}</span>
</el-menu-item>
</template>
</el-submenu>
</template>
<template v-else-if="!route.hidden">
<el-menu-item :index="route.path" :key="route.path">
<i :class="route.children[0].icon" />
<span slot="title">{{ route.children[0].name }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
</div>
</template>
<style scoped>
.side-nav-bar:not(.el-menu--collapse) {
width: 210px;
}
.side-nav-bar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
}
.side-nav-bar i {
margin-right: 1rem;
}
*::-webkit-scrollbar {
width: 0.5rem;
height: 1px;
}
*::-webkit-scrollbar-thumb {
border-radius: 0.5rem;
background-color: rgba(144, 147, 153, 0.3);
}
</style>
2、后端代码(SpringBoot)
1.Controller层
java
package com.pzg.chat.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.api.R;
import com.pzg.chat.model.dto.MenuDTO;
import com.pzg.chat.model.dto.UserMenuDTO;
import com.pzg.chat.model.vo.ConditionVO;
import com.pzg.chat.model.vo.ResultVO;
import com.pzg.chat.service.MenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* (SysMenu)表控制层
*
* @author makejava
* @since 2024-01-17 14:38:59
*/
@Api(tags = "菜单模块")
@RestController
public class MenuController {
@Resource
private MenuService menuService;
@ApiOperation(value = "查看当前用户菜单")
@GetMapping("/admin/user/menus")
public ResultVO<List<UserMenuDTO>> listUserMenus() {
return ResultVO.ok(menuService.listUserMenus());
}
}
2.Service层
java
public interface MenuService extends IService<Menu> {
List<UserMenuDTO> listUserMenus();
}
3.ServiceImpl层
java
package com.pzg.chat.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pzg.chat.constant.CommonConstant;
import com.pzg.chat.entity.Menu;
import com.pzg.chat.mapper.MenuMapper;
import com.pzg.chat.model.dto.MenuDTO;
import com.pzg.chat.model.dto.UserMenuDTO;
import com.pzg.chat.model.vo.ConditionVO;
import com.pzg.chat.service.MenuService;
import com.pzg.chat.utils.BeanCopy;
import com.pzg.chat.utils.UserUtil;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
import static com.pzg.chat.constant.CommonConstant.COMPONENT;
import static com.pzg.chat.constant.CommonConstant.TRUE;
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
@Override
public List<UserMenuDTO> listUserMenus() {
Integer id = UserUtil.getUserDetailsDTO().getId();
List<Menu> menus = this.baseMapper.listMenusByUserInfoId(id);
List<Menu> catalogs = listCatalogs(menus);
Map<Integer, List<Menu>> childrenMap = getMenuMap(menus);
List<UserMenuDTO> userMenuDTOS = convertUserMenuList(catalogs, childrenMap);
return userMenuDTOS;
}
private List<Menu> listCatalogs(List<Menu> menus) {
return menus.stream()
.filter(item -> Objects.isNull(item.getParentId()))
.sorted(Comparator.comparing(Menu::getOrderNum))
.collect(Collectors.toList());
}
private List<UserMenuDTO> convertUserMenuList(List<Menu> catalogList, Map<Integer, List<Menu>> childrenMap) {
return catalogList.stream().map(item -> {
UserMenuDTO userMenuDTO = new UserMenuDTO();
List<UserMenuDTO> list = new ArrayList<>();
List<Menu> children = childrenMap.get(item.getId());
if (CollectionUtils.isNotEmpty(children)) {
userMenuDTO = BeanCopy.singleCopy(item, UserMenuDTO.class);
list = children.stream()
.sorted(Comparator.comparing(Menu::getOrderNum))
.map(menu -> {
UserMenuDTO dto = BeanCopy.singleCopy(menu, UserMenuDTO.class);
dto.setHidden(menu.getIsHidden().equals(TRUE));
return dto;
})
.collect(Collectors.toList());
} else {
userMenuDTO.setPath(item.getPath());
userMenuDTO.setComponent(COMPONENT);
list.add(UserMenuDTO.builder()
.path("")
.name(item.getName())
.icon(item.getIcon())
.component(item.getComponent())
.build());
}
userMenuDTO.setHidden(item.getIsHidden().equals(TRUE));
userMenuDTO.setChildren(list);
return userMenuDTO;
}).collect(Collectors.toList());
}
}
4.Menu类
java
package com.pzg.chat.entity;
import java.time.LocalDateTime;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* (SysMenu)表实体类
*
* @author makejava
* @since 2024-01-17 14:38:59
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName("sys_menu")
public class Menu {
//主键
private Integer id;
//菜单名
private String name;
//菜单路径
private String path;
//组件
private String component;
//菜单icon
private String icon;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//排序
private Integer orderNum;
//父id
private Integer parentId;
//是否隐藏 0否1是
private Integer isHidden;
}
5.UserMenuDTO
java
package com.pzg.chat.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserMenuDTO {
private String name;
private String path;
private String component;
private String icon;
private Boolean hidden;
private List<UserMenuDTO> children;
}
6.mybatis.xml
XML
<select id="listMenusByUserInfoId" resultType="com.pzg.chat.entity.Menu">
SELECT DISTINCT m.id,
name,
path,
component,
icon,
is_hidden,
parent_id,
order_num
FROM user_role ur
JOIN sys_role_menu rm ON ur.role_id = rm.role_id
JOIN sys_menu m ON rm.menu_id = m.id
WHERE user_info_id = #{userInfoId}
</select>
3、数据库表结构
1.表sys_menu
sql
CREATE TABLE `sys_menu` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '菜单名',
`path` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '菜单路径',
`component` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '组件',
`icon` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '菜单icon',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`order_num` tinyint(1) NOT NULL COMMENT '排序',
`parent_id` int DEFAULT NULL COMMENT '父id',
`is_hidden` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否隐藏 0否1是',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=229 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
2.表sys_role
sql
CREATE TABLE `sys_role` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '角色id',
`role_name` varchar(120) NOT NULL COMMENT '角色名',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`updateTime` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
3.表sys_role_menu
sql
CREATE TABLE `sys_role_menu` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_id` int DEFAULT NULL COMMENT '角色id',
`menu_id` int DEFAULT NULL COMMENT '菜单id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3060 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
4. 表sys_user_info
sql
CREATE TABLE `sys_user_info` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '用户详情id',
`nick_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '昵称',
`username` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '账号',
`gender` int DEFAULT NULL COMMENT '性别',
`avatar` varchar(225) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '头像',
`address` varchar(225) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '地址',
`disable` int DEFAULT NULL COMMENT '是否禁用(0禁用,1不禁用)',
`date_birth` datetime DEFAULT NULL COMMENT '出生日期',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
4、效果
按照上面要求即可实现