本文介绍如何从数据库中读取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树结构数据后,解析渲染后展示效果如下: