# 多级菜单数据结构 - 非递归

创建数据库表:

/*
 Navicat Premium Data Transfer
 Source Server         : windows
 Source Server Type    : MySQL
 Source Server Version : 80028
 Source Host           : localhost:3306
 Source Schema         : tree_data
 Target Server Type    : MySQL
 Target Server Version : 80028
 File Encoding         : 65001
 Date: 29/02/2024 11:26:32
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for data_one
-- ----------------------------
DROP TABLE IF EXISTS `data_one`;
CREATE TABLE `data_one`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `p_id` int NULL DEFAULT NULL,
  `order_num` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of data_one
-- ----------------------------
INSERT INTO `data_one` VALUES (1, '邢台', 0, 1);
INSERT INTO `data_one` VALUES (2, '沙河市', 1, 2);
INSERT INTO `data_one` VALUES (3, '河北省', 1, 3);
INSERT INTO `data_one` VALUES (4, '北京 ', 0, 1);
INSERT INTO `data_one` VALUES (5, '朝阳', 4, 2);
INSERT INTO `data_one` VALUES (6, '赞善乡', 2, 1);
SET FOREIGN_KEY_CHECKS = 1;

创建好表如下:

image-20240229112708284

编写 java 代码:

实体类:

public class DataOne {
    private Integer id;
    private String name;
    private Integer pId;
    private Integer orderNum; // 排序字段
    private List<DataOne> data1s; // 子级菜单集合
    public List<DataOne> getData1s() {
        return data1s;
    }
    public void setData1s(List<DataOne> data1s) {
        this.data1s = data1s;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getpId() {
        return pId;
    }
    public void setpId(Integer pId) {
        this.pId = pId;
    }
    public Integer getOrderNum() {
        return orderNum;
    }
    public void setOrderNum(Integer orderNum) {
        this.orderNum = orderNum;
    }
    @Override
    public String toString() {
        return "Data1{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pId=" + pId +
                ", orderNum=" + orderNum +
                ", data1s=" + data1s +
                '}';
    }
}

创建 JdbcUtils 工具类:

public class JUtils {
    private static DataSource source;
    static{
        Properties pro = null;
        try{
            pro = new Properties();
            InputStream in = JUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(in);
            source = DruidDataSourceFactory.createDataSource(pro);
        }catch(IOException e){
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return source.getConnection();
    }
    public static DataSource getSource() {
        return source;
    }
}

创建查询数据库并返回多级菜单数据结构的类:

public class TreeDataOne {
    // 创建 JdbcTemplate 对象查询数据库
    private JdbcTemplate jdbcTemplate = new JdbcTemplate(JUtils.getSource());
    public List<DataOne> getTreeChildren() {
        // 查询 data_one 表的所有数据
        String sql = "select * from data_one";
        List<DataOne> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<DataOne>(DataOne.class));
        // 调用函数将所有数据根据某字段来构建成树形结构并返回
        return buildTree(query);
    }
    public List<DataOne> buildTree(List<DataOne> listTree) {
        // 创建 map 集合
        Map<Integer, DataOne> map = new HashMap<>();
        for (DataOne datas : listTree) {
            // 存储 每条数据的 id 与它的数据
            map.put(datas.getId(), datas);
        }
        // 创建 List 集合
        List<DataOne> datalists = new ArrayList<>();
        for (DataOne data1 : listTree) {
            // 获取遍历的每条数据的 pId
            Integer parentId = data1.getpId();
            if (parentId == null || parentId == 0) {
                datalists.add(data1);
            }else {
                DataOne dataOne = map.get(parentId);
                if (dataOne != null) {
                    if (dataOne.getData1s() == null) {
                        dataOne.setData1s(new ArrayList<>());
                    }
                    dataOne.getData1s().add(data1);
                }
            }
        }
        sortTree(datalists);
        return datalists;
    }
    public void sortTree(List<DataOne> listTree) {
        for (DataOne datas : listTree) {
            if (datas.getData1s() != null && ! datas.getData1s().isEmpty()) {
                sortTree(datas.getData1s());
            }
        }
        Collections.sort(listTree, Comparator.comparingInt(DataOne::getOrderNum));
    }
}

测试代码:

// 多级菜单数据测试
@Test
public void testTwo() {
   TreeDataOne data1Service = new TreeDataOne();
   List<DataOne> treeChildren = data1Service.getTreeChildren();
   for (DataOne treeChild : treeChildren) {
      System.out.println(treeChild);
   }
}

打印结果:

信息: {dataSource-1} inited
Data1{id=1, name='邢台', pId=0, orderNum=1, data1s=[Data1{id=2, name='沙河市', pId=1, orderNum=2, data1s=[Data1{id=6, name='赞善乡', pId=2, orderNum=1, data1s=null}]}, Data1{id=3, name='河北省', pId=1, orderNum=3, data1s=null}]}
Data1{id=4, name='北京 ', pId=0, orderNum=1, data1s=[Data1{id=5, name='朝阳', pId=4, orderNum=2, data1s=null}]}

格式化后的数据:

Data1 {
	id = 1, name = '邢台', pId = 0, orderNum = 1, data1s = [Data1 {
		id = 2, name = '沙河市', pId = 1, orderNum = 2, data1s = [Data1 {
			id = 6, name = '赞善乡', pId = 2, orderNum = 1, data1s = null
		}]
	}, Data1 {
		id = 3, name = '河北省', pId = 1, orderNum = 3, data1s = null
	}]
}
Data1 {
	id = 4, name = '北京 ', pId = 0, orderNum = 1, data1s = [Data1 {
		id = 5, name = '朝阳', pId = 4, orderNum = 2, data1s = null
	}]
}