二级分类菜单及三级分类菜单的层级结构返回

前言

在开发投诉分类功能模块时,遇到过这样一个业务场景:后端需要按层级结构返回二级分类菜单所需数据,换言之,将具有父子关系的List结果集数据转为树状结构数据来返回

二级分类菜单

前期准备

这里简单复刻下真实场景中 出现的二级分类菜单层级结构返回

数据库设计

建表语句如下

sql 复制代码
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称',
  `parent_id` bigint NULL DEFAULT NULL COMMENT '父级id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of menu
-- ----------------------------
INSERT INTO `menu` VALUES (1, '质量问题', 0);
INSERT INTO `menu` VALUES (2, '变质', 1);
INSERT INTO `menu` VALUES (3, '过期', 1);
INSERT INTO `menu` VALUES (4, '包装破损', 1);
INSERT INTO `menu` VALUES (5, '服务问题', 0);
INSERT INTO `menu` VALUES (6, '态度恶劣', 5);
INSERT INTO `menu` VALUES (7, '东拉西扯', 5);

效果图预览



这里是在SpringBoot项目中演示实现的,持久层框架选用MyBatis-Plus,版本号:3.5.3.1

🌟之所以强调MP版本号,是因为之前在实现分页时遇过挫,真实项目选用的版本是3.3.2,而自己在学习MP时,选择版本是3.5.3.1。MP官方文档在不同版本中,有关分页插件的使用介绍可能存在不同,实际开发中对引入MP依赖的版本号还是要有所关注

开发测试

创建实体类

java 复制代码
package com.atguigu.mybatisplus.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author Songguo
 * @date 2023/11/15 9:56
 */
@Data
@TableName("menu")
public class Menu {
    private Long id;

    private String name;

    private Long parentId;
}

创建mapper层

java 复制代码
package com.atguigu.mybatisplus.mapper;

import com.atguigu.mybatisplus.pojo.Menu;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface MenuMapper extends BaseMapper<Menu> {
}

创建service层接口及实现类

java 复制代码
package com.atguigu.mybatisplus.service;

import com.atguigu.mybatisplus.pojo.Menu;
import com.baomidou.mybatisplus.extension.service.IService;

public interface MenuService extends IService<Menu> {
}
java 复制代码
package com.atguigu.mybatisplus.service.impl;

import com.atguigu.mybatisplus.mapper.MenuMapper;
import com.atguigu.mybatisplus.pojo.Menu;
import com.atguigu.mybatisplus.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * @author Songguo
 * @date 2023/11/15 10:00
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
}

创建测试类

java 复制代码
package com.atguigu.mybatisplus;

import com.atguigu.mybatisplus.pojo.Menu;
import com.atguigu.mybatisplus.service.MenuService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Songguo
 * @date 2023/11/15 10:02
 */
@SpringBootTest
public class MenuServiceImplTest {
    @Autowired
    private MenuService menuService;

    @Test
    public void ListToTreeTest() {
        List<Menu> list = menuService.list();
        // 存放要返回的树状结构数据
        List<Map<String, Object>> MenuList = new ArrayList<>();

        for (Menu menu : list) {
            if (Long.valueOf(0) == menu.getParentId()) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", menu.getId());
                map.put("name", menu.getName());
                // map.put("parentId", menu.getParentId());
                map.put("children", getChildren(list, menu.getId()));
                MenuList.add(map);
            }

        }

        MenuList.forEach(System.out::println);
    }

    public List<Map<String, Object>> getChildren(List<Menu> list, Long topId) {
        List<Map<String, Object>> data = new ArrayList<>();

        for (Menu menu : list) {
            if (topId == menu.getParentId()) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", menu.getId());
                map.put("name", menu.getName());
                // map.put("parentId", menu.getParentId());
                data.add(map);
            }
        }

        return data;
    }

}

注意: 在真实场景中,并不需要返回每条记录的所有字段值,主要看前端需要接收那些数据

实现思路很简单:

1️⃣获取分类菜单所有记录

2️⃣遍历找出一级节点(父节点),然后在调用getChildren()(重金寻子方法)获取二级节点(子节点)

3️⃣通过List<Map<String,Object>>来存放结果集

三级分类菜单

前期准备

这里简单复刻下真实场景中 出现的三级分类菜单层级结构返回

数据库设计

建表语句如下

sql 复制代码
CREATE TABLE address (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  parent_id INT NOT NULL,
  level INT NOT NULL
);

INSERT INTO address (name, parent_id, level) VALUES ('湖北', 0, 1);
INSERT INTO address (name, parent_id, level) VALUES ('辽宁', 0, 1);
INSERT INTO address (name, parent_id, level) VALUES ('武汉', 1, 2);
INSERT INTO address (name, parent_id, level) VALUES ('荆州', 1, 2);
INSERT INTO address (name, parent_id, level) VALUES ('沈阳', 2, 2);
INSERT INTO address (name, parent_id, level) VALUES ('蔡甸区', 3, 3);
INSERT INTO address (name, parent_id, level) VALUES ('江夏区', 3, 3);
INSERT INTO address (name, parent_id, level) VALUES ('沙市区', 4, 3);
INSERT INTO address (name, parent_id, level) VALUES ('大东区', 5, 3);
INSERT INTO address (name, parent_id, level) VALUES ('浑南区', 5, 3);

效果图预览



开发测试

创建实体类

java 复制代码
package com.atguigu.mybatisplus.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author Songguo
 * @date 2023/11/26 17:04
 */
@Data
@TableName("address")
public class Address {
    private int id;

    private String name;

    private int parentId;

    private int level;
}

创建mapper层

java 复制代码
package com.atguigu.mybatisplus.mapper;

import com.atguigu.mybatisplus.pojo.Address;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface AddressMapper extends BaseMapper<Address> {
}

创建service层接口及实现类

java 复制代码
package com.atguigu.mybatisplus.service;


import com.atguigu.mybatisplus.pojo.Address;
import com.baomidou.mybatisplus.extension.service.IService;

public interface AddressService extends IService<Address> {
}
java 复制代码
package com.atguigu.mybatisplus.service.impl;

import com.atguigu.mybatisplus.mapper.AddressMapper;
import com.atguigu.mybatisplus.pojo.Address;
import com.atguigu.mybatisplus.service.AddressService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * @author Songguo
 * @date 2023/11/26 17:08
 */
@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements AddressService {
}

创建测试类

java 复制代码
package com.atguigu.mybatisplus;

import com.atguigu.mybatisplus.pojo.Address;
import com.atguigu.mybatisplus.service.AddressService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Songguo
 * @date 2023/11/26 17:10
 */
@SpringBootTest
public class AddressServiceImplTest {
    @Autowired
    private AddressService addressService;

    @Test
    public void getAddress() {
        List<Address> list = addressService.list();
        // list.forEach(System.out::println);
        // 存放结果集
        List<Map<String, Object>> addressList = new ArrayList<>();

        for (Address address : list) {
            if (address.getLevel() == 1) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", address.getId());
                map.put("name", address.getName());
                // map.put("parentId", address.getParentId());
                map.put("children", getChildren(list, address.getId()));
                addressList.add(map);
            }
        }

        addressList.forEach(System.out::println);
    }

    public List<Map<String, Object>> getChildren(List<Address> list, int parentId) {
        List<Map<String, Object>> data = new ArrayList<>();

        for (Address address : list) {
            HashMap<String, Object> map = new HashMap<>();
            if (parentId == address.getParentId()) {
                map.put("id", address.getId());
                map.put("name", address.getName());
                // map.put("parentId", address.getParentId());
                if (address.getLevel() < 3) {
                    map.put("children", getChildren(list, address.getId()));
                }
                data.add(map);
            }
        }

        return data;
    }

}

小结

二级分类菜单的层级结构返回是在真实项目中遇到的,而三级分类菜单的层级结构返回是模拟真实场景下的需求进行扩展实现的

弄懂了二级分类和三级分类,多级分类还会远嘛

相关推荐
BillKu27 分钟前
Java + Spring Boot + Mybatis 插入数据后,获取自增 id 的方法
java·tomcat·mybatis
全栈凯哥28 分钟前
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
java·算法·leetcode·链表
chxii29 分钟前
12.7Swing控件6 JList
java
全栈凯哥31 分钟前
Java详解LeetCode 热题 100(27):LeetCode 21. 合并两个有序链表(Merge Two Sorted Lists)详解
java·算法·leetcode·链表
YuTaoShao31 分钟前
Java八股文——集合「List篇」
java·开发语言·list
PypYCCcccCc36 分钟前
支付系统架构图
java·网络·金融·系统架构
华科云商xiao徐1 小时前
Java HttpClient实现简单网络爬虫
java·爬虫
扎瓦1 小时前
ThreadLocal 线程变量
java·后端
BillKu1 小时前
Java后端检查空条件查询
java·开发语言
jackson凌2 小时前
【Java学习笔记】String类(重点)
java·笔记·学习