一、相关空间表简介及设计
本节重点介绍需要使用到的一些基础空间表和用于存储省级城市距离的空间表信息。通过本节的讲解,了解如何进行省级地市的信息查询,以及如何存储省级城市距离及其路线信息。
1、相关基础空间表
为了查询省会城市和其他地级城市,这里需要用到两张表:biz_geographic_name(PostGIS 空间表)和 biz_city(城市信息表)。通过省级行政区划代码找到 biz_city 表的城市信息,然后查找对应的包含的省会及地区城市信息。
CREATE TABLE "public"."biz_city" (
"id" int8 NOT NULL,
"province_code" varchar(16) COLLATE "pg_catalog"."default" NOT NULL,
"province_name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
"city_code" varchar(16) COLLATE "pg_catalog"."default" NOT NULL,
"city_name" varchar(512) COLLATE "pg_catalog"."default" NOT NULL,
"type" varchar(32) COLLATE "pg_catalog"."default",
"geom" "public"."geometry",
CONSTRAINT "pk_biz_city" PRIMARY KEY ("id")
);
CREATE INDEX "idx_biz_city_citycode" ON "public"."biz_city" USING btree ("city_code" COLLATE "pg_catalog"."text_ops" ASC NULLS LAST);
CREATE INDEX "idx_biz_city_pcode" ON "public"."biz_city" USING btree ("province_code" COLLATE "pg_catalog"."text_ops" ASC NULLS LAST);
COMMENT ON COLUMN "public"."biz_city"."id" IS '主键 ID';
COMMENT ON COLUMN "public"."biz_city"."province_code" IS '省份编码';
COMMENT ON COLUMN "public"."biz_city"."province_name" IS '省份名称';
COMMENT ON COLUMN "public"."biz_city"."city_code" IS '市级编码';
COMMENT ON COLUMN "public"."biz_city"."city_name" IS '实际名称';
COMMENT ON COLUMN "public"."biz_city"."type" IS '类型';
COMMENT ON COLUMN "public"."biz_city"."geom" IS 'geom';
CREATE TABLE "public"."biz_geographic_name" (
"pk_id" int8 NOT NULL,
"name" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"pinyin" varchar(255) COLLATE "pg_catalog"."default",
"classz" varchar(4) COLLATE "pg_catalog"."default",
"bz" varchar(100) COLLATE "pg_catalog"."default",
"slx" varchar(20) COLLATE "pg_catalog"."default",
"geom" "public"."geometry" NOT NULL,
CONSTRAINT "pk_biz_geographic_name" PRIMARY KEY ("pk_id")
);
CREATE INDEX "idex_biz_geographic_name_classz" ON "public"."biz_geographic_name" USING btree ("classz" COLLATE "pg_catalog"."text_ops" ASC NULLS LAST);
CREATE INDEX "idx_biz_geographic_name_geom" ON "public"."biz_geographic_name" USING gist ("geom" "public"."gist_geometry_ops_2d");
COMMENT ON COLUMN "public"."biz_geographic_name"."pk_id" IS '主键 id';
COMMENT ON COLUMN "public"."biz_geographic_name"."name" IS '地名';
COMMENT ON COLUMN "public"."biz_geographic_name"."pinyin" IS '汉语拼音';
COMMENT ON COLUMN "public"."biz_geographic_name"."classz" IS 'classz';
COMMENT ON COLUMN "public"."biz_geographic_name"."bz" IS '备注';
COMMENT ON COLUMN "public"."biz_geographic_name"."slx" IS 'slx';
COMMENT ON COLUMN "public"."biz_geographic_name"."geom" IS '空间对象';
COMMENT ON TABLE "public"."biz_geographic_name" IS '地名基础信息表,用于存储中国范围内的地名信息';
2、查找省会与地市信息
查询省会与地市信息的 SQL 如下:
SELECT T.*, st_x(T.geom) lon, st_y(T.geom) lat, st_asgeojson(T.geom)
FROM biz_geographic_name T, biz_city tc
WHERE tc.province_code = '430000'
AND T.classz IN ('AD', 'AC')
AND st_contains(tc.geom, T.geom);
执行以上 SQL 脚本后,可以看到结果集,作为下一步计算的基础。

3、省级城市距离表设计
为了存储两地的行车最快路线以及其行驶的里程数,同时方便后续数据查询,在第一次调用后缓存结果可显著提高计算能力。因此需要设计一张空间信息表来存储经过计算过的行车路线信息。

空间表的物理表结构如下所示:
CREATE TABLE "public"."biz_provincial_city_distance" (
"pk_id" int8 NOT NULL,
"province_code" varchar(16) NOT NULL DEFAULT ''::character varying,
"province_name" varchar(64) NOT NULL DEFAULT ''::character varying,
"distance" numeric(10,4) NOT NULL DEFAULT 0,
"city_name" varchar(64) NOT NULL DEFAULT ''::character varying,
"geom" "geometry",
"source" varchar(10) NOT NULL DEFAULT ''::character varying,
CONSTRAINT "pk_biz_provincial_city_distanc" PRIMARY KEY ("pk_id")
);
COMMENT ON COLUMN "biz_provincial_city_distance"."pk_id" IS '主键';
COMMENT ON COLUMN "biz_provincial_city_distance"."province_code" IS '省份 code';
COMMENT ON COLUMN "biz_provincial_city_distance"."province_name" IS '省份 name';
COMMENT ON COLUMN "biz_provincial_city_distance"."distance" IS '距离';
COMMENT ON COLUMN "biz_provincial_city_distance"."city_name" IS '城市名称';
COMMENT ON COLUMN "biz_provincial_city_distance"."geom" IS '路线信息';
COMMENT ON COLUMN "biz_provincial_city_distance"."source" IS '来源';
COMMENT ON TABLE "biz_provincial_city_distance" IS '省市距离信息表';
作为行车计算的成果保存表,这张表在以后的计算中还会经常用到。
二、省会与地级市距离实现
为了实现能够计算省域的省会与地级市的最快行车距离,首先需要明确详细的工作流。我们绘制具体的系统工作流程,使用天地图的驾车 API 辅助生成距离的路线,同时计算通行时间,最后使用 GeoTools 来实现成果入库。
1、系统工作流程图

基本步骤如下:第一步是根据输入的省份 code 查询省会及对应得地级市信息;如果查找的地市信息,则进入循环;在循环中去调用天地图的最快行车 API 查询接口;最后将得到的路线信息及其通行时间进行一个批量的入库。
2、查询指定省份的省会与地市
在查询出数据之后,通常来说,省会城市是返回的结果集中的第一条,因此在进行行车导航的时候,默认第一条是省会城市。将第一条数据的经纬度作为目标点。这里使用的是天地图的检索接口,返回的数据采用的坐标还是 4326 的坐标系,需要注意不要弄错。
根据省份 code 查询省会及其地级市的方法如下:
String province_code = "430000";
String provinceName = "湖南省";
List<GeographicNameVo> cityList = GeoNameService.findProvinceCityListByPcode(province_code);
然后在返回的结果集当中,默认第一条数据是省会城市,将其单独拿出来作为目标城市,并提取具体的经纬度信息。
GeographicNameVo provincialCapital = cityList.get(0);
String destInfo = provincialCapital.getLon() + "," + provincialCapital.getLat();
3、天地图行车导航
接下来循环各个地级市,比如以湖南省为例,就是循环湘潭市、衡阳市等,基于这些城市的经纬度坐标,分别计算与省会长沙市的最快通勤距离。调用过程方法如下所示:
List<ProvincialCityDistance> dataList = new ArrayList<ProvincialCityDistance>();
for(int i = 1; i < cityList.size(); i++) {
GeographicNameVo sourceCity = cityList.get(i);
String origInfo = sourceCity.getLon() + "," + sourceCity.getLat();
String postStr = "%7B'orig':'" + origInfo + "','dest':'" + destInfo + "','style':'" + 0 + "'%7D";
HttpResponse<String> resp = tdtOptService.drivePlan(postStr, "search", TDT_SERVER_KEY);
JAXBContext context = JAXBContext.newInstance(TdtResult.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
TdtResult result = (TdtResult) unmarshaller.unmarshal(new StringReader(resp.getBodyResult()));
System.out.println("距离:" + result.getDistance());
System.out.println("时长:" + result.getDuration());
String geom = convertToLineStringWKT(result.getRoutelatlon());
geom = "SRID=" + 4326 + ";" + geom; // 拼接 srid,实现动态写入
System.out.println(geom);
ProvincialCityDistance dinstance = new ProvincialCityDistance(province_code, provinceName, new BigDecimal(result.getDistance()), sourceCity.getName(), geom, "tianditu");
dataList.add(dinstance);
}
由于调用的是天地图的 API,这里的 SRID 直接设置为 4326。如果是其他的导航平台,比如高德或者百度就需要进行坐标的转换。
4、导航路径入库
最后调用批量入库的方法,Mybatis_Plus 集成了许多方便的方法,可以进行数据操作。
// 执行入库
if(dataList.size() > 0) {
distanceService.saveBatch(dataList, 100);
}
上述代码执行后,可以在控制台看到输出表示数据成功的保存到数据库中。

三、成果展示
最后看看我们的成果,以湖南省、新疆自治区、黑龙江省为例,这三个省的省会及其地级市的距离情况。
1、湖南省最快行车距离展示
查询湖南省的各个地级市到省会长沙的具体 SQL 如下:
SELECT * , st_srid(geom) FROM biz_provincial_city_distance T WHERE T.province_code = '430000' ORDER BY distance;
可以看到在湖南省的各地级市中,距离长沙最近的是湘潭 60 公里,而最远的则是湘西州 387 公里。具体列表如下:
1948389936998682626 430000 湖南省 59.5900 湘潭市
1948389936734441473 430000 湖南省 73.2500 株洲市
1948389936998682632 430000 湖南省 78.6600 益阳市
1948389937334226946 430000 湖南省 139.1500 娄底市
1948389936998682629 430000 湖南省 155.4200 岳阳市
1948389936998682630 430000 湖南省 171.5900 常德市
1948389936998682627 430000 湖南省 191.4800 衡阳市
1948389936998682628 430000 湖南省 218.2000 邵阳市
1948389936998682634 430000 湖南省 312.9900 永州市
1948389936998682633 430000 湖南省 318.0400 郴州市
1948389936998682631 430000 湖南省 320.3500 张家界市
1948389936998682635 430000 湖南省 385.1900 怀化市
194837556525057 430000 湖南省 387.1100 湘西土家族苗族自治州

2、新疆自治区最快行车距离展示
下面再来看下我国最大的一个省份,新疆自治区的各地市与省会乌鲁木齐的距离又是多少呢?距离乌鲁木齐最近的是昌吉 35 公里,最远的则是 1334.7100 喀什。
1948410402484256769 650000 新疆维吾尔自治区 34.9700 昌吉回族自治州
1948410402400370690 650000 新疆维吾尔自治区 191.2700 吐鲁番市
1948410402513616897 650000 新疆维吾尔自治区 342.0900 巴音郭楞蒙古自治州
1948410402169683970 650000 新疆维吾尔自治区 389.7900 克拉玛依市
1948410402484256770 650000 新疆维吾尔自治区 519.0300 博尔塔拉蒙古自治州
1948410402400370691 650000 新疆维吾尔自治区 585.5400 哈密地区
1948410402832384004 650000 新疆维吾尔自治区 618.0900 塔城地区
1948410402832384005 650000 新疆维吾尔自治区 618.0900 塔城地区
1948410402832384003 650000 新疆维吾尔自治区 689.1600 伊犁哈萨克自治州
1948410402832384006 650000 新疆维吾尔自治区 793.7300 阿勒泰地区
1948410402513616898 650000 新疆维吾尔自治区 877.0100 阿克苏地区
1948410402832384002 650000 新疆维吾尔自治区 1278.1100 和田地区
1948410402652028930 650000 新疆维吾尔自治区 1294.6200 克孜勒苏柯尔克孜自治州
1948410402773663746 650000 新疆维吾尔自治区 1334.7100 喀什地区

3、黑龙江省最快行车距离展示
最后来看一下我国的北疆,黑龙江省的最快行车距离展示。使用客户端软件运行以上 sql 后,可以看到如下结果。距离哈尔滨最近的是绥化市 112 公里,最远的是黑河市 560 公里。
1948411772348157953 230000 黑龙江省 112.7800 绥化市
1948411772171997186 230000 黑龙江省 153.4400 大庆市
1948411771584794626 230000 黑龙江省 302.9300 齐齐哈尔市
1948411772171997187 230000 黑龙江省 322.4100 伊春市
1948411772171997190 230000 黑龙江省 330.8700 牡丹江市
1948411772171997188 230000 黑龙江省 380.4400 佳木斯市
1948411772171997189 230000 黑龙江省 427.0100 七台河市
1948411771853230081 230000 黑龙江省 444.5100 鹤岗市
1948411771853230082 230000 黑龙江省 452.5800 双鸭山市
1948411771765149697 230000 黑龙江省 477.3500 鸡西市
1948411772171997191 230000 黑龙江省 569.4200 黑河市

四、总结
本次实践聚焦于省域这一相对较大范围的地理区域,相较于城市内部的路线规划,省域驾车路线面临着更多的挑战。省域内道路网络更为复杂,涵盖了高速公路、国道、省道以及乡村道路等多种类型。与常规的两点之间直线最短的计算方式不同,在两个城市的行车距离计算中,往往两者的距离会超出直线距离。因此通过驾车距离的长短来衡量与省会城市的联系度,也可以作为衡量交通对地域经济影响的因素评估做参考。该方案实现了基于 GeoTools 和 SpringBoot 的省域驾车最快路线生成,从技术实现到系统优化,全方位呈现了项目的全貌。


