1:查出所有三级分类,并以树形结构组装起来
三级分类(电商里面经常用到的功能):所有的数据都是来源于数据库,我们要对三级分类进行维护,进行增删改查,我们首先就必须要后台管理系统来可以维护我们的整个数据。所以我们引出了下面的问题,解决了下面问题,我们就可以在搭建前端界面进行前后端连接
问题:如何查出所有三级分类以及子分类,并以树形结构组装起来?,我们看下面的思路分析
1.1 思路分析
思路:
- 首先我们要明确一点使用java8新特性Stream来完成如上操作,我们要先查询出所有三级分类并创建一个集合流,返回CategoryEntity的List
List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
List<CategoryEntity> collect = categoryEntities.stream()
接着调用filter方法过滤出它的一级分类
filter方法的部分代码片段
List<CategoryEntity> level1Menu = entities.stream().filter( categoryEntity ->
categoryEntity.getParentCid() == 0
)
- 然后在CategoryEntity类中设置一个如下属性
CategoryEntity类的部分代码片段
private List< CategoryEntity > children;(代码含义:包含所有分类的子分类),
- 接着我们继续用流中的map方法设置我们的子分类
map方法的部分代码片段
//1:查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
//2:组装成父子的树形结构
List<CategoryEntity> level1Menu = entities.stream().filter( categoryEntity ->
categoryEntity.getParentCid() == 0
).map( (menu) -> {
menu.setChildren(getChildren(menu,entities));
return menu;
})(代码含义:用我们写好的getChildren方法来帮我们找到子分类,并设置)
- 最后调用sorted方法进行排序和collect方法例如将流转换成集合和聚合元素
//1:查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
//2:组装成父子的树形结构
List<CategoryEntity> level1Menu = entities.stream().filter( categoryEntity ->
categoryEntity.getParentCid() == 0
).map( (menu) -> {
menu.setChildren(getChildren(menu,entities));
return menu;
}).sorted((menu1,menu2)->{
// return menu1.getSort()-menu2.getSort();//为了防止空指针异常
return ((menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort()));
}).collect(Collectors.toList());
- 一个小问题:map中的getChildren(menu,entities)方法怎么写?
该方法的目的是继续找到一级分类下的二级分类,三级分类,
我们要传入两个参数如下
private List<CategoryEntity> getChildren(CategoryEntity root,List<CategoryEntity> all){
思路:
- 我们使用all创建一个数据流,然后调用filter方法进行过滤
filter方法的部分代码片段
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
//让当前菜单(categoryEntity)的parentcid等于我们指定菜单(root)的catid,说明当前菜单就是它的子菜单
return categoryEntity.getParentCid() == root.getCatId();
})
- 如果上面操作完成,说明我们一二级分类都找到了,那三级分类怎么办呢?
我们就继续使用all流中的map方法,进行递归调用
map方法的部分代码片段
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
//让当前菜单(categoryEntity)的parentcid等于我们指定菜单(root)的catid,说明当前菜单就是它的子菜单
return categoryEntity.getParentCid() == root.getCatId();
}).map(categoryEntity->{
//1:继续找到二级分类的子菜单
categoryEntity.setChildren(getChildren(categoryEntity,all));
return categoryEntity;
})
- 然后在进行sort方法调用,collect方法调用,就可以完成三级分类以树形结构组装起来
代码如下
/**
* collect整个菜单就是我们要用的子菜单,但是每个子菜单还是会有可有子菜单
*/
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
//让当前菜单(categoryEntity)的parentcid等于我们指定菜单(root)的catid,说明当前菜单就是它的子菜单
return categoryEntity.getParentCid() == root.getCatId();
}).map(categoryEntity->{
//1:继续找到子菜单
categoryEntity.setChildren(getChildren(categoryEntity,all));
return categoryEntity;
}).sorted((menu1,menu2)->{
//2:进行排序
// return menu1.getSort()-menu2.getSort();
return ((menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort()));
}).collect(Collectors.toList());
完整的代码版演示后面有
1.2 完整的代码演示
第一步:将三级分类数据导入到如下的数据库的表中
第二步:我们来编写第一个功能,一次性查出它的所有分类和子分类,并将他们以父子方式的结构组装起来,方便后台管理系统进行维护
我们先编写查询到全部三级分类的数据代码
CategoryController.java
public class CategoryController {
@Autowired
private CategoryService categoryService;
/**
* 查出所有三级分类以及子分类,并以树形结构组装起来
*/
@RequestMapping("/list/tree")
public R list(){
List<CategoryEntity> entities =categoryService.listWithTree();
return R.ok().put("data", entities);
}
CategoryServiceImpl.java
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
@Override
public List<CategoryEntity> listWithTree() {
//1:查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
return entities;
}
}
启动mall-product
访问http://localhost:30000/product/category/list/tree
现在我们继续完成把三级分类的数据组装成父子结构
按照1.1的思路
先完成查找到了一级分类的数据的代码
CategoryServiceImpl
@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
).collect(Collectors.toList());
return level1Menu;
}
}
测试
http://localhost:30000/product/category/list/tree
接下来我们再来找到每一个分类的子分类,要找到子分类,那希望在mall-product中的CategoryEntity中多写一个属性
@Data
@TableName("pms_category")
public class CategoryEntity implements Serializable {
//..
//这一个字段含义:包含所有分类的子分类
//表示不是数据表里的字段
@TableField(exist = false)
private List<CategoryEntity> children;
成功查找到三级分类的数据的代码完整版演示如下
@Override
/**
* java8新特性
* sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
* Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
filter
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
*/
public List<CategoryEntity> listWithTree() {
//1:查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
//2:组装成父子的树形结构
List<CategoryEntity> level1Menu = entities.stream().filter( categoryEntity ->
categoryEntity.getParentCid() == 0
).map( (menu) -> {
menu.setChildren(getChildren(menu,entities));
return menu;
}).sorted((menu1,menu2)->{
// return menu1.getSort()-menu2.getSort();//为了防止空指针异常
return ((menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort()));
}).collect(Collectors.toList());
return level1Menu;
}
/**
* 所有的子菜单在哪里,我们可以写一个递归的方法,来找到每一个菜单的子菜单
* 我们写一个方法:获取某一个菜单的子菜单,(递归查找所有一级菜单的子菜单)
*/
private List<CategoryEntity> getChildren(CategoryEntity root,List<CategoryEntity> all){
/**
* collect整个菜单就是我们要用的子菜单,但是每个子菜单还是会有可有子菜单
*/
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
//让当前菜单(categoryEntity)的parentcid等于我们指定菜单(root)的catid,说明当前菜单就是它的子菜单
return categoryEntity.getParentCid() == root.getCatId();
}).map(categoryEntity->{
//1:继续找到子菜单
categoryEntity.setChildren(getChildren(categoryEntity,all));
return categoryEntity;
}).sorted((menu1,menu2)->{
//2:进行排序
// return menu1.getSort()-menu2.getSort();
return ((menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort()));
}).collect(Collectors.toList());
return children;
}
注意:我们第一次启动mall-product
访问http://localhost:30000/product/category/list/tree的时候会报一个空指针异常,原因就是CategoryEntity类中的sort字段在没赋值时为null,
所以我们在代码中做如下修改
//...
//2:进行排序
// return menu1.getSort()-menu2.getSort();
return ((menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort()));
//..
在进行访问http://localhost:30000/product/category/list/tree
进行验证是否可以查询三级分类的数据