java 递归实现权限树(菜单树)

本文探讨了在开发中如何处理多级菜单结构的问题,提出了两种解决方案:后端返回所有数据由前端构建树,或者后端直接构建树状结构。鉴于数据库查询开销和前端能力限制,作者选择了后端通过递归在Java中构建树状结构的方法,并详细介绍了实现步骤,包括数据库准备、实体类、DAO层、Mapper和Controller层的代码示例。

一、 权限树的问题由来

  1. 在开发中难免遇到一个有多级菜单结构树,或者多级部门的结构树,亦或是省市区县的多级结构,数据结构类似如下的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",
         
Java实现递归查询树级菜单数据,通常涉及从数据库中获取扁平化的菜单列表,并将其转换为具有父子层级关系的树形结构。这种结构通常用于前端菜单展示、权限管理等功能中。以下是一个完整的实现思路和代码示例: ### 实体类定义 首先,定义一个菜单实体类,用于存储菜单项的基本信息以及子菜单列表: ```java public class Menu { private Long id; private String name; private Long parentId; private List<Menu> children = new ArrayList<>(); // 构造方法、getter 和 setter public Menu(Long id, String name, Long parentId) { this.id = id; this.name = name; this.parentId = parentId; } // getter 和 setter public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Long getParentId() { return parentId; } public void setParentId(Long parentId) { this.parentId = parentId; } public List<Menu> getChildren() { return children; } public void setChildren(List<Menu> children) { this.children = children; } } ``` ### 递归构建菜单树 接下来,编写递归方法来构建菜单树。该方法会遍历所有菜单项,并为每个菜单项查找其子菜单: ```java public class MenuTreeBuilder { public static List<Menu> buildMenuTree(List<Menu> menus) { List<Menu> rootMenus = new ArrayList<>(); // 构建父菜单映射 Map<Long, Menu> menuMap = new HashMap<>(); for (Menu menu : menus) { menuMap.put(menu.getId(), menu); } // 遍历菜单列表,构建树形结构 for (Menu menu : menus) { if (menu.getParentId() == null || menu.getParentId() == 0) { rootMenus.add(menu); } else { Menu parent = menuMap.get(menu.getParentId()); if (parent != null) { parent.getChildren().add(menu); } } } return rootMenus; } } ``` ### 递归查询子菜单 如果你希望使用递归方式动态查询每个菜单项的子菜单(例如从数据库中按需查询),可以参考以下方法: ```java public class MenuService { private List<Menu> allMenus; // 所有菜单列表 public MenuService(List<Menu> allMenus) { this.allMenus = allMenus; } public List<Menu> getChildMenus(Long parentId) { List<Menu> childMenus = new ArrayList<>(); for (Menu menu : allMenus) { if (menu.getParentId() != null && menu.getParentId().equals(parentId)) { List<Menu> children = getChildMenus(menu.getId()); menu.setChildren(children); childMenus.add(menu); } } return childMenus; } public List<Menu> buildMenuTree() { return getChildMenus(0L); // 假设根节点的parentId为0 } } ``` ### 使用示例 假设你已经从数据库中查询出所有菜单项,并将其封装为 `Menu` 对象列表: ```java List<Menu> menus = Arrays.asList( new Menu(1L, "首页", 0L), new Menu(2L, "用户管理", 0L), new Menu(3L, "角色管理", 0L), new Menu(4L, "用户列表", 2L), new Menu(5L, "用户权限", 2L), new Menu(6L, "角色列表", 3L) ); List<Menu> menuTree = MenuTreeBuilder.buildMenuTree(menus); // 打印菜单树 for (Menu menu : menuTree) { System.out.println(menu.getName()); printChildren(menu.getChildren(), 1); } private static void printChildren(List<Menu> children, int level) { for (Menu child : children) { for (int i = 0; i < level; i++) { System.out.print("--"); } System.out.println(child.getName()); printChildren(child.getChildren(), level + 1); } } ``` ### 总结 通过上述实现,可以轻松地将扁平化的菜单数据转换为具有层级结构的树形菜单。递归方法在处理菜单树时非常常见,尤其适用于菜单层级不确定或动态变化的场景。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值