https://blog.youkuaiyun.com/weter_drop/article/details/103601591
完整示例代码地址如下:
https://github.com/Dr-Water/springboot-action/tree/master/springboot-shiro
一、 权限树的问题由来
在开发中难免遇到一个有多级菜单结构树,或者多级部门的结构树,亦或是省市区县的多级结构,数据结构类似如下的json数据:
[
{
"id": "1",
"name": "主菜单1",
"pid": "0",
"menuChildren": [
{
"id": "4",
"name": "子菜单1.1",
"pid": "1",
"menuChildren": [
{
"id": "6",
"name": "子菜单1.1.1",
"pid": "4",
"menuChildren": []
},
{
"id": "9",
"name": "子菜单1.1.2",
"pid": "4",
"menuChildren": []
}
]
},
{
"id": "5",
"name": "子菜单1.2",
"pid": "1",
"menuChildren": []
}
]
},
{
"id": "2",
"name": "主菜单2",
"pid": "0",
"menuChildren": [
{
"id": "7",
"name": "子菜单2.1",
"pid": "2",
"menuChildren": []
},
{
"id": "8",
"name": "子菜单2.2",
"pid": "2",
"menuChildren": []
}
]
},
{
"id": "3",
"name": "主菜单3",
"pid": "0",
"menuChildren": []
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
二、 解决方案
目前的解决方案主要有以下两种方案:
方案一:后端把所有需要的数据以一个大list返回前端,前端进行操作,把数据搞成树状结构
方案二: 后端在后端返回数据之前把数据搞成已经有层次结构的数据,方案二也分为两种解决方法
方法一:次性将数据查询出来,在java程序中进行树状结构的构建
方法二: 第一次将最高层次的数据查询出来,然后多次循环查询数据库将子数据查询出来
由于博主的前端水平有限,目前只能用后端的实现方式,再加上每次查询数据库的开销比较大,所以本文使用方案二的方法一进行验证
实现步骤
以菜单的结构树为例
准备mysql数据库的基础数据
java的实体类:
@Data
@NoArgsConstructor
public class Menu implements Serializable {
private String id;
private String name;
private String pid;
private List<Menu> menuChildren;
}
1
2
3
4
5
6
7
8
9
java的dao层
@Mapper
public interface MenuDao {
/**
* 根据父类id查询子类菜单
* @param pid
* @return
*/
List<Menu> selectByPid(Integer pid);
/**
* 查询所有的菜单
* @return
*/
List<Menu> selectAll();
/**
* 查询除了一级菜单以外的菜单
* @return
*/
List<Menu> selectAllNotBase();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mapper文件
<?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.ratel.shiro.dao.MenuDao">
<select id="selectByPid" resultType="com.ratel.shiro.entity.Menu">
SELECT * FROM menu WHERE pid=#{pid}
</select>
<select id="selectAll" resultType="com.ratel.shiro.entity.Menu">
SELECT * FROM menu
</select>
<select id="selectAllNotBase" resultType="com.ratel.shiro.entity.Menu">
SELECT * FROM menu where pid!= 0
</select>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Controller层(由于是查询操作,并且没有复杂的操作,偷个懒就不写service层)
@RestController
@RequestMapping("mymenu")
public class MenuController {
@Autowired
private MenuDao menuDao;
@RequestMapping("/getMenuTree")
public List<Menu> getMenuTree(){
List<Menu> menusBase = menuDao.selectByPid(0);
List<Menu> menuLNotBase = menuDao.selectAllNotBase();
for (Menu menu : menusBase) {
List<Menu> menus = iterateMenus(menuLNotBase, menu.getId());
menu.setMenuChildren(menus);
}
return menusBase;
}
/**
*多级菜单查询方法
* @param menuVoList 不包含最高层次菜单的菜单集合
* @param pid 父类id
* @return
*/
public List<Menu> iterateMenus(List<Menu> menuVoList,String pid){
List<Menu> result = new ArrayList<Menu>();
for (Menu menu : menuVoList) {
//获取菜单的id
String menuid = menu.getId();
//获取菜单的父id
String parentid = menu.getPid();
if(StringUtils.isNotBlank(parentid)){
if(parentid.equals(pid)){
//递归查询当前子菜单的子菜单
List<Menu> iterateMenu = iterateMenus(menuVoList,menuid);
menu.setMenuChildren(iterateMenu);
result.add(menu);
}
}
}
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
启动程序用postman进行测试:
返回的json数据如下:
[
{
"id": "1",
"name": "主菜单1",
"pid": "0",
"menuChildren": [
{
"id": "4",
"name": "子菜单1.1",
"pid": "1",
"menuChildren": [
{
"id": "6",
"name": "子菜单1.1.1",
"pid": "4",
"menuChildren": []
},
{
"id": "9",
"name": "子菜单1.1.2",
"pid": "4",
"menuChildren": []
}
]
},
{
"id": "5",
"name": "子菜单1.2",
"pid": "1",
"menuChildren": []
}
]
},
{
"id": "2",
"name": "主菜单2",
"pid": "0",
"menuChildren": [
{
"id": "7",
"name": "子菜单2.1",
"pid": "2",
"menuChildren": []
},
{
"id": "8",
"name": "子菜单2.2",
"pid": "2",
"menuChildren": []
}
]
},
{
"id": "3",
"name": "主菜单3",
"pid": "0",
"menuChildren": []
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
参考链接:
java递归 处理权限管理菜单树或分类
一次性搞定权限树遍历--------权限树后台遍历的通用解决方案
(java后台)用户权限的多级菜单遍历方法
java 用递归实现球上下级(牵涉到对上级的去重)
java递归获取某个父节点下面的所有子节点
java递归算法总结
————————————————
版权声明:本文为优快云博主「ratelfu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/weter_drop/article/details/103601591