三级分类之Stream的使用

参考

简介

在跟着尚硅谷学习谷粒商城中遇到这个三级分类问题,使用了Stream Api,记录一下

过程

主要内容就是对商品类别表进行三级分类,category表设计如下,主要关注,分类id,父分类id,排序这几个字段

category表

数据内容,这里只贴了30条,总1000条,随后在web上展示

表数据

了解了需求,CategoryEntity如下,关注新加入的非数据库字段属性List<CategoryEntity> children,用于存放该分类下的子分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@Data
@TableName("pms_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;

}

我们重点关注业务层,dao层使用的是Mybatis-Plus,不多介绍

就是在这里我们使用了Stream处理了从数据库查到的所有分类信息

处理过程:

  • 从数据库查到所有分类信息List<CategoryEntity>
  • 先查到所有的一级分类(parentCid为0的,从上面的数据内容也可看出来)
  • 接着从这些父分类,找到属于他的子分类(通过getChildren函数)
  • sorted根据sort字段升序排列
  • collect形成集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

...

@Override
public List<CategoryEntity> listWithTree() {
// 1、查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
// 2、组装树形结构

// 2.1、一级分类
List<CategoryEntity> level1Menu = entities.stream().filter((categoryEntity) ->
categoryEntity.getParentCid() == 0
).peek((menu) ->
menu.setChildren(getChildren(menu, entities))
).sorted(
Comparator.comparingInt(CategoryEntity::getSort)
).collect(Collectors.toList());
return level1Menu;
}

/**
* 递归查找所有菜单的子菜单
* @param root
* @param all
* @return
*/
private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {
List<CategoryEntity> children = all.stream().filter((categoryEntity ->
categoryEntity.getParentCid().equals(root.getCatId()))
).peek((categoryEntity ->
categoryEntity.setChildren(getChildren(categoryEntity, all)))
).sorted(
Comparator.comparingInt(CategoryEntity::getSort)
).collect(Collectors.toList());
return children;
}

...

}

最后web显示如下,我使用的JSONView插件,也可以用F12查看相关信息

返回的JSON数据

结果就是我们期望的结果,观察发现排序也正确,“手机”排在首位

思考

如果这个业务不使用Stream该怎么做,会有多复杂,从这里就可体会到Stream的强大

使用Stream,需要哪些知识?

首先作为JDK1.8的重点升级,JDK1.8的lambda表达式、函数式接口、链式编程都是重点

四大函数式接口

这些都可以直接搜源码看接口怎样设计的就明白怎么用了,下面我用白话概括一下

Function 函数式接口

传入一个参数,由这个参数返回值

Predicate 断言型接口

传入一个参数,由这个参数进行判断,返回布尔值

Consumer 消费型接口

传入一个参数,由这个参数进行处理,无返回

Supplier 供给型接口

无参数,返回一个值

回想

在使用Stream其实就是传入一些函数式接口,再结合使用lambda表达式就变得非常简便

想想但是学的使用体会还没有这么大,直到遇见了真的业务,感受就马上不同了

总结

此后,我终于能体会到一些算法题的业务场景了,还有JavaSE基础真的很重要,更多的得慢慢感受了