电商项目——如何查出所有三级分类,并以树形结构组装起来?

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
在这里插入图片描述
进行验证是否可以查询三级分类的数据
在这里插入图片描述


版权声明:本文为qq_44891295原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。