宜兴网站建设百度网站制作联系方式
完整示例代码地址如下:
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": []}
]
二、 解决方案
目前的解决方案主要有以下两种方案:
- 方案一:后端把所有需要的数据以一个大list返回前端,前端进行操作,把数据搞成树状结构
- 方案二: 后端在后端返回数据之前把数据搞成已经有层次结构的数据,方案二也分为两种解决方法
- 方法一:次性将数据查询出来,在java程序中进行树状结构的构建
- 方法二: 第一次将最高层次的数据查询出来,然后多次循环查询数据库将子数据查询出来
由于博主的前端水平有限,目前只能用后端的实现方式,再加上每次查询数据库的开销比较大,所以本文使用方案二的方法一进行验证
实现步骤
以菜单的结构树为例
- 准备mysql数据库的基础数据
- java的实体类:
@Data
@NoArgsConstructor
public class Menu implements Serializable {private String id;private String name;private String pid;private List<Menu> menuChildren;
}
- java的dao层
@Mapper
public interface MenuDao {/*** 根据父类id查询子类菜单* @param pid* @return*/List<Menu> selectByPid(Integer pid);/*** 查询所有的菜单* @return*/List<Menu> selectAll();/*** 查询除了一级菜单以外的菜单* @return*/List<Menu> selectAllNotBase();
}
- mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//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>
- Controller层(由于是查询操作,并且没有复杂的操作,偷个懒就不写service层)
@RestController
@RequestMapping("mymenu")
public class MenuController {@Autowiredprivate 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) {//获取菜单的idString menuid = menu.getId();//获取菜单的父idString 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;}
}
- 启动程序用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": []}
]
参考链接:
java递归 处理权限管理菜单树或分类
一次性搞定权限树遍历--------权限树后台遍历的通用解决方案
(java后台)用户权限的多级菜单遍历方法
java 用递归实现球上下级(牵涉到对上级的去重)
java递归获取某个父节点下面的所有子节点
java递归算法总结