遞歸查詢子分類
電商平台比如京東和淘寶中,商品一般分三級菜單。要想實現一個接口查詢一個商品的分類及其子分類信息,需要使用到遞歸查詢。
數據表中的記錄都是單條並且沒有層級的,要想描述各個記錄之間的層級父子關系,一般會設計一個 parentId
字段。
CREATE TABLE `t_category` (
`cat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分類id',
`name` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分類名稱',
`parent_cid` bigint(20) NULL DEFAULT NULL COMMENT '父分類id',
`cat_level` int(11) NULL DEFAULT NULL COMMENT '層級',
`show_status` tinyint(4) NULL DEFAULT NULL COMMENT '是否顯示[0-不顯示,1顯示]',
`sort` int(11) NULL DEFAULT NULL COMMENT '排序',
`icon` char(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '圖標地址',
`product_unit` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '計量單位',
`product_count` int(11) NULL DEFAULT NULL COMMENT '商品數量',
PRIMARY KEY (`cat_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1433 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品三級分類' ROW_FORMAT = Dynamic;
數據:
下面簡述查詢所有商品分類及其子分類的接口。
實體類:CategoryEntity
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.Data;
@Data
@TableName("t_category")
public class CategoryEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 分類id
*/
@TableId
private Long catId;
/**
* 分類名稱
*/
private String name;
/**
* 父分類id
*/
private Long parentCid;
/**
* 層級
*/
private Integer catLevel;
/**
* 是否顯示[0-不顯示,1顯示]
*/
private Integer showStatus;
/**
* 排序
*/
private Integer sort;
/**
* 圖標地址
*/
private String icon;
/**
* 計量單位
*/
private String productUnit;
/**
* 商品數量
*/
private Integer productCount;
@TableField(exist = false)
private List<CategoryEntity> children;
}
為了表示子菜單,這里添加一個數據表中不存在的字段 children
,並且使用注解標識。
接口:
/**
* 查出所有分類以及子分類,以樹形結構組裝起來
*/
public List<CategoryEntity> listWithTree() {
// 1. 查出所有分類
List<CategoryEntity> entities = baseMapper.selectList(null);
// 2. 組裝成父子的樹形結構
// 2.1 找到所有的一級分類
List<CategoryEntity> level1Menus = entities.stream().filter(categoryEntity ->
categoryEntity.getParentCid() == 0
).map(menu -> {
// 2.2 設置子菜單
menu.setChildren(getChildren(menu, entities));
return menu;
// 2.3 排序
}).sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
.collect(Collectors.toList());
return level1Menus;
}
/**
* 遞歸查找所有菜單的子菜單
*/
private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {
List<CategoryEntity> children = all.stream().filter(categoryEntity ->
categoryEntity.getParentCid() == root.getCatId()
).map(categoryEntity -> {
// 1. 找到子菜單
categoryEntity.setChildren(getChildren(categoryEntity, all));
return categoryEntity;
}).sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort()))).collect(Collectors.toList());
return children;
}
前端數據效果:
這個模型有遞歸查詢的接口中經常用到。