目的:我们要查一个菜单,菜单有个parent_id字段,可以绑定父级餐单,我们想让他展示层树的形态返回数据。即下图
- {
- "menuId": 0,
- "menuName": "首页",
- "permissions": [
- {
- "menuId": 40,
- "menuName": "游戏管理",
- "parentId": 0,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 41,
- "menuName": "游戏基本信息",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 42,
- "menuName": "游戏客户端",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 43,
- "menuName": "游戏更新",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 66,
- "menuName": "游戏白名单列表",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 79,
- "menuName": "游戏数据",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 83,
- "menuName": "留存数据",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 85,
- "menuName": "测试白名单",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 89,
- "menuName": "双端互通",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 115,
- "menuName": "游戏公告",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 120,
- "menuName": "游戏Ltv",
- "parentId": 40,
- "isSelected": 1
- },
- {
- "menuId": 129,
- "menuName": "游戏Ltv",
- "parentId": 40,
- "isSelected": 1
- }
- ]
- },
- {
- "menuId": 44,
- "menuName": "用户管理",
- "parentId": 0,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 45,
- "menuName": "用户详情",
- "parentId": 44,
- "isSelected": 1
- },
- {
- "menuId": 46,
- "menuName": "用户日志",
- "parentId": 44,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 48,
- "menuName": "用户行为日志",
- "parentId": 46,
- "isSelected": 1
- },
- {
- "menuId": 49,
- "menuName": "用户设备日志",
- "parentId": 46,
- "isSelected": 1
- }
- ]
- }
- ]
- },
- {
- "menuId": 50,
- "menuName": "消费管理",
- "parentId": 0,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 51,
- "menuName": "订单管理",
- "parentId": 50,
- "isSelected": 1
- },
- {
- "menuId": 64,
- "menuName": "商品管理",
- "parentId": 50,
- "isSelected": 1
- }
- ]
- },
- {
- "menuId": 59,
- "menuName": "通用管理",
- "parentId": 0,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 60,
- "menuName": "全局配置",
- "parentId": 59,
- "isSelected": 1
- },
- {
- "menuId": 61,
- "menuName": "系统配置",
- "parentId": 59,
- "isSelected": 1
- },
- {
- "menuId": 62,
- "menuName": "权限管理",
- "parentId": 59,
- "isSelected": 1
- },
- {
- "menuId": 122,
- "menuName": "角色管理",
- "parentId": 59,
- "isSelected": 1
- }
- ]
- },
- {
- "menuId": 97,
- "menuName": "官网管理",
- "parentId": 0,
- "isSelected": 1,
- "permissions": [
- {
- "menuId": 98,
- "menuName": "官网游戏管理",
- "parentId": 97,
- "isSelected": 1
- },
- {
- "menuId": 99,
- "menuName": "礼包管理",
- "parentId": 97,
- "isSelected": 1
- }
- ]
- }
- ]
- }
解决方法:
1.数据库查询出的结果就具有层级结构,通过写数据库语句实现
SQL 层级查询(一) - 腾讯云开发者社区-腾讯云 (tencent.com)
2.我们将查询出来的数据进行改装,通过java代码的形式,使其变成层级结构
第一步,数据库语句查询
可以看到,我们的菜单都有个父级菜单字段,我们除了查询餐单id,菜单名称,还要把父级id查询出来
第二步,写个DTO类,用于存数据,DTO类需要有个List<自己>的字段
第三步,编写数据转为树形结构Java代码
- /**
- * 将数据库中的菜单转换为树形结构
- *
- * @param permissionDOs 系统菜单
- * @return 树形结构
- *
- */
- public static PermissionDTO getMenuTreeByRole(List
permissionDOs) { - Map
> systemMenuMap = permissionDOs.stream() - .collect(Collectors.groupingBy(PermissionDTO::getParentId));
- PermissionDTO permissionDTO = new PermissionDTO();
- permissionDTO.setMenuId(0);
- permissionDTO.setMenuName("首页");
- listToTreeByRole(systemMenuMap, permissionDTO);
- return permissionDTO;
- }
-
- /**
- * 将列表转换为树形结构
- *
- * @param collect 列表
- * @param permissionDTO 角色权限
- */
- private static void listToTreeByRole(Map
> collect, PermissionDTO permissionDTO) { - List
treeMenuNodes = collect.get(permissionDTO.getMenuId()); - if (!CollectionUtils.isEmpty(treeMenuNodes)) {
- List
permissions = new ArrayList<>(); - BeanCopyUtil.copyColl(treeMenuNodes, permissions, PermissionDTO.class);
- permissionDTO.setPermissions(permissions);
- permissionDTO.getPermissions().forEach(t -> listToTreeByRole(collect, t));
- }
- }
方法解读:
1.首先,我们将得到的数据库数据通过parent_id进行分组,即map结构,key为parent_id,value为组成员
2.设置第一级菜单,即没有父级菜单id为0的,调用递归方法listToTreeByRole,设置他的自己菜单
3.递归方法第一步,即通过当前菜单id,从我们的map中获取其子菜单(前面我们的map分过组了,所以我们可以很容易的得到当前key下的子菜单)
4.子菜单不为空,就把子菜单绑定到当前菜单对象的下面
5.递归,对子菜单执行操作
6.结果
得到一个PermissionDTO对象
递归结构: