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

news2024/10/6 2:29:15

应用场景
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": []
		}
	]
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/842706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美国地区TikTok直播电商SOP(附下载)

关于报告的所有内容&#xff0c;公众【营销人星球】获取下载查看 核心观点 随着互联网的普及和社交媒体的兴起&#xff0c;网红直播已经成为了一种新型的娱乐方式和商 业模式。越来越多的人开始关注网红直播&#xff0c;希望通过这种方式获得更多的粉丝和商业机会。但是&…

防勒索病毒

随着勒索软件攻击在2023年的激增&#xff0c;网络安全已成为当今最重要的议题之一。根据区块链分析公司Chainaanalysis的最新报告&#xff0c;勒索软件攻击已成为唯一呈增长趋势的基于加密货币的犯罪行为&#xff0c;勒索金额更是比一年前增加了近1.758亿美元&#xff0c;达到4…

软件设计师(七)面向对象技术

面向对象&#xff1a; Object-Oriented&#xff0c; 是一种以客观世界中的对象为中心的开发方法。 面向对象方法有Booch方法、Coad方法和OMT方法等。推出了同一建模语言UML。 面向对象方法包括面向对象分析、面向对象设计和面向对象实现。 一、面向对象基础 1、面向对象的基本…

CentOS 7 构建 LVS-DR 群集 nginx负载均衡

1、基于 CentOS 7 构建 LVS-DR 群集。 DS&#xff08;Director Server&#xff09;&#xff1a;DIP 192.168.231.132 & VIP 192.168.231.200 [root132 ~]# nmcli c show NAME UUID TYPE DEVICE ens33 c89f4a1a-d61b-4f24-a260…

云曦暑期学习第四周——流量、日志分析

1 日志分析 1.1 What is 日志 日志&#xff0c;是作为记录系统与服务最直接有效的方法。在日志中&#xff0c;可以发现访问记录以及发现攻击线索。日志分析也是最常用的分析安全 事件所采用的途径。系统日志和 web 日志分别记录了不同内容&#xff0c;为分析攻击提供了有效证…

C#--设计模式之单例模式

单例模式大概是所有设计模式中最简单的一种&#xff0c;如果在面试时被问及熟悉哪些设计模式&#xff0c;你可能第一个答的就是单例模式。 单例模式的实现分为两种&#xff1a; 饿汉式&#xff1a;在静态构造函数执行时就立即实例化。懒汉式&#xff1a;在程序执行过程中第一…

RaabitMQ(三) - RabbitMQ队列类型、死信消息与死信队列、懒队列、集群模式、MQ常见消息问题

RabbitMQ队列类型 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选择是否持久化(Durability)以及是否自动删除(Auto delete)两个属性。 Durability有两个选项&#xff0c;Durable和Transient。 Durable表…

mysql高级三:sql性能优化+索引优化+慢查询日志

内容介绍 单表索引失效案例 0、思考题&#xff1a;如果把100万数据插入MYSQL &#xff0c;如何提高插入效率 &#xff08;1&#xff09;关闭自动提交&#xff0c;只手动提交一次 &#xff08;2&#xff09;删除除主键索引外其他索引 &#xff08;3&#xff09;拼写mysql可以执…

matlab智能算法程序包89套最新高清录制!matlab专题系列!

关于我为什么要做代码分享这件事&#xff1f; 助力科研旅程&#xff01; 面对茫茫多的文献&#xff0c;想复现却不知从何做起&#xff0c;我们通过打包成品代码&#xff0c;将过程完善&#xff0c;让您可以拿到一手的复现过程以及资料&#xff0c;从而在此基础上&#xff0c;照…

CNN成长路:从AlexNet到EfficientNet(02)

一、说明 在~10年的深度学习中&#xff0c;进步是多么迅速&#xff01;早在 2012 年&#xff0c;Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在&#xff0c;我们超过90%的EfficientNet架构和师生训练&#xff08;teacher-student&#xff09;。 二、第一阶段 …

白盒测试怎么做

一、什么是白盒测试 白盒测试又称结构测试、逻辑驱动测试或基于代码的测试。 白盒测试是一种测试用例设计方法&#xff0c;盒子指的是被测试的软件&#xff0c;白盒指的是盒子是可视的&#xff0c;即清楚盒子内部的东西以及里面是如何运作的。 "白盒"法需要测试者…

Spring学习笔记——2

Spring学习笔记——2 1、Bean的基本注解开发1.1、注解版本和Component简介1.2、Component使用1.3、Component的三个衍生注解 二、Bean依赖注入注解开发2.1、依赖注入相关注解2.2、Autowired扩展 三、非自定义Bean注解开发四、Bean配置类的注解开发五、Spring注解的解析原理六、…

解决Vue+Element UI使用表单rules国际化时From表单验证信息不能实时更新

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 博主在工作之余开始进行自动化测试平台的开发&#xff0c;虽然已经996一个月了但是还是在使劲挤时间做这件事情&#xff0c;目前平台使用前端框架vu…

mysql再docker中运行,直接在实体机上运行mysql命令初始化数据库数据

背景 项目上我们使用docker安装mysql&#xff0c;项目启动的时候需要利用sql语句初始化数据。 直接在实体上是识别不到mysql命令的。 实现方式 实现方式1&#xff1a;在docker容器内部执行sql语句 1. 将sql文件上传到容器内 docker cp /root/1.sql d5:/home/ 说明&#…

日期格式化的最佳实践:如何在Java中处理日期格式化

文章目录 前言一、使用format()方法二、使用注解JsonFormat三、使用消息转换器1.定义用户类2.重写DateSerializer 方法3.定义对象映射器&#xff1a;4.定义消息转换器5.调用测试 总结 前言 当涉及到日期格式化时&#xff0c;了解正确的方式和最佳实践是至关重要的。 日期格式化…

Stephen Wolfram:ChatGPT 的训练

The Training of ChatGPT ChatGPT 的训练 OK, so we’ve now given an outline of how ChatGPT works once it’s set up. But how did it get set up? How were all those 175 billion weights in its neural net determined? Basically they’re the result of very large…

目标检测与跟踪 (3)- TensorRTYOLO V8性能优化与部署测试

系列文章目录 目标检测与跟踪 &#xff08;1&#xff09;- 机器人视觉与YOLO V8_Techblog of HaoWANG的博客-CSDN博客 目标检测与跟踪 &#xff08;2&#xff09;- YOLO V8配置与测试_Techblog of HaoWANG的博客-CSDN博客 目录 系列文章目录 前言 YOLO v8 TensorRT 一、…

等保三级中“身份鉴别”要求与2FA双因子认证有何关联?

为了保护信息的安全&#xff0c;我国实行对信息及信息载体按照重要性等级分别进行保护&#xff0c;也就是信息安全等级保护制度。根据信息系统在国家安全、经济建设、社会生活中的重要程度&#xff0c;信息系统遭到破坏后对国家安全、社会秩序、公共利益以及公民、法人和其他组…

c++(类型转换+IO)[30]

类型转换 意义相近的类型------隐式类型转换 意义不想近的类型&#xff0c;值转换后有意义------显示的强制类型转换 static_cast 任何隐式类型的转换&#xff0c;非多态类型的转换&#xff08;静态转换&#xff09;&#xff0c;意义相近的转换。 用于常见的隐式类型转换&am…

Spring Boot数据访问基础知识与JDBC简单实现

目录 Spring Boot数据访问基础知识 Spring Data ORM JDBC JPA JDBC简单实现 步骤1&#xff1a;新建Maven项目&#xff0c;添加依赖 步骤2&#xff1a;配置数据源—让程序可以访问到 步骤3&#xff1a;配置数据源—让IDEA可以访问到 步骤4&#xff1a;添加数据库和表 …