下面我将为您详细讲解“springboot + vue 实现递归生成多级菜单”的完整攻略。
简介
本文将介绍如何使用SpringBoot和Vue.js实现递归生成多级菜单。通过该方案,可以生成任意深度的多级菜单。
准备工作
在开始之前,需要下载安装以下软件:
- JDK 8+
- Node.js
- Vue CLI
创建SpringBoot项目
首先,使用Spring Initializr创建一个新的SpringBoot项目,具体方法可以参考官方文档。
在创建过程中,需要添加以下依赖项:
- Spring Web
- Spring Data JPA
- MySQL Driver
创建完成后,将生成的代码导入到你的IDE中并进行配置。
创建数据库表
创建一个名为sys_menu
的数据库表,用于存储菜单数据。
表结构如下:
CREATE TABLE `sys_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
`url` varchar(200) DEFAULT NULL COMMENT '菜单URL',
`perms` varchar(500) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
`type` int(11) DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
`order_num` int(11) DEFAULT NULL COMMENT '菜单排序',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
编写SpringBoot代码
下一步是编写SpringBoot后端代码。在com.example.demo
包下创建一个名为controller
的包,并在其中创建一个名为MenuController
的控制器。
@RestController
@RequestMapping("/menu")
public class MenuController {
@Autowired
private MenuService menuService;
@GetMapping("/list")
public List<Menu> list() {
return menuService.list();
}
}
在com.example.demo
包下创建一个名为service
的包,并在其中创建一个名为MenuService
的服务。
public interface MenuService {
List<Menu> list();
}
@Service
public class MenuServiceImpl implements MenuService {
@Autowired
private MenuRepository menuRepository;
@Override
public List<Menu> list() {
// 递归查询所有菜单
List<Menu> menuList = menuRepository.findByParentIdIsNull();
return build(menuList);
}
/**
* 递归生成菜单树
* @param menuList 菜单列表
* @return 生成的菜单树
*/
private List<Menu> build(List<Menu> menuList) {
List<Menu> treeList = new ArrayList<>();
for (Menu menu : menuList) {
if (menu.getType() == 0) {
// 递归查询子菜单
List<Menu> children = menuRepository.findByParentId(menu.getId());
menu.setChildren(build(children));
}
treeList.add(menu);
}
return treeList;
}
}
最后,在com.example.demo
包下创建一个名为repository
的包,并在其中创建一个名为MenuRepository
的仓库。
public interface MenuRepository extends JpaRepository<Menu, Long> {
/**
* 按 parentId 查找菜单
*/
List<Menu> findByParentId(Long parentId);
/**
* 查找 parentId 为 null 的菜单
*/
List<Menu> findByParentIdIsNull();
}
创建Vue前端项目
在命令行中执行如下命令,创建一个名为vue-demo
的新项目:
vue create vue-demo
该命令会使用Vue CLI创建一个新的Vue.js项目,并自动安装所需的依赖项。
编写Vue代码
在vue-demo
项目中,打开src/App.vue
文件,修改其内容如下:
<template>
<div>
<h1>{{ title }}</h1>
<ul>
<menu-item v-for="menu in menuList" :key="menu.id" :menu="menu"></menu-item>
</ul>
</div>
</template>
<script>
import axios from 'axios'
import MenuItem from './components/MenuItem.vue'
export default {
name: 'App',
components: {
MenuItem
},
data() {
return {
title: '递归生成多级菜单',
menuList: []
}
},
created() {
// 加载菜单数据
axios.get('/menu/list').then(response => {
this.menuList = response.data
})
}
}
</script>
该代码会渲染一个多级菜单,其数据来源于后端控制器。
在vue-demo
项目中,创建一个名为components
的目录,并在其中创建一个名为MenuItem.vue
的组件。
<template>
<li>
<a v-if="menu.type === 1" :href="menu.url">{{ menu.name }}</a>
<span v-else>{{ menu.name }}</span>
<ul v-if="menu.children">
<menu-item v-for="child in menu.children" :key="child.id" :menu="child"></menu-item>
</ul>
</li>
</template>
<script>
export default {
name: 'MenuItem',
props: {
menu: {
type: Object,
required: true
}
}
}
</script>
该组件会渲染一个菜单项,并递归渲染其子菜单项。
运行程序
在命令行中,分别进入springboot
和vue-demo
目录,并执行以下命令:
// 在springboot目录下执行以下命令
./mvnw spring-boot:run
// 在vue-demo目录下执行以下命令
npm run serve
现在,您就可以在浏览器中访问http://localhost:8080
,查看漂亮的多级菜单了!
示例说明
示例1:添加菜单
为了演示添加菜单的操作,可以修改MenuController
中list()
方法的返回值,返回一个由多个菜单项组成的“菜单列表”。具体代码如下:
@GetMapping("/list")
public List<Menu> list() {
List<Menu> menuList = new ArrayList<>();
// 添加第一个菜单项
Menu menu1 = new Menu();
menu1.setId(1L);
menu1.setName("系统管理");
menu1.setUrl(null);
menu1.setType(0);
menu1.setOrderNum(10);
menu1.setCreateTime(new Date());
menu1.setUpdateTime(new Date());
Menu menu11 = new Menu();
menu11.setId(11L);
menu11.setName("用户管理");
menu11.setUrl("/user");
menu11.setType(1);
menu11.setOrderNum(10);
menu11.setCreateTime(new Date());
menu11.setUpdateTime(new Date());
Menu menu12 = new Menu();
menu12.setId(12L);
menu12.setName("角色管理");
menu12.setUrl("/role");
menu12.setType(1);
menu12.setOrderNum(20);
menu12.setCreateTime(new Date());
menu12.setUpdateTime(new Date());
// 第一个菜单项添加两个子菜单项
menu1.setChildren(Arrays.asList(menu11, menu12));
// 添加第二个菜单项
Menu menu2 = new Menu();
menu2.setId(2L);
menu2.setName("购物中心");
menu2.setUrl("/shop");
menu2.setType(1);
menu2.setOrderNum(20);
menu2.setCreateTime(new Date());
menu2.setUpdateTime(new Date());
menuList.add(menu1);
menuList.add(menu2);
return menuList;
}
示例2:删除菜单
为了演示删除菜单的操作,可以在MenuServiceImpl
中添加一个名为delete()
的方法,实现删除菜单的功能。具体操作如下:
public void delete(Long id) {
// 从数据库中删除菜单
menuRepository.deleteById(id);
}
在MenuController
中添加一个名为delete()
的方法,实现删除菜单项的功能。具体代码如下:
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
menuService.delete(id);
}
在MenuItem.vue
组件中添加一个名为delete()
的方法,实现“删除菜单”按钮的功能。具体代码如下:
<template>
<li>
<div>
<a v-if="menu.type === 1" :href="menu.url">{{ menu.name }}</a>
<span v-else>{{ menu.name }}</span>
<button v-if="menu.type !== 0" @click="deleteMenu">删除</button>
</div>
<ul v-if="menu.children">
<menu-item v-for="child in menu.children" :key="child.id" :menu="child"></menu-item>
</ul>
</li>
</template>
<script>
export default {
name: 'MenuItem',
props: {
menu: {
type: Object,
required: true
}
},
methods: {
deleteMenu() {
if (window.confirm('确认删除该菜单?')) {
// 向后台发送删除请求
axios.delete('/menu/' + this.menu.id)
// 重新加载菜单数据
this.$root.$emit('reloadMenu')
}
}
}
}
</script>
将“删除菜单”按钮添加到菜单项中之后,就可以轻松删除菜单项了!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot + vue 实现递归生成多级菜单(实例代码) - Python技术站