Bootstrap

国家行政区划编码格式化和树形结构转换示例

一、需求描述

国家行政区划编码树形结构是一种用于组织和表示国家内部各级行政区划的层次结构。这种结构不仅有助于数据的分类和存储,还能提高地理信息系统的效率,便于各级政府和机构进行数据管理和统计分析。项目内需要自行维护一套行政区划数据,支持高德地图定位获取到的行政机构编码进行数据映射。国家行政区划编码的可以通过民政部官方网站获取:2023版国家县级及以上行政区划编码目的地址。官方的行政区划编码数据是按记录行提供的,没有父子级关系绑定信息、数据记录行本身没有层级信息、数据记录行没有行政区划全称。因此,需要对该数据进行重新处理后才能在项目内方便的进行使用,具体处理过程即相关代码参照如下。

二、树形机构转换依赖模型

  • TreeNode

节点数据模型,提供了基础树形结构构建所必须的属性(主要是父子级对应关系)获取相关方法,提供了符合父子级关系特征的数据行转换为树形结构的方法,比如将数据行集合转换为树的方法、树形结构数据的展开为数据行等基础树操作。代码如下:

package org.jeecg.common.entity;

import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className: Node
 * @author: Liuyh
 * @date: 2024/10/16 13:32
 * @Version: 1.0
 * @description:
 */
public interface TreeNode<T> {

    /**
     * 获取当前节点id
     *
     * @return
     */
    String currentId();

    /**
     * 获取节点的父节点id
     *
     * @return
     */
    String getParentId();

    /**
     * 设置节点的层级
     *
     * @param level
     */
    void setNodeLevel(Integer level);

    /**
     * 获取节点的所有子节点
     *
     * @return
     */
    List<T> getChildren();


    /**
     * 构建多棵树形结构
     *
     * @param rootIds {@literal Root ids}
     * @param nodes   {@literal All nodes}
     * @param <T>
     * @return
     */
    static <T extends TreeNode<T>> List<T> buildTree(List<String> rootIds, List<T> nodes) {
        Map<String, List<T>> nodeMap = nodes.stream().collect(Collectors.groupingBy(o -> o.getParentId()));
        // 找到所有的根节点
        List<T> rootNodes =
                nodes.stream().filter(node -> rootIds.contains(node.currentId())).collect(Collectors.toList());

        // 构建树形结构
        rootNodes.forEach(root -> buildChildren(root, nodeMap, 0));
        return rootNodes;
    }

    /**
     * 构建一棵树形结构
     * <b>根节点{@linkplain #getParentId()}为空或者null</b>
     *
     * @param nodes      {@literal All nodes}
     * @param firstLevel {@literal firest Level of root node}
     * @param <T>
     * @return
     */
    static <T extends TreeNode<T>> List<T> buildTree(List<T> nodes, int firstLevel) {
        Map<String, List<T>> nodeMap = nodes.stream().collect(Collectors.groupingBy(o -> o.getParentId()));
        // 找到所有的根节点
        List<T> rootNodes = CollectionUtils.isEmpty(nodeMap.get(null)) ? nodeMap.get("") : nodeMap.get(null);
        // 构建树形结构
        rootNodes.forEach(root -> buildChildren(root, nodeMap, firstLevel));
        return rootNodes;
    }

    /**
     * 构建一棵树形结构
     *
     * @param rootNode {@literal Root node}
     * @param nodeMap  {@literal Map of nodes group by parent id}
     * @param level    {@literal Level of current node}
     * @param <T>
     */
    static <T extends TreeNode<T>> void buildChildren(T rootNode, Map<String, List<T>> nodeMap, int level) {
        // 设置当前节点的层级
        rootNode.setNodeLevel(level);
        // 找到当前节点的所有子节点
        List<T> children = nodeMap.get(rootNode.currentId());
        if (children != null && !children.isEmpty()) {
            // 将子节点添加到当前节点的 children 列表中
;