Java中List转Tree、List转化深林树、Tree转List

目录

一、简介

二、List转Tree

三、List转化深林树

四、Tree转List


一、简介

在我们业务需求中,有些业务要实现List转化TreeTree转化List,如:菜单权限、产品分类、数字字典等等!

 

举个栗子

业务需求:我们菜单权限需要树形化显示菜单层级关系

表结构如下

CREATE TABLE "sys_permission" (
  "id" bigint(20) NOT NULL AUTO_INCREMENT,
  "pid" bigint(20) DEFAULT NULL COMMENT '父级权限id',
  "name" varchar(100) DEFAULT NULL COMMENT '名称',
  "permission_value" varchar(200) DEFAULT NULL COMMENT '权限值',
  "icon" varchar(500) DEFAULT NULL COMMENT '图标',
  "type" int(1) DEFAULT NULL COMMENT '权限类型:0->目录;1->菜单;2->按钮(接口绑定权限)',
  "data_type" int(1) DEFAULT '0' COMMENT '权限数据类型:0->查看全部;1->查看自己数据权限',
  "url" varchar(200) DEFAULT NULL COMMENT '前端资源路径',
  "permission_status" int(1) NOT NULL DEFAULT '1' COMMENT '启用状态;0->启用;1->禁用',
  "sort" int(4) DEFAULT NULL COMMENT '排序',
  "create_time" datetime DEFAULT NULL COMMENT '创建时间',
  "create_user" varchar(100) DEFAULT NULL COMMENT '创建用户',
  "update_time" datetime DEFAULT NULL COMMENT '创建时间',
  "update_user" varchar(100) DEFAULT NULL COMMENT '创建用户',
  PRIMARY KEY ("id"),
  KEY "idx_pid" ("pid")
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8mb4 COMMENT='后台用户权限表';

二、List转Tree

1.controller层

需求:根据角色ID获取权限树

@RestController
@AllArgsConstructor
@RequestMapping("/permission")
@Api(value = "permission", tags = "权限模块")
public class PermissionController {

    private final PermissionService permissionService;

    @GetMapping("getPermissionTreeList")
    @ApiOperation(value = "获取树形权限列表", notes = "获取权限列表")
    public Result<List<PermissionTreeResp>> getPermissionTreeList(
            @RequestParam(value = "roleId") @ApiParam(name = "roleId", value = "角色ID") Long roleId
    ) {
        List<PermissionTreeResp> permissionResp = permissionService.getPermissionTreeList(roleId);
        return Result.success(permissionResp);
    }

    @PostMapping("savePermission")
    @ApiOperation(value = "保存权限", notes = "保存权限")
    public Result<List<PermissionTreeResp>> savePermission(@RequestBody @Validated PermissionTreeReq permissionTreeReq) {
        permissionService.savePermission(permissionTreeReq);
        return getPermissionTreeList(permissionTreeReq.getRoleId());
    }
}

2. PermissionServiceImpl接口实现层

实现思路

  1. 查询正常的权限列表;
  2. 把DTO转换成Entity,(如果你返回对象也是Entity就不用转换对象);
  3. 查询一级目录权限列表;
  4. 遍历一级权限列表,把一级权限ID等于所有权限Pid(父ID);
  5. 递归遍历;
@Override
    public List<PermissionTreeResp> getPermissionTreeList(Long roleId) {

        log.info("getPermissionTreeList.req roleId={}", roleId);
        Wrapper<Permission> wapper = new QueryWrapper<>(new Permission())
                .eq("permission_status", StatusEnum.NORMAL.getValue());
        List<Permission> permissionList = this.list(wapper);
        List<PermissionTreeResp> permissionTreeResps = new LinkedList<>();
        if (CollectionUtil.isNotEmpty(permissionList)) {
            List<PermissionTreeResp> permissionTreeList = BeanToUtils.entityToList(permissionList, PermissionTreeResp.class);
            // 查询一级目录
            permissionTreeResps = permissionTreeList.stream().filter(permission -> permission.getPid() == 0).collect(Collectors.toList());

            if (CollectionUtil.isNotEmpty(permissionTreeList)) {
                for (PermissionTreeResp permissionTreeResp : permissionTreeResps) {
                    permissionTreeResp.setChildren(getChildrenTree(permissionTreeResp, permissionTreeList));
                }
            }
        }
        // 降序排序
        permissionTreeResps = getPermissionSortedTree(permissionTreeResps);
        return permissionTreeResps;
    }


 /**
     * 递归遍历子树结构
     *
     * @param permissionTreeResp  父权限
     * @param permissionTreeResps 所有权限
     * @date: 2021/3/9 15:32
     * @return: java.util.List<com.zlp.dto.PermissionTreeResp>
     */
    private List<PermissionTreeResp> getChildrenTree(PermissionTreeResp permissionTreeResp, List<PermissionTreeResp> permissionTreeResps) {

        List<PermissionTreeResp> treeRespList;
        treeRespList = permissionTreeResps.stream().filter(permission -> permission.getPid().
                equals(permissionTreeResp.getId()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(treeRespList)) {
            for (PermissionTreeResp treeResp : treeRespList) {
                treeResp.setChildren(getChildrenTree(treeResp, permissionTreeResps));
            }
        }
        // 降序排序
        treeRespList = getPermissionSortedTree(treeRespList);
        return treeRespList;
    }

接口返回的数据

{
  "code": 200,
  "message": "操作成功",
  "data": [
    {
      "id": 1,
      "pid": 0,
      "name": "设备",
      "permissionValue": null,
      "type": 0,
      "dataType": 0,
      "sort": 1,
      "isHaveFlag": false,
      "children": [
        {
          "id": 5,
          "pid": 1,
          "name": "Co-Brain",
          "permissionValue": null,
          "type": 1,
          "dataType": 0,
          "sort": 1,
          "isHaveFlag": false,
          "children": [
            {
              "id": 12,
              "pid": 5,
              "name": "添加设备",
              "permissionValue": "equipment:add",
              "type": 2,
              "dataType": 0,
              "sort": 2,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 13,
              "pid": 5,
              "name": "删除设备",
              "permissionValue": "equipment:del",
              "type": 2,
              "dataType": 0,
              "sort": 3,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 15,
              "pid": 5,
              "name": "维修设置",
              "permissionValue": "equipment:repair",
              "type": 2,
              "dataType": 0,
              "sort": 5,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 16,
              "pid": 5,
              "name": "启用设备",
              "permissionValue": "equipment:enable",
              "type": 2,
              "dataType": 0,
              "sort": 6,
              "isHaveFlag": false,
              "children": []
            }
          ]
        }
      ]
    },
    {
      "id": 2,
      "pid": 0,
      "name": "客户",
      "permissionValue": null,
      "type": 0,
      "dataType": 0,
      "sort": 2,
      "isHaveFlag": false,
      "children": [
        {
          "id": 6,
          "pid": 2,
          "name": "机构管理",
          "permissionValue": null,
          "type": 1,
          "dataType": 0,
          "sort": 1,
          "isHaveFlag": false,
          "children": [
            {
              "id": 19,
              "pid": 6,
              "name": "添加机构",
              "permissionValue": "organ:add",
              "type": 2,
              "dataType": 0,
              "sort": 2,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 53,
              "pid": 6,
              "name": "添加机构",
              "permissionValue": "organ:add",
              "type": 2,
              "dataType": 1,
              "sort": 2,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 21,
              "pid": 6,
              "name": "编辑资料",
              "permissionValue": "organ:update",
              "type": 2,
              "dataType": 0,
              "sort": 4,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 55,
              "pid": 6,
              "name": "编辑资料",
              "permissionValue": "organ:update",
              "type": 2,
              "dataType": 1,
              "sort": 4,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 22,
              "pid": 6,
              "name": "创建协议",
              "permissionValue": "organ:createEquipment",
              "type": 2,
              "dataType": 0,
              "sort": 5,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 56,
              "pid": 6,
              "name": "创建协议",
              "permissionValue": "organ:createEquipment",
              "type": 2,
              "dataType": 1,
              "sort": 5,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 24,
              "pid": 6,
              "name": "编辑协议",
              "permissionValue": "organ:agreement:update",
              "type": 2,
              "dataType": 0,
              "sort": 7,
              "isHaveFlag": false,
              "children": []
            },
            {
              "id": 58,
              "pid": 6,
              "name": "编辑协议",
              "permissionValue": "organ:agreement:update",
              "type": 2,
              "dataType": 1,
              "sort": 7,
              "isHaveFlag": false,
              "children": []
            }
          ]
        },
        {
          "id": 7,
          "pid": 2,
          "name": "机构审核",
          "permissionValue": null,
          "type": 1,
          "dataType": 0,
          "sort": 2,
          "isHaveFlag": false,
          "children": []
        }
      ]
    },
    {
      "id": 3,
      "pid": 0,
      "name": "客户账号",
      "permissionValue": null,
      "type": 0,
      "dataType": 0,
      "sort": 3,
      "isHaveFlag": false,
      "children": [
        {
          "id": 8,
          "pid": 3,
          "name": "账号管理",
          "permissionValue": null,
          "type": 1,
          "dataType": 0,
          "sort": 1,
          "isHaveFlag": false,
          "children": []
        }
      ]
    }
  ]
}

三、List转化深林树

1. INode 接口

把共同方法抽离出来

public interface INode {

	/**
	 * 主键
	 *
	 * @return
	 */
	Long getId();

	/**
	 * 排序 1,2,3,4 (从小到大排序)
	 *
	 * @return
	 */
	Integer getSort();

	/**
	 * 父主键
	 *
	 * @return
	 */
	Long getPid();

	/**
	 * 子孙节点
	 *
	 * @return
	 */
	List<INode> getChildren();

}

 2. ForestNodeManager

/**
 * 森林管理类
 *
 */
public class ForestNodeManager<T extends INode> {

	/**
	 * 森林的所有节点
	 */
	private List<T> list;

	/**
	 * 森林的父节点ID
	 */
	private List<Long> parentIds = new ArrayList<>();

	public ForestNodeManager(List<T> items) {
		list = items;
	}

	/**
	 * 根据节点ID获取一个节点
	 *
	 * @param id 节点ID
	 * @return 对应的节点对象
	 */
	public INode getTreeNodeAT(Long id) {
		for (INode forestNode : list) {
			if (forestNode.getId().longValue() == id.longValue()) {
				return forestNode;
			}
		}
		return null;
	}

	/**
	 * 增加父节点ID
	 *
	 * @param parentId
	 */
	public void addParentId(Long parentId) {
		parentIds.add(parentId);
	}

	/**
	 * 获取树的根节点(一个森林对应多颗树)
	 *
	 * @return 树的根节点集合
	 */
	public List<T> getRoot() {
		List<T> roots = new ArrayList<>();
		for (T forestNode : list) {
			if (forestNode.getPid() == 0 || parentIds.contains(forestNode.getId())) {
				roots.add(forestNode);
			}
		}
		return roots;
	}

}

3. ForestNodeMerger

/**
 * 森林节点归并类
 *
 */
public class ForestNodeMerger {

	/**
	 * 将节点数组归并为一个森林(多棵树)(填充节点的children域)
	 * 时间复杂度为O(n^2)
	 *
	 * @param items 节点域
	 * @return 多棵树的根节点集合
	 */
	public static <T extends INode> List<T> merge(List<T> items) {
		ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
		items.forEach(forestNode -> {
			if (forestNode.getPid() != 0) {
				// 获取父节点
				INode node = forestNodeManager.getTreeNodeAT(forestNode.getPid());
				if (node != null) {
					node.getChildren().add(forestNode);
				} else {
					forestNodeManager.addParentId(forestNode.getId());
				}
			}
		});
		List<T> root = forestNodeManager.getRoot();
		return root.stream().sorted(Comparator.comparing(T::getSort)).collect(Collectors.toList());
	}

}

4. PermissionForestTree实体类

实现INode接口,实现getChildren方法

@Data
@ApiModel(value = "权限树形返回信息")
public class PermissionForestTree implements INode {


    @ApiModelProperty(value = "ID")
    private Long id;

    @ApiModelProperty(value = "父级权限id")
    private Long pid;

    @ApiModelProperty(value = "权限名称")
    private String name;

    @ApiModelProperty(value = "按钮权限值")
    private String permissionValue;

    @ApiModelProperty(value = "权限类型:0->目录;1->菜单;2->按钮(接口绑定权限)")
    private Integer type;

    @ApiModelProperty(value = "权限操作类型 0->查看全部按钮权限值; 1->查看自己数据权限按钮权限值")
    private Integer dataType;

    @ApiModelProperty(value = "排序 1,2,3,4 (从小到大排序)")
    private Integer sort;

    @ApiModelProperty(value = "是否拥有权限标识:false->否 ; ture->是")
    private Boolean isHaveFlag = false;

    @ApiModelProperty(value = "子孙节点")
    private List<INode> children ;

    @Override
    public List<INode> getChildren() {
        if (this.children == null) {
            this.children = new ArrayList<>();
        }
        return this.children;
    }

}

5. 调用ForestNodeMerger.merge转化深林树

 @GetMapping("getPermissionForestTreeList")
    @ApiOperation(value = "获取深林树形权限列表", notes = "获取深林树形权限列表")
    public Result<List<PermissionForestTree>> getPermissionForestTreeList(
            @RequestParam(value = "roleId") @ApiParam(name = "roleId", value = "角色ID") Long roleId
    ) {
        List<PermissionForestTree> permissionForestTrees = permissionService.getPermissionForestTreeList(roleId);
        return Result.success(ForestNodeMerger.merge(permissionForestTrees));
    }

 

四、Tree转List

需求修改权限,跟前端妹子协商好参数,也是通过树形化传给后台

实现思路

  1. 获取前端传给的树形列表;
  2. 定义一个空的List用来添加权限列表
  3. 把一级目录权限添加都List集合
  4. 在判断有子孙节点是否有元素
  5. 递归遍历子孙节点添加List集合
@Override
    public Boolean savePermission(PermissionTreeReq permissionTreeReq) {

        log.info("savePermission.req permissionTreeReq={}", JSON.toJSONString(permissionTreeReq));
        List<PermissionTreeResp> permissionRespList = new LinkedList<>();
        List<PermissionTreeResp> permissionTreeList = permissionTreeReq.getPermissionTreeResps();
        // 树转化成List
        treeToList(permissionRespList, permissionTreeList);
        log.info("treeToList={}",JSON.toJSONString(permissionRespList));
        return Boolean.TRUE;
    }
    /**
     * 数转换成List
     * @param permissionRespList
     * @param permissionTreeList
     * @date: 2021/3/9 22:23
     * @return: void
     */
    private void treeToList(List<PermissionTreeResp> permissionRespList, List<PermissionTreeResp> permissionTreeList) {
        
        for (PermissionTreeResp permissionTreeResp : permissionTreeList) {
            permissionRespList.add(permissionTreeResp);
            if (CollectionUtil.isNotEmpty(permissionTreeResp.getChildren())) {
                treeToList(permissionRespList,permissionTreeResp.getChildren());
            }
        }
    }

 

感谢大家看到最后,如文章有不足,欢迎大家在评论区支持,给予意见。如果觉得我的文章对你有帮助,那就给我一个赞同吧!

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值