Java将List列表转换为Tree树结构的方法

        本文介绍如何从数据库中读取List列表数据并将其转换为Tree树结构数据。从而可以完整展现其中的层级关系。

1、表结构

        本次以商品分类为例,表结构设计支持多级商品分类,理论上可以无限向下创建下级分类。一般二级分类或三级分类就可以满足平时日常需要。

# 商品分类
create table goods_category
(
   id                   bigint(20) not null,
   name                 varchar(20) character set utf8 comment '名称',
   lv                   int(10) default -1 comment '层级',
   pid                  bigint(20) default -1 comment '上级编号',
   sort_no              int(10) default -1 comment '顺序号',
   remark               varchar(256) character set utf8,
   state                tinyint comment '状态【0:禁用  1:启用】',
   create_id            bigint(20) default NULL comment '创建人ID',
   create_name          varchar(50) character set utf8 comment '创建人',
   create_time          datetime default NULL comment '创建时间',
   update_id            bigint(20) default NULL comment '更新人ID',
   update_name          varchar(50) comment '更新人',
   update_time          datetime default NULL comment '更新时间',
   primary key (id)
)

2、表数据

        为演示代码执行效果,模拟实际业务插入多条测试商品分类的测试数据用来验证。SQL执行脚本如下:

-- ----------------------------
-- Records of goods_category
-- ----------------------------
INSERT INTO `goods_category` VALUES (1596020641453182976, '电子产品', 1, 0, 1, '接口修改备注', 1, 1513792719871414272, '卓医生', '2022-11-25 13:59:08', 1513792719871414272, '卓医生', '2022-12-15 15:16:48');
INSERT INTO `goods_category` VALUES (1596021690557665280, '衣帽服饰', 1, 0, 0, '备注2', 0, 1513792719871414272, '卓医生', '2022-11-25 14:03:18', 1513792719871414272, '卓医生', '2022-12-10 09:21:04');
INSERT INTO `goods_category` VALUES (1596332421178068992, '生活用品', 1, 0, 2, NULL, 1, 1511553737313882112, '卓瑞-县医生', '2022-11-26 10:38:02', 1513792719871414272, '卓医生', '2022-11-28 10:22:38');
INSERT INTO `goods_category` VALUES (1596385737597652992, '个人清洁', 2, 1596332421178068992, 1, NULL, 1, 1513792719871414272, '卓医生', '2022-11-26 14:09:54', 1141701653246906368, 'admin', '2022-12-06 15:49:44');
INSERT INTO `goods_category` VALUES (1596390126764822528, '女装', 2, 1596021690557665280, 1, '温馨提示\n·支持7天无理由退货\n人气配件 手机贴膜手机壳移动电源直插充电器耳机 \n更多\n荣耀X30 骁龙6nm疾速5G芯 66W超级快充 120Hz全视屏 全网通版 8GB+256GB 魅海蓝\n荣耀X30 骁龙6nm疾速5G芯 66W超级快充 120Hz全视屏 全网通版 8GB+256GB 魅海蓝\n+\n\n梵帝西诺【两片装-贴坏包赔】 荣耀X30水凝膜 高清防刮曲面全覆盖 荣耀x30手机保护贴膜', 1, 1511553737313882112, '卓瑞-县医生', '2022-11-26 14:27:20', 1141701653246906368, 'admin', '2022-12-06 15:47:23');
INSERT INTO `goods_category` VALUES (1596390287658323968, '手机', 2, 1596020641453182976, 1, NULL, 1, 1511553737313882112, '卓瑞-县医生', '2022-11-26 14:27:59', 1141701653246906368, 'admin', '2022-12-06 15:50:03');
INSERT INTO `goods_category` VALUES (1596390607767605248, '厨房清洁', 2, 1596332421178068992, 2, NULL, 0, 1511553737313882112, '卓瑞-县医生', '2022-11-26 14:29:15', 1513792719871414272, '卓医生', '2022-12-07 09:17:54');
INSERT INTO `goods_category` VALUES (1598154739474894848, '电脑', 2, 1596020641453182976, 2, NULL, 1, 1513792719871414272, '卓医生', '2022-12-01 11:19:17', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1598154804796985344, '男装', 2, 1596021690557665280, 2, NULL, 1, 1513792719871414272, '卓医生', '2022-12-01 11:19:32', 1141701653246906368, 'admin', '2022-12-12 15:43:21');
INSERT INTO `goods_category` VALUES (1598217708242079744, '美妆护肤', 1, 0, 4, NULL, 1, 1513792719871414272, '卓医生', '2022-12-01 15:29:30', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1599678464963776512, '鞋类', 1, 0, 5, NULL, 0, 1513792719871414272, '卓医生', '2022-12-05 16:14:01', 1513792719871414272, '卓医生', '2022-12-08 15:08:57');
INSERT INTO `goods_category` VALUES (1599678513273769984, '高跟鞋', 2, 1599678464963776512, 1, NULL, 1, 1513792719871414272, '卓医生', '2022-12-05 16:14:13', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1599678545406332928, '运动鞋', 2, 1599678464963776512, 2, NULL, 1, 1513792719871414272, '卓医生', '2022-12-05 16:14:20', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1599678606177603584, '平板帆布鞋', 2, 1599678464963776512, 3, NULL, 1, 1513792719871414272, '卓医生', '2022-12-05 16:14:35', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1599678655439704064, '马丁靴鞋', 2, 1599678464963776512, 4, NULL, 1, 1513792719871414272, '卓医生', '2022-12-05 16:14:47', NULL, NULL, NULL);
INSERT INTO `goods_category` VALUES (1599953632688738304, '生活百货', 1, 0, 3, '', 1, 1513792719871414272, '卓医生', '2022-12-06 10:27:26', 1513792719871414272, '卓医生', '2022-12-06 17:19:00');

        执行SQL脚本后,实际插入的数据效果如下:

 3、将list列表转换为Tree树结构

        从数据库中查询出来的数据是多条记录的列表,业务需要是展示多级树结构。执行转换代码如下:

/**
 * @Description: 查询商品分类树数据
 * @Author: knight
 * @Date: 2022/12/12 13:58
 */
@Override
public List<Map<String, Object>> getTreeData(Map<String, Object> map) {
    PageMethod.orderBy("pid, sort_no");
    List<GoodsCategory> list = getList(map);
    if(list == null || list.isEmpty()){
        return new ArrayList<>();
    }

    return listToTree(list, 0L);
}
/**
 * @Description: 将 list 转换为 树
 * @Author: knight
 * @Date: 2022/11/30 18:03
 */
public List<Map<String, Object>> listToTree(List<GoodsCategory> list, Long pId ) {
    final String STR_CHILDREN = "children";
    //空间换时间,所需要的空间
    HashMap<Object, Map<String, Object>> tempMap = new HashMap<>(list.size());
    //最顶层的根节点
    List<Map<String, Object>> rootList = new ArrayList<>();

    for (GoodsCategory node : list) {
        //当前节点名称
        Long id = node.getId();
        //父节点名称
        Long parentid = node.getPid();
        //处理当前节点,可能先处理父节点时,已经把该节点挂载子节点了,如果没有的话就新建一个
        Map<String, Object> packageBody = tempMap.getOrDefault(id, new HashMap<>());
        Map<String, Object> current = BeanUtil.beanToMap(node);
        //把之前添加的children信息拿过来,挂载到现在的node下。putIfAbsent
        current.putIfAbsent(STR_CHILDREN, packageBody.getOrDefault(STR_CHILDREN, new ArrayList<>()));
        tempMap.put(id, current);
        //处理顶级节点,parentid为null的情况下,为顶级节点
        if (parentid.equals(pId)) {
            rootList.add(current);
        } else {
            //把当前节点挂到父节点下
            //获取父节点,父节点不存在就先初始化一个
            Map<String, Object> parent = tempMap.getOrDefault(parentid, new HashMap<>());
            //父节点为空情况
            //1 还没处理到:创建一个, 2 没有父节点的子节点,坏的数据,丢进去,最后不会被挂到根节点下
            ArrayList<Map<String, Object>> children = (ArrayList) parent.getOrDefault(STR_CHILDREN, new ArrayList());
            parent.put("children", children);
            //把当前节点挂载到父节点下
            children.add(current);
            //把父节点也挂到map中放到节点下
            tempMap.put(parentid, parent);
        }
    }
    return rootList;
}

4、数据验证

        将list列表转换后的Tree树结构数据后的数据格式如下:

        前端在接收到Tree树结构数据后,解析渲染后展示效果如下: 


新时代农民工  

猜你喜欢

转载自blog.csdn.net/sg_knight/article/details/128331125