应用场景
1.京东
京东的页面就是这么显示的在家用电器下面有电视.空调.洗衣机然后再电视下面又有全面屏电视.教育电视等等
2.我们的后端管理系统
我们后端在页面上显示的很多也是通过层级目录的显示出来。
如何实现
1.准备数据库
我们这里parent_cid为0的为我们的一级菜单
2. 准备我们的实体类
注意我们需要编写一个List集合来放我们的二级集合,泛型为当前类
(实体类字段对应数据库字段即可,乱码是因为使用代码生成器,可能编码没有设置好)
注意:需要加上@TableField(exist = false) 代表数据库没有这个字段,不然会报错
3.编写controller
4.编写service方法,代码逻辑
package com.atguigu.gulimall.product.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.gulimall.product.dao.CategoryDao;
import com.atguigu.gulimall.product.entity.CategoryEntity;
import com.atguigu.gulimall.product.service.CategoryService;
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
@Override
public PageUtils queryPage(Map<String, Object> params) {
IPage<CategoryEntity> page = this.page(
new Query<CategoryEntity>().getPage(params),
new QueryWrapper<CategoryEntity>()
);
return new PageUtils(page);
}
@Override
public List<CategoryEntity> listWithTree() {
//查询出所有的分类
List<CategoryEntity> entities = baseMapper.selectList(null);
//2.组装成父子的树形结构
//2.1找到所有的一级分类
/**
List<CategoryEntity> level1Menus = entities.stream().filter((categoryEntity) -> {
return categoryEntity.getParentCid() == 0;
}).map((menu) -> {
menu.setChildren(getChildrens(menu, entities));
return menu;
}).sorted((menu1, menu2) -> {
return (menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort());
}).collect(Collectors.toList());
*
* 这段的代码的意思为调用了stream的filter过滤方法把查询出来getParentCid==0的数 因为这些都是我们的一级菜单
* 然后查询还要查询出我们一级菜单下的二级菜单调用stream流下的map将我们的返回值重新改变一下在返回,这样把我们查询的数据set到我们的Children里面我们的Children为一个
* list集合,我们二级菜单的数据哪里来呢,我们就可以编写一个方法采用递归的方法查询出我们的二级菜单,我们二级菜单下面还有三级菜单
*
*/
List<CategoryEntity> level1Menus = entities.stream().filter((categoryEntity) -> {
return categoryEntity.getParentCid() == 0;
}).map((menu) -> {
//menu当前菜单在entities找下一个菜单
menu.setChildren(getChildrens(menu, entities));
return menu;
}).sorted((menu1, menu2) -> {
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
/**2.2查出我们的一级菜单下的子菜单 我们需要在实体类中编写一个list集合放我们的子菜单,因为
一个一级菜单下面可以有多个二级菜单
*/
System.out.println(level1Menus);
return level1Menus;
}
//递归查出所有的菜单的子菜单
/**
* @param root 为当前菜单
* @param all 所有的菜单
* @return
* 首先调用stream的方法过滤一下 判断当前菜单的父id是否等于当前菜单的这个id。如果相同这个菜单就是这个id下的子菜单
* 我们就调用map方法改变我们的返回值修改一下在重新返回,
* map方法的作用为调用自己查询出下一级菜单 因为我们二级菜单下面可能有三级菜单或者四级菜单
*/
private List<CategoryEntity> getChildrens(CategoryEntity root, List<CategoryEntity> all) {
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid() == root.getCatId();
}).map(categoryEntity -> {
//还是调用这个setChildren方法添加我们的子菜单 参数为categoryEntity为当前的菜单找,在所有菜单中找到所有的子菜单
//categoryEntity的意思 如果当前菜单为二级菜单就调用这个方法查询这个二级菜单下的子菜单
categoryEntity.setChildren(getChildrens(categoryEntity, all));
return categoryEntity;
}).sorted((menu1, menu2) -> {
//菜单的排序
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return children;
}
}
注意我们这里使用到了jdk8中的stream
stream中的filter方法为过滤里面可以加条件
stream中的map方法为把我们返回的数据重新改变一下在返回可以set一些新的值返回
stream中的sorted方法为把查询出的数据以那种方式排序
stream.collect(Collectors.toList())为把查询出的数据已list集合返回