第四章:PostGIS空间服务|实现地图查地、算地核心能力实战

第四章:PostGIS空间服务|实现地图查地、算地核心能力实战

本章导读

很多GIS开发者都有一个通病:只会前端搭地图、渲染图层、做弹窗展示,完全不懂后端空间计算。网上绝大多数GIS Demo都停留在「可视化玩具」阶段,无法落地自然资源真实业务。

自然资源行业的核心刚需从来不是"看地图",而是算地块、查地类、统面积、判合规、空间叠加分析

普通MySQL、Oracle无法支撑复杂几何拓扑运算,而PostgreSQL + PostGIS是目前开源GIS领域、自然资源项目、智慧城市项目的工业级标准选型。

本章基于云原生微服务架构 (Nacos3.2.2 + Higress网关),从零带大家生产级落地PostGIS空间微服务,包含环境部署、库表设计、空间索引优化、核心空间SQL、SpringBoot接口开发、服务注册、网关联调全流程,所有代码可直接上线复用。

读完本章,彻底告别"只会调前端地图组件"的短板,掌握企业级GIS后端核心硬核能力。

一、本章前置架构回顾

在前序章节中,我们已经完整搭建项目云原生底座:

  • Nacos3.2.2:实现全项目配置云端托管、服务注册发现、配置热更新

  • Higress网关:统一流量入口、流量治理、接口防护、长连接适配

云原生底座是项目骨架 ,而PostGIS空间计算能力 是自然资源AI-GIS项目的核心血肉,也是区别于普通可视化Demo的关键。

二、本章核心收获(必看)

本章全程工程化实操,无冗余理论、无玩具代码,学完可直接具备企业级GIS后端开发能力:

  • ✅ 透彻理解PostGIS业务价值,搞懂国土项目必须用空间数据库的底层逻辑

  • ✅ Docker一键部署 PostgreSQL14 + PostGIS3.2 生产级环境

  • ✅ 自然资源行业标准空间表设计:行政区、地类图斑、地块拓展三大核心表

  • ✅ 掌握空间索引+普通索引双重优化,解决大数据量图斑查询卡顿、超时问题

  • ✅ 手写5大生产级空间SQL:框选查询、重叠面积计算、地类统计、行政区筛选、合规排查

  • ✅ 搭建标准化SpringBoot GIS空间微服务,适配云原生架构

  • ✅ 微服务接入Nacos注册中心+配置中心,彻底消灭硬编码、支持配置热更新

  • ✅ 打通Higress网关全链路,实现前端统一入口调用GIS空间接口

  • ✅ 掌握空间服务自测、异常排查、工程化验收全套标准

三、深度解析:为什么国土GIS项目必须用PostGIS?

很多初学GIS开发的同学,都会陷入一个致命误区:使用普通业务数据库存储地块坐标,通过Java/Python业务代码遍历计算空间拓扑关系

这种方案在测试环境、少量样本数据下可以勉强运行,但一旦落地真实自然资源业务,面对上万、数十万条国土图斑数据,会直接出现 查询卡顿、服务卡死、统计失真、接口超时、精度丢失 等一系列问题,完全不具备商用落地价值。

国土地块分析、地类统计、合规研判等核心业务,存在三大核心特性,是MySQL、Oracle等传统关系型数据库完全无法适配的。

3.1 空间数据维度特殊,传统数据库无法识别

国土图斑、行政区边界均属于多维几何空间数据,包含复杂的多边形、多点、多边界矢量结构,并非简单的字符串、数字结构化数据。

传统数据库无专属几何数据类型,只能将坐标拼接为字符串存储,无法识别点、线、面空间要素,更不具备原生空间解析能力,从底层断绝了高精度空间运算的可能性。

3.2 空间拓扑计算逻辑复杂,代码遍历效率极低

国土业务核心计算逻辑,全部依赖空间拓扑运算:判断圈选范围与图斑是否相交、图斑是否完全包含在选区中、跨区地块重叠面积核算、邻接关系判断等。

若通过业务代码手动遍历所有图斑坐标、迭代计算几何关系,时间复杂度极高。十万级图斑数据单次统计耗时可达数十秒,完全无法满足前端实时渲染、业务快速查询的使用需求。

3.3 国土业务精度与性能要求严苛

自然资源业务直接服务于国土变更调查、用地预审、合规审核、土地确权等官方场景,零误差、高精度是硬性要求,不允许出现面积虚高、占比偏差、图斑漏算等问题。

PostGIS底层封装工业级几何算法,支持WGS84等主流坐标系高精度浮点计算,同时搭配GIST空间索引,可将十万级数据复杂空间查询耗时压缩至毫秒级,完美兼顾业务精度与服务性能。

3.4 适配项目云原生整体架构

除了算力优势,PostGIS生态高度成熟,完美适配本项目微服务体系:支持主流ORM框架整合、适配Docker容器化部署、兼容Nacos配置热更新、无框架冲突、开源免费、社区文档完善,是自然资源AI-GIS项目的唯一最优生产级选型

四、生产级实操:PostgreSQL14+PostGIS3.2环境部署

本章所有实操均采用企业稳定版本组合:PostgreSQL 14 + PostGIS 3.2,兼容性强、BUG少、生态适配完善,是目前政企GIS项目主流选型。全程采用Docker Compose一键部署,环境纯净、可移植性强、支持全平台运行。

4.1 编写Docker Compose部署配置

新建项目目录 postgis-local,创建 docker-compose.yml配置文件,包含端口映射、数据持久化、时区配置、容器自启全套生产配置,彻底避免数据丢失、环境冲突问题。

yaml 复制代码
version: '3.8'
services:
  postgis:
    image: postgis/postgis:14-3.2
    container_name: postgis
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: Postgres@123
      POSTGRES_DB: postgres
      TZ: Asia/Shanghai
    volumes:
      - ./postgis-data:/var/lib/postgresql/data
    networks:
      - gis-network

networks:
  gis-network:
    driver: bridge

4.2 容器启动与环境校验

进入部署目录,执行后台启动命令,运行PostGIS容器:

bash 复制代码
docker-compose up -d

启动完成后,查看容器运行状态,确保无异常退出:

bash 复制代码
docker ps | grep postgis

容器状态显示 Up 即为启动成功,可使用DBeaver、Navicat、PgAdmin等工具连接数据库,核心连接参数如下:

  • 连接地址:localhost

  • 端口:5432

  • 用户名:postgres

  • 密码:Postgres@123

  • 默认数据库:postgres

4.3 初始化项目专属GIS业务库

为实现环境隔离、数据解耦,不使用系统默认数据库,单独创建自然资源专属GIS业务库,并手动开启PostGIS核心扩展。

sql 复制代码
-- 创建自然资源GIS专属业务数据库
CREATE DATABASE natural_gis_db;

-- 切换至新数据库
\c natural_gis_db;

-- 开启PostGIS核心空间扩展(核心关键步骤)
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;

-- 验证扩展是否生效(返回版本号即为成功)
SELECT postgis_version();

执行后控制台输出版本号,代表当前数据库已成功升级为工业级空间数据库,具备几何存储、拓扑运算、空间分析全套能力。

五、行业标准实操:自然资源空间数据表设计

表结构设计决定项目上限,不合理的GIS表结构会导致后续查询卡顿、业务拓展困难、统计逻辑冗余。本节严格遵循国土调查行业标准,搭建三张核心业务表,覆盖行政区管理、地类图斑存储、地块属性拓展全场景,同时配置空间索引+普通索引,从底层保障性能。

5.1 行政区空间数据表

存储省、市、县、乡镇、村五级行政区边界数据,支撑行政区筛选、区域批量统计、层级查询业务。

sql 复制代码
-- 行政区空间数据表
CREATE TABLE sys_area (
    id BIGSERIAL PRIMARY KEY,
    area_code VARCHAR(20) NOT NULL,
    area_name VARCHAR(50) NOT NULL,
    area_level INT NOT NULL,
    parent_code VARCHAR(20),
    geom GEOMETRY(MultiPolygon,4326) NOT NULL,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 单独添加字段注释
COMMENT ON COLUMN sys_area.area_code IS '行政区编码';
COMMENT ON COLUMN sys_area.area_name IS '行政区名称';
COMMENT ON COLUMN sys_area.area_level IS '行政级别:1省2市3县4乡镇5村';
COMMENT ON COLUMN sys_area.parent_code IS '上级行政区编码';
COMMENT ON COLUMN sys_area.geom IS '行政区边界几何数据,WGS84坐标系';

-- 核心空间索引(空间查询必备优化)
CREATE INDEX idx_sys_area_geom ON sys_area USING GIST(geom);
-- 业务字段索引,加速行政区筛选
CREATE INDEX idx_sys_area_code ON sys_area(area_code);

5.2 地类图斑核心业务表

项目核心核心业务表,存储所有国土图斑数据,支撑地类统计、面积核算、合规研判、空间叠加分析所有核心功能。

sql 复制代码
-- 地类图斑核心业务表
CREATE TABLE land_parcel (
    id BIGSERIAL PRIMARY KEY,
    parcel_code VARCHAR(30) NOT NULL,
    land_type_code VARCHAR(20) NOT NULL,
    land_type_name VARCHAR(50) NOT NULL,
    actual_area NUMERIC(10,2) NOT NULL,
    manage_type VARCHAR(20),
    geom GEOMETRY(MultiPolygon,4326) NOT NULL,
    area_code VARCHAR(20) NOT NULL,
    is_valid SMALLINT DEFAULT 1,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 字段独立注释
COMMENT ON COLUMN land_parcel.parcel_code IS '图斑唯一编码';
COMMENT ON COLUMN land_parcel.land_type_code IS '国土地类编码(国标)';
COMMENT ON COLUMN land_parcel.land_type_name IS '地类名称:耕地/林地/草地/建设用地等';
COMMENT ON COLUMN land_parcel.actual_area IS '地块实际面积(平方米)';
COMMENT ON COLUMN land_parcel.manage_type IS '管控类型:允许建设/限制建设/禁止建设';
COMMENT ON COLUMN land_parcel.geom IS '地块多边形几何边界';
COMMENT ON COLUMN land_parcel.area_code IS '所属行政区编码';
COMMENT ON COLUMN land_parcel.is_valid IS '是否有效:1有效0作废';

-- 空间索引(大数据量图斑相交、查询核心优化)
CREATE INDEX idx_land_parcel_geom ON land_parcel USING GIST(geom);
-- 业务索引,加速分类统计、区域筛选
CREATE INDEX idx_land_parcel_type ON land_parcel(land_type_code);
CREATE INDEX idx_land_parcel_area ON land_parcel(area_code);

5.3 地块属性拓展表

采用主表+拓展表设计模式,避免主表字段冗余,实现业务解耦,适配后续业务迭代、新增属性字段需求。

sql 复制代码
-- 地块属性拓展表
CREATE TABLE land_parcel_ext (
    id BIGSERIAL PRIMARY KEY,
    parcel_id BIGINT NOT NULL,
    land_use_status VARCHAR(30),
    build_year VARCHAR(10),
    remark VARCHAR(500),
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 独立字段注释
COMMENT ON COLUMN land_parcel_ext.parcel_id IS '关联主图图斑ID';
COMMENT ON COLUMN land_parcel_ext.land_use_status IS '土地利用状态';
COMMENT ON COLUMN land_parcel_ext.build_year IS '建设年份';
COMMENT ON COLUMN land_parcel_ext.remark IS '备注信息';

-- 关联索引,加速联表查询
CREATE INDEX idx_parcel_id ON land_parcel_ext(parcel_id);

六、项目核心算力:五大生产级空间SQL实战

整个AI-GIS系统的后端核心算力,全部依托PostGIS空间SQL实现。前端框选、圈选、统计、合规查询等所有交互功能,底层均基于本节语句开发。所有SQL适配WGS84坐标系,兼容前端OpenLayers地图,坐标精准、面积无偏差、可直接上线使用。

6.1 自定义多边形框选,查询相交图斑

对应前端自由框选、多边形圈选核心功能,匹配范围内所有有效地块图斑,为后续统计、分析提供数据基础。

sql 复制代码
-- 自定义多边形范围,查询相交的所有有效地块图斑
SELECT 
    lp.id,
    lp.parcel_code,
    lp.land_type_code,
    lp.land_type_name,
    lp.actual_area,
    lp.manage_type,
    lp.area_code
FROM land_parcel lp
WHERE lp.is_valid = 1
-- 判断地块与圈选范围几何相交
AND ST_Intersects(
    lp.geom,
    ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326)
);

6.2 框选范围地类面积、占比智能统计

项目核心统计语句,自动分组汇总各类土地的地块数量、总面积、面积占比,直接输出结构化数据,支撑前端图表可视化展示。

sql 复制代码
-- 框选范围地类分类统计、面积、占比核算
SELECT 
    land_type_name,
    land_type_code,
    COUNT(id) AS parcel_count,
    SUM(actual_area) AS total_area,
    -- 计算各类地类占总面积比例,保留2位小数
    ROUND(SUM(actual_area) * 100.0 / (SELECT SUM(actual_area) FROM land_parcel WHERE is_valid=1 AND ST_Intersects(geom,ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326))),2) AS area_ratio
FROM land_parcel
WHERE is_valid = 1
AND ST_Intersects(geom,ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326))
GROUP BY land_type_name,land_type_code
ORDER BY total_area DESC;

6.3 行政区精准筛选地块数据

适配前端行政区下拉筛选、区域专项统计场景,通过行政区编码精准匹配下辖所有有效地块。

sql 复制代码
-- 根据行政区编码筛选下辖所有有效地块
SELECT * FROM land_parcel 
WHERE is_valid = 1 
AND area_code = '620100000';

6.4 高精度地块重叠面积计算

解决跨范围地块统计偏差问题,精准核算地块落在圈选范围内的实际重叠面积,完全贴合国土业务统计标准,杜绝数据虚高、统计不准问题。

sql 复制代码
-- 精准计算地块重叠面积
SELECT 
    parcel_code,
    land_type_name,
    actual_area AS total_parcel_area,
    -- 计算重叠面积并转换为平方米,保留2位小数
    ROUND(ST_Area(ST_Intersection(geom,ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326)))*1000000,2) AS overlap_area
FROM land_parcel
WHERE is_valid = 1
AND ST_Intersects(geom,ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326));

6.5 土地合规筛选统计

适配用地合规研判、违规用地排查业务,快速筛选指定范围内禁止/限制建设地块,支撑业务审核、合规分析场景。

sql 复制代码
-- 筛选选中范围内禁止建设地块
SELECT * FROM land_parcel
WHERE is_valid = 1
AND manage_type = '禁止建设'
AND ST_Intersects(geom,ST_GeomFromText('POLYGON((103.8 36.5,103.9 36.5,103.9 36.6,103.8 36.6,103.8 36.5))',4326));

七、云原生实操:SpringBoot GIS空间微服务搭建

完成底层数据库与算力搭建后,我们搭建标准化GIS空间微服务,整合PostGIS适配、Mybatis、Nacos配置、服务注册能力,工程结构严格遵循微服务分层规范,适配项目云原生架构。

7.1 核心Pom依赖配置

之前创建的gis-space-service项目中引入PostgreSQL驱动、PostGIS空间适配、Nacos、Mybatis-Plus等核心依赖。

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.12</version>
        <relativePath/>
    </parent>

    <artifactId>gis-space-service</artifactId>

    <properties>
        <java.version>17</java.version>
        <spring.cloud.version>2023.0.0</spring.cloud.version>
        <spring.cloud.alibaba.version>2023.0.1.2</spring.cloud.alibaba.version>
        <spring.ai.version>1.0.0-RC1</spring.ai.version>
    </properties>

    <!-- 统一版本管理,无需每个依赖手写version -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring Cloud 版本列车 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Spring Cloud Alibaba BOM -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>aliyun-public</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <url>https://repo.spring.io/milestone</url>
            <snapshots><enabled>false</enabled></snapshots>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 恢复MCP依赖,版本托管 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server</artifactId>
            <version>${spring.ai.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
            <version>${spring.ai.version}</version>
        </dependency>


        <!-- BOM托管,不再手写version -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!-- PostgreSQL驱动 -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- PostGIS空间适配 -->
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-spatial</artifactId>
            <version>7.4.1.Final</version>
            <scope>compile</scope>
        </dependency>

        <!-- Mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <annotationProcessorPaths>
                                <path>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                </path>
                            </annotationProcessorPaths>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-testCompile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <annotationProcessorPaths>
                                <path>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                </path>
                            </annotationProcessorPaths>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

7.2 云端统一配置(bootstrap.yml)

遵循项目云原生规范,通过bootstrap.yml拉取Nacos云端配置,彻底消除本地硬编码,支持配置热更新、服务自动注册。

yaml 复制代码
spring:
  application:
    name: gis-space-service
  profiles:
    active: dev
  config:
    # 必须开启,解决上面的强制校验报错
    import: optional:nacos:${spring.application.name}-${spring.profiles.active}.yml
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: gis-ai-rag-namespace
        group: natural-resource-group
      config:
        server-addr: 127.0.0.1:8848
        namespace: gis-ai-rag-namespace
        group: natural-resource-group
        name: ${spring.application.name}-${spring.profiles.active}
        file-extension: yml
        refresh-enabled: true
        optional: true

在nacos中修改一下之前建好的配置文件

7.3 服务启动类配置

开启服务注册、配置热刷新、Mapper扫描,适配云原生运行机制。

java 复制代码
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@SpringBootApplication
@EnableDiscoveryClient
@RefreshScope
@MapperScan("com.gis.space.mapper")
public class GisSpaceApplication {
    public static void main(String[] args) {
        SpringApplication.run(GisSpaceApplication.class, args);
    }
}

八、核心业务接口开发

基于上述空间SQL,分层封装标准化后端接口,统一请求参数、统一返回格式,实现前端零改造对接,支撑框选统计、行政区查询、地类分析核心功能。

这里的规范可以参考 SpringBoot AI 项目标准化档分层架构:统一封装大模型请求层设计文

8.1 接口入参实体类

java 复制代码
import lombok.Data;

@Data
public class GisQueryDTO {
    // 前端传递的多边形WKT坐标
    private String wkt;
    // 行政区编码
    private String areaCode;
    // 地类编码
    private String landTypeCode;
}

8.2 Mapper层空间查询方法

java 复制代码
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;

public interface LandParcelMapper {

    // 框选范围地类统计
    @Select("SELECT land_type_name,land_type_code,COUNT(id) parcel_count,SUM(actual_area) total_area," +
            "ROUND(SUM(actual_area)*100.0/(SELECT SUM(actual_area) FROM land_parcel WHERE is_valid=1 AND ST_Intersects(geom,ST_GeomFromText(#{wkt},4326))),2) area_ratio " +
            "FROM land_parcel WHERE is_valid=1 AND ST_Intersects(geom,ST_GeomFromText(#{wkt},4326)) " +
            "GROUP BY land_type_name,land_type_code ORDER BY total_area DESC")
    List<Map<String,Object>> statisticLandTypeByWkt(@Param("wkt") String wkt);

    // 行政区地类统计
    @Select("SELECT land_type_name,land_type_code,COUNT(id) parcel_count,SUM(actual_area) total_area " +
            "FROM land_parcel WHERE is_valid=1 AND area_code=#{areaCode} " +
            "GROUP BY land_type_name,land_type_code ORDER BY total_area DESC")
    List<Map<String,Object>> statisticLandTypeByArea(@Param("areaCode") String areaCode);
}

8.3 Service业务层封装

java 复制代码
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Service
public class LandParcelService {

    @Resource
    private LandParcelMapper landParcelMapper;

    public List<Map<String, Object>> statisticByWkt(String wkt) {
        return landParcelMapper.statisticLandTypeByWkt(wkt);
    }

    public List<Map<String, Object>> statisticByArea(String areaCode) {
        return landParcelMapper.statisticLandTypeByArea(areaCode);
    }
}

8.4 Controller接口层(网关统一路由)

java 复制代码
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/gis/statistic")
public class GisStatisticController {

    @Resource
    private LandParcelService landParcelService;

    // 多边形框选统计接口
    @PostMapping("/wkt")
    public List<Map<String,Object>> statisticByWkt(@RequestBody GisQueryDTO dto){
        return landParcelService.statisticByWkt(dto.getWkt());
    }

    // 行政区统计接口
    @PostMapping("/area")
    public List<Map<String,Object>> statisticByArea(@RequestBody GisQueryDTO dto){
        return landParcelService.statisticByArea(dto.getAreaCode());
    }
}

最终得到的结果如下图:工程报错的,或者没有测试数据的自行捉摸着弄一下。过一段时间整个案例做完了上传我这边的所有代码及测试数据。

九、全链路验收:服务注册、热更新、网关联调

9.1 Nacos服务注册校验

启动GIS空间微服务,登录Nacos3.2.2控制台,切换项目专属命名空间,服务列表可正常查询到 gis-space-service,健康实例数为1,代表服务注册成功、服务发现正常。

9.2 配置热更新验证

在Nacos云端修改GIS业务参数(统计小数位数、地图默认参数等),发布配置后无需重启服务,调用接口可实时读取最新配置,热更新功能正常生效,彻底解决传统项目改配置重启服务的痛点。

9.3 Higress网关全链路测试

通过网关统一入口调用接口:localhost:8080/api/gis/statistic/wkt,接口正常返回结构化统计数据,网关路由转发、流量拦截、请求适配全部正常,前端-网关-微服务-数据库全链路请求闭环成型。

十、本章工程化总结 & 上线验收标准

10.1 本章总结

本章从零完成PostGIS空间微服务全流程工程化落地 ,搭建起AI-GIS系统最核心的空间算力底座,彻底打破传统GIS项目"只展示、不计算"的玩具化弊端,实现了国土地块统计、地类分析、合规研判、面积核算等核心业务的工业化落地。

结合前序章节的Nacos配置治理、Higress流量治理,项目已完整成型云原生+空间算力双核心架构,为后续AI知识库对接、智能分析、智能研判功能奠定底层基础。

10.2 生产级验收标准(逐条核对)

  • ✅ PostGIS容器环境正常启动,空间扩展成功激活,专属业务数据库创建完成

  • ✅ 三大核心空间业务表搭建完毕,空间索引、普通索引配置齐全,性能优化到位

  • ✅ 五大核心空间SQL调试通过,高精度、高效率支撑各类国土统计场景

  • ✅ SpringBoot GIS微服务结构规范、依赖齐全、无版本冲突

  • ✅ 服务成功注册Nacos,云端配置拉取正常,支持热更新、无硬编码

  • ✅ 核心业务接口可正常调用,数据返回精准、无偏差

  • ✅ Higress网关路由正常,全链路请求通畅,实现生产级闭环

🔥 下期预告

下一章我们将落地自然资源RAG向量知识库 ,解决AI模型幻觉问题,实现国土专业知识智能问答、智能研判、文案自动生成,完成项目智能化核心能力搭建!