如何查询多级菜单(采用递归的方法)

应用场景
1.京东
京东的页面就是这么显示的在家用电器下面有电视.空调.洗衣机然后再电视下面又有全面屏电视.教育电视等等
在这里插入图片描述

2.我们的后端管理系统
我们后端在页面上显示的很多也是通过层级目录的显示出来。
如何实现

1.准备数据库

我们这里parent_id为0的为我们的一级菜单
在这里插入图片描述

2. 准备我们的实体类

注意我们需要编写一个List集合来放我们的二级集合,泛型为当前类
(实体类字段对应数据库字段即可,乱码是因为使用代码生成器,可能编码没有设置好)
注意:需要加上@TableField(exist = false) 代表数据库没有这个字段,不然会报错

package com.xue.entity;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 产品类目
 */
@Data
@Accessors(chain = true)
public class StuCategory implements Serializable {
    @TableId(value = "category_id", type = IdType.AUTO)
    private Long categoryId;
    @ExcelProperty("店铺id")
    private Integer shopId;
    @ExcelProperty("产品父id")
    private Integer parentId;
    @ExcelProperty("产品类目名字")
    private String categoryName;
    @ExcelProperty("产品图片")
    private String productImage;
    @ExcelProperty("创建时间")
    private Date createTime;
    @ExcelProperty("修改时间")
    private Date updateTime;
    @ExcelProperty("排序")
    private String sort;
    //编写一个list集合来放二级集合
    @TableField(exist = false)//代表数据库没有这个字段,不然会报错
    private List<StuCategory> children;
}

3.编写Controller

package com.xue.controller;

import com.xue.entity.StuCategory;
import com.xue.service.StuCategoryService;
import com.xue.util.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
public class StuCategoryController {

    @Resource
    private StuCategoryService stuCategoryService;

    /**
     * 查询所有分类以及子分类,并用树型结构组装起来
     * @return
     */
    @GetMapping("StuCategoryList")
    public Result<List> StuCategoryList() {
        List<StuCategory> stuCategoryList = stuCategoryService.listwithTree();
        return Result.success(stuCategoryList);
    }

}

4.编写Service方法

package com.xue.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xue.entity.StuCategory;

import java.util.List;

public interface StuCategoryService extends IService<StuCategory> {

    List<StuCategory> listwithTree();
}

5.编写ServiceImpl

package com.xue.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xue.entity.StuCategory;
import com.xue.mapper.StuCategoryMapper;
import com.xue.service.StuCategoryService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class StuCategoryServiceImpl extends ServiceImpl<StuCategoryMapper, StuCategory> implements StuCategoryService {

    @Resource
    private StuCategoryMapper stuCategoryMapper;

    @Override
    public List<StuCategory> listwithTree() {
        //查询出所有的分类
        List<StuCategory> stuCategoryList=stuCategoryMapper.selectList(null);
        /**
         *     这段的代码的意思为调用了stream的filter过滤方法把查询出来getParentCid==0的数 因为这些都是我们的一级菜单
         *     然后查询还要查询出我们一级菜单下的二级菜单调用stream流下的map将我们的返回值重新改变一下在返回,这样把我们查询的数据set到我们的Children里面我们的Children为一个
         *     list集合,我们二级菜单的数据哪里来呢,我们就可以编写一个方法采用递归的方法查询出我们的二级菜单,我们二级菜单下面还有三级菜单
         */
        List<StuCategory> stuCategories=stuCategoryList.stream().filter((StuCategory)->{
            return StuCategory.getParentId() == 0;
        }).map((menu) -> {
            //menu当前菜单在entities找下一个菜单
            menu.setChildren(getChildrens(menu, stuCategoryList));
            return menu;
        }).sorted((menu1, menu2) -> {
            return (menu1.getSort() == null ? 0 : Integer.parseInt(menu1.getSort())) - (menu2.getSort() == null ? 0 : Integer.parseInt(menu2.getSort()));
        }).collect(Collectors.toList());
        /**2.2查出我们的一级菜单下的子菜单 我们需要在实体类中编写一个list集合放我们的子菜单,因为
         一个一级菜单下面可以有多个二级菜单
         */
        System.out.println(stuCategories);
        return stuCategories;
    }
    //递归查出所有的菜单的子菜单

    /**
     * @param root 为当前菜单
     * @param all  所有的菜单
     * @return
     * 首先调用stream的方法过滤一下  判断当前菜单的父id是否等于当前菜单的这个id。如果相同这个菜单就是这个id下的子菜单
     * 我们就调用map方法改变我们的返回值修改一下在重新返回,
     * map方法的作用为调用自己查询出下一级菜单 因为我们二级菜单下面可能有三级菜单或者四级菜单
     */
    private List<StuCategory> getChildrens(StuCategory root, List<StuCategory> all) {

        List<StuCategory> children = all.stream().filter(stuCategory -> {
            return stuCategory.getParentId() == root.getCategoryId().intValue();
        }).map(categoryEntity -> {
            //还是调用这个setChildren方法添加我们的子菜单  参数为categoryEntity为当前的菜单找,在所有菜单中找到所有的子菜单
            //categoryEntity的意思  如果当前菜单为二级菜单就调用这个方法查询这个二级菜单下的子菜单
            categoryEntity.setChildren(getChildrens(categoryEntity, all));
            return categoryEntity;
        }).sorted((menu1, menu2) -> {
            return (menu1.getSort() == null ? 0 : Integer.parseInt(menu1.getSort())) - (menu2.getSort() == null ? 0 : Integer.parseInt(menu2.getSort()));
        }).collect(Collectors.toList());
        return children;
    }
}

注意我们这里使用到了jdk8中的stream
stream中的filter方法为过滤里面可以加条件
stream中的map方法为把我们返回的数据重新改变一下在返回可以set一些新的值返回
stream中的sorted方法为把查询出的数据以那种方式排序
stream.collect(Collectors.toList())为把查询出的数据已list集合返回

看看效果吧

{
	"code": 200,
	"msg": "成功",
	"date": [
		{
			"categoryId": 1,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "手机数码",
			"productImage": null,
			"createTime": "2023-08-07T02:56:57.000+00:00",
			"updateTime": "2023-08-07T02:57:00.000+00:00",
			"sort": "1",
			"children": [
				{
					"categoryId": 7,
					"shopId": 1,
					"parentId": 1,
					"categoryName": "手机通信",
					"productImage": null,
					"createTime": "2023-08-07T03:00:58.000+00:00",
					"updateTime": "2023-08-07T03:01:01.000+00:00",
					"sort": "1",
					"children": [
						{
							"categoryId": 8,
							"shopId": 1,
							"parentId": 7,
							"categoryName": "智能设备",
							"productImage": null,
							"createTime": "2023-08-07T03:01:22.000+00:00",
							"updateTime": "2023-08-07T03:01:23.000+00:00",
							"sort": "1",
							"children": []
						}
					]
				}
			]
		},
		{
			"categoryId": 2,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "美妆护肤",
			"productImage": null,
			"createTime": "2023-08-07T02:57:22.000+00:00",
			"updateTime": "2023-08-07T02:57:25.000+00:00",
			"sort": "1",
			"children": []
		},
		{
			"categoryId": 3,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "运动服饰",
			"productImage": null,
			"createTime": "2023-08-07T02:57:37.000+00:00",
			"updateTime": "2023-08-07T02:57:40.000+00:00",
			"sort": "1",
			"children": []
		},
		{
			"categoryId": 4,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "酒水饮料",
			"productImage": null,
			"createTime": "2023-08-07T02:58:19.000+00:00",
			"updateTime": "2023-08-07T02:58:21.000+00:00",
			"sort": "1",
			"children": []
		},
		{
			"categoryId": 5,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "珠宝钟表",
			"productImage": null,
			"createTime": "2023-08-07T02:58:37.000+00:00",
			"updateTime": "2023-08-07T02:58:39.000+00:00",
			"sort": "1",
			"children": []
		},
		{
			"categoryId": 6,
			"shopId": 1,
			"parentId": 0,
			"categoryName": "美味零食",
			"productImage": null,
			"createTime": "2023-08-07T03:00:33.000+00:00",
			"updateTime": "2023-08-07T03:00:36.000+00:00",
			"sort": "1",
			"children": []
		}
	]
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值