使用Java调用GeoTools实现全球国家矢量数据入库实战

目录

前言

一、相关数据介绍

1、无空间参考的数据

2、有空间参考的数据

3、空间信息表物理模型

二、全球国家空间数据入库

1、后台实体类图

 2、后台实体对象关键代码

三、时空数据入库实践

1、读取无空间参考数据

2、入库成果及注意事项

 四、总结


前言

        在当今世界,国家的构成和数量对国际关系、经济合作以及文化交流等方面都有深远的影响。根据最新的统计数据,目前全球共有233个国家和地区,这其中包括195个国家,而其中的193个国家是联合国的正式会员国。国家数量的变化不仅仅是地理政治的调整,更是历史的映射。例如,二十世纪的多次战争和殖民地的独立运动,使得全球的国家数量在短时间内显著增加。此外,南苏丹的独立(2011年)和科索沃的宣告独立(2008年)等事件,都是国际关系复杂性的体现。随着全球化的发展,经济和文化的交流更加频繁,各国间的依存度逐渐加深。这种现象不仅促使一些地区国家通过联合体形式确保集合安全和发展,如欧盟,还引发了部分国家对独立的渴望,努力争取更大的自主权。

        联合国自1945年成立以来,一直致力于促进国际间的合作,维护世界的和平与发展。它不仅是国家交流的重要平台,也是各国相互依赖、协调利益的重要场所。通过联合国,各国在经济、社会、环境、文化等多个领域进行合作。联合国的成员国数量在不断变化,反映出国际关系的动态背景。目前,193个成员国中有多个新兴市场国家和发展中国家的加入,推动了国际合作的多样性。与此同时,联合国的存在也体现了各国在国际事务中平等发言的权利与责任。总的来说,全球国家数量的统计不仅是数字游戏,更是理解世界现状的入口。国家的数量及其变化与历史、文化、外交乃至经济发展息息相关。未来,随着国际局势的变化,不同国家间的关系会更加错综复杂,这将影响全球治理的结构与模式。

        由此可见,不管是研究国际局势,还是研究全球性的经济、政治、金融往来甚至一些局部的冲突,地缘文化在国家的交流和往来当中都非常需要国家等关键信息。本文即以Java编程语言为例,重点讲解如何使用GeoTools来进行全球国家和地区的空间数据入库。为下一步做全球性的空间分析等积累数据基础。如果您也对如何处理全球国家和地区的数据有兴趣,不妨来这里看看。

一、相关数据介绍

        本文主要介绍相关技术,博客涉及的相关数据为从互联网上下载的共享数据。地图属于敏感的数据,请大家在使用相关的地图数据时,一定要注意,比如敏感的边界问题等等。这里有两份基本的数据,一份是没有设置空间参考的信息,但包含了国家的中文信息。另一份设置了4326的空间参考,但属性字段较乱,需要整理,因此我们结合两份数据来进行整合,提取出符合我们需要的空间信息。

1、无空间参考的数据

        下面这份数据是没有设置空间参考的全球国家矢量信息,我们使用Qgis软件打开数据可以看到以下的信息。

         打开矢量数据的属性信息表,首先来大致了解一下这份数据对应的属性信息列表。

         这里请大家注意无空间参考的数据的属性信息及属性表格。介绍完无空间参考的数据后,再来介绍一下有空间参考的数据。

2、有空间参考的数据

        顾名思义,这里的数据是定义了空间参考的,不仅如此。它的属性列表和字段也是比之前的数据多的。我们可以打开QGIS软件来看一下具体的数据信息。

        同样的,我们打开属性表格来看一下这份数据的属性表格。 

         对比前面的无空间参考的数据,可以看到这份数据的数据列更多。但是在实际情况下,我们根据需求可以不展示这么多信息。

3、空间信息表物理模型

        在本文的数据处理过程中,我们将两份数据进行求交集。通过一个三字码简称来实现国家信息的关联。在无空间信息参考的shp表格中参考中文信息。作为现实世界的映射,我们设计的空间表如下所示:

        这里提供物理表结构的SQL脚本如下:

CREATE TABLE "public"."biz_world_contry" (
  "pk_id" int8 NOT NULL,
  "full_english_name" varchar(255) COLLATE "pg_catalog"."default",
  "short_english_name" varchar(255) COLLATE "pg_catalog"."default",
  "min_english_name" varchar(50) COLLATE "pg_catalog"."default",
  "full_chinese_name" varchar(255) COLLATE "pg_catalog"."default",
  "short_chinese_name" varchar(255) COLLATE "pg_catalog"."default",
  "continent" varchar(50) COLLATE "pg_catalog"."default",
  "unreg" varchar(50) COLLATE "pg_catalog"."default",
  "geom" "public"."geometry"
);
COMMENT ON COLUMN "public"."biz_world_contry"."full_english_name" IS '英文全称';
COMMENT ON COLUMN "public"."biz_world_contry"."short_english_name" IS '英文简称';
COMMENT ON COLUMN "public"."biz_world_contry"."min_english_name" IS '最简名称';
COMMENT ON COLUMN "public"."biz_world_contry"."full_chinese_name" IS '中文全称';
COMMENT ON COLUMN "public"."biz_world_contry"."short_chinese_name" IS '中文简称';
COMMENT ON COLUMN "public"."biz_world_contry"."continent" IS '所属大洲,如Asia';
COMMENT ON COLUMN "public"."biz_world_contry"."unreg" IS '大洲详情';
COMMENT ON COLUMN "public"."biz_world_contry"."geom" IS 'geom';
COMMENT ON TABLE "public"."biz_world_contry" IS '世界国家信息表';

         为了加速查询速度,这里我们创建两个普通索引和一个空间索引,创建索引的SQL语句如下,供大家参考:

CREATE INDEX "idx_biz_world_contry_continent" ON "public"."biz_world_contry" USING btree (
  "continent" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
CREATE INDEX "idx_biz_world_contry_geom" ON "public"."biz_world_contry" USING gist (
  "geom" "public"."gist_geometry_ops_2d"
);
CREATE INDEX "idx_biz_world_contry_min_englis" ON "public"."biz_world_contry" USING btree (
  "min_english_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);

二、全球国家空间数据入库

        在了解了上述的两份空间数据的基础数据和时空数据库表结构之后,接下来就可以来进行空间数据库入库的相关功能开发。这里将从相关的类图、调用流程图等方面来进行介绍。

1、后台实体类图

        为了实现对空间数据的读取与空间入库,可以分为以下的几个类来实现业务逻辑,包含三个最简单的基本实体类,分别读取无空间参考的实体类和有空间参考索引的实体类,还有一个与空间表对应的数据库表实体。

 2、后台实体对象关键代码

        有了上述的类图后,接下来将重点提供后台的实体对象及相关模型层的相关代码。方便大家在处理数据时方便进行相关的做参考。空间数据表模型实体类如下:

package com.yelang.project.extend.earthquake.domain;

import java.io.Serializable;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.handler.PgGeometryTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 世界国家信息
 * @author 夜郎king
 *
 */
@TableName(value = "biz_world_contry", autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class WorldCountries implements Serializable{
	private static final long serialVersionUID = -5984870862010624612L;
	@TableId(value="pk_id")
	private Long pkId;//
	@TableField(value="full_english_name")
	private String fullEnglishName;//英文全称
	@TableField(value="short_english_name")
	private String shortEnglishName;//英文简称
	@TableField(value="min_english_name")
	private String minEnglishName;//最简名称
	@TableField(value="full_chinese_name")
	private String fullChineseName;//中文全称
	@TableField(value="short_chinese_name")
	private String shortChineseName;
	private String continent;//所属大洲,如:Asia
	private String unreg;//大洲详情
	@TableField(typeHandler = PgGeometryTypeHandler.class)
	private String geom;
	@TableField(exist=false)
	private String geomJson;
	public WorldCountries(String fullEnglishName, String shortEnglishName, String minEnglishName,
			String fullChineseName, String shortChineseName, String continent, String unreg, String geom) {
		super();
		this.fullEnglishName = fullEnglishName;
		this.shortEnglishName = shortEnglishName;
		this.minEnglishName = minEnglishName;
		this.fullChineseName = fullChineseName;
		this.shortChineseName = shortChineseName;
		this.continent = continent;
		this.unreg = unreg;
		this.geom = geom;
	}
}

        有空间参考的实体类关键代码如下:

package com.yelang.project.extend.earthquake.domain;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * - 设置坐标参考系的全球国家信息
 * @author 夜郎king
 *
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WorldCountriesWithCRS implements Serializable{
	private static final long serialVersionUID = -2200848007577967594L;
	private String geom;
	private String name;
	private String iso3;//简称
	private String continent;//所属洲,比如亚洲、美洲等
	private String unreg1;
	private Integer eu;//是否欧盟
}

无空间参考实体类的关键代码如下:

package com.yelang.project.extend.earthquake.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * - 没有设置坐标参考系的全球国家信息
 * @author 夜郎king
 *
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WorldCountriesWithNoCRS implements Serializable{
	private static final long serialVersionUID = 9034823653023305410L;
	private String name;//英文名称
	private String feName;//英文全称
	private String fcName;//国家中文名
	private String soc;//英文简称
	private BigDecimal pop = new BigDecimal("0");//人口
}

        以上就是三个基础的实体类。在进行空间数据库的操作时,采用的是Mybatis-Plus技术框架,在前面的博客中,关于Mybatis-plus如何操作空间数据库,花了很多的时间来进行处理,因此这里不再进行赘述。

三、时空数据入库实践

        最后重点来介绍如何进行时空数据的入库,将实现两份空间数据的读取,然后进行数据合并,最后调用Mybatis-plus来进行数据入库。

1、读取无空间参考数据

        业务逻辑不复杂,这里调用Geotools组件来实现Shapefile文件的读取。这里直接给出相关的代码,里面的具体字段,大家可以根据实际情况来进行替换即可。

private static List<WorldCountriesWithNoCRS> ReadWorldContriesWithNoCRS() throws IOException, FactoryException {
		// 指定Shapefile的文件路径
		String shpFile = "F:/vector_data/世界国家行政边界数据/世界国家行政边界数据/世界国家.shp";//没有参考坐标
		ShapefileDataStore shapefileDataStore = new ShapefileDataStore(new File(shpFile).toURI().toURL());
		shapefileDataStore.setCharset(Charset.forName("GBK"));// 设置中文字符编码
		// 获取特征类型
		SimpleFeatureType featureType = shapefileDataStore.getSchema(shapefileDataStore.getTypeNames()[0]);
		CoordinateReferenceSystem crs = featureType.getGeometryDescriptor().getCoordinateReferenceSystem();
		System.out.println("坐标参考系统:" + crs);
		Integer epsgCode = 0;
		if(crs != null) {
			epsgCode = CRS.lookupEpsgCode(crs, true);
		}
		SimpleFeatureSource featureSource = shapefileDataStore.getFeatureSource();
		SimpleFeatureCollection simpleFeatureCollection=featureSource.getFeatures();
        SimpleFeatureIterator itertor = simpleFeatureCollection.features();
        //遍历featurecollection
        List<WorldCountriesWithNoCRS> list = new ArrayList<WorldCountriesWithNoCRS>();
        while (itertor.hasNext()){
            SimpleFeature feature = itertor.next();
            Property nameProperty = feature.getProperty("NAME");
            String name = (String)nameProperty.getValue();
            Property feNameProperty = feature.getProperty("FENAME");
            String feName = (String) feNameProperty.getValue();
            Property fcNameProperty = feature.getProperty("FCNAME");
            String fcName = (String)fcNameProperty.getValue();
            Property socProperty = feature.getProperty("SOC");
            String soc = (String)socProperty.getValue();
            Property popProperty = feature.getProperty("POP");
            BigDecimal pop = new BigDecimal(String.valueOf(popProperty.getValue()));
         	WorldCountriesWithNoCRS wc = new WorldCountriesWithNoCRS(name, feName, fcName, soc, pop);
         	list.add(wc);
        }
        System.out.println(list.size());
        return list;
	}

        这里需要注意的是,由于这里没有设置空间参考,因此我们没有进行空间geometry属性的读取。在后面的已设置空间参考的数据中来进行获取。接下来我们来实现有空间参考信息的数据读取:

private static List<WorldCountriesWithCRS> ReadWorldContriesWithCRS() throws IOException, FactoryException {
		// 指定Shapefile的文件路径
		String shpFile = "F:/vector_data/世界国家_WGS84/countries.shp";//有参考坐标
		ShapefileDataStore shapefileDataStore = new ShapefileDataStore(new File(shpFile).toURI().toURL());
		//shapefileDataStore.setCharset(Charset.forName("UTF-8"));// 设置中文字符编码
		// 获取特征类型
		SimpleFeatureType featureType = shapefileDataStore.getSchema(shapefileDataStore.getTypeNames()[0]);
		CoordinateReferenceSystem crs = featureType.getGeometryDescriptor().getCoordinateReferenceSystem();
		System.out.println("坐标参考系统:" + crs);
		Integer epsgCode = 0;
		if(crs != null) {
			epsgCode = CRS.lookupEpsgCode(crs, true);
		}
		SimpleFeatureSource featureSource = shapefileDataStore.getFeatureSource();
		SimpleFeatureCollection simpleFeatureCollection=featureSource.getFeatures();
        SimpleFeatureIterator itertor = simpleFeatureCollection.features();
        //遍历featurecollection
        List<WorldCountriesWithCRS> list = new ArrayList<WorldCountriesWithCRS>();
        while (itertor.hasNext()){
            SimpleFeature feature = itertor.next();
            Property nameProperty = feature.getProperty("NAME");
            String name = (String)nameProperty.getValue();
            Property iso3Property = feature.getProperty("ISO3");
            String iso3 = (String) iso3Property.getValue();
            Property continentProperty = feature.getProperty("CONTINENT");
            String continent = (String)continentProperty.getValue();
            Property unreg1Property = feature.getProperty("UNREG1");
            String unreg1 = (String)unreg1Property.getValue();
            Property euProperty = feature.getProperty("EU");
            Integer eu = (Integer)euProperty.getValue();
            // 获取空间字段
         	org.locationtech.jts.geom.Geometry geometry = (org.locationtech.jts.geom.Geometry) feature.getDefaultGeometry();
            // 创建WKTWriter对象
         	WKTWriter wktWriter = new WKTWriter();
         	// 将Geometry对象转换为WKT格式的字符串
         	String wkt = wktWriter.write(geometry);
         	String geom = "SRID=" + epsgCode +";" + wkt;//拼接srid,实现动态写入
         	WorldCountriesWithCRS wc = new WorldCountriesWithCRS(geom, name, iso3, continent, unreg1, eu);
         	list.add(wc);
        }
        System.out.println(list.size());
        return list;
	}

        最后我们按照国家的简称来将List集合转变成Map集合,在后续的数据查找时,只需要按照简称来查询就可以快速的找到对应的国家信息,最后将数据插入到PostGIS空间数据库中。关键代码如下:

@Test
public void readShpData() throws IOException, FactoryException {
	List<WorldCountriesWithNoCRS> noCrsList = ReadWorldCountry2DB.ReadWorldContriesWithNoCRS();
	Map<String,WorldCountriesWithNoCRS> noCrsMap = new HashMap<String,WorldCountriesWithNoCRS>();
	for(WorldCountriesWithNoCRS noCrs : noCrsList) {
		noCrsMap.put(noCrs.getSoc(), noCrs);
	}
	System.out.println("--------------------------------------------------------");
	List<WorldCountriesWithCRS> crsList = ReadWorldCountry2DB.ReadWorldContriesWithCRS();
	List<WorldCountries> toDbDataList = new ArrayList<WorldCountries>();
	for(WorldCountriesWithCRS crs : crsList) {
		String fullChineseName = "";
		if(noCrsMap.containsKey(crs.getIso3())) {
			WorldCountriesWithNoCRS noCrs = noCrsMap.get(crs.getIso3());
			fullChineseName = noCrs.getFcName();
		}
		WorldCountries dbWc = new WorldCountries(crs.getName(), crs.getName(), crs.getIso3(), fullChineseName, fullChineseName, crs.getContinent(), crs.getUnreg1(), crs.getGeom());
		toDbDataList.add(dbWc);
	}
	if(toDbDataList.size() > 0) {
		worldCountryService.saveBatch(toDbDataList,100);
	}
}

2、入库成果及注意事项

        在使用Junit中运行上述代码后,即将全球数据信息插入到空间数据中。接下来我们将使用数据库端软件来验证是否成功的将数据插入到空间数据库中。这里我们以pgAdmin为例来进行讲解。我们在PgAdmin中打开查询窗口,然后执行以下语句:

select st_srid(geom),* from biz_world_contry;

        同时我们还可以执行空间信息查询,将相应的国家信息展示出来,以日本、德国为例,查询的sql语句如下,其中xxx表示具体的国家名字:

select * from biz_world_contry t where t.full_chinese_name = 'xxx';

        对于查询出来的结果,可以直接在查询结果中点击空间信息预览按钮来进行预览。

        需要注意的点:在进行复杂面数据的空间入库时,需要注意在插入数据时,关闭打印功能,这样可以显著提高插入效率。

 四、总结

        以上就是本文的主要内容,本文即以Java编程语言为例,重点讲解如何使用GeoTools来进行全球国家和地区的空间数据入库。为下一步做全球性的空间分析等积累数据基础。行文仓促,难免有许多不足之处,在此恳请各位专家博主在评论区留下真知灼见,在此表示感谢。

        博文编写过程中,参考以下内容,在此表示感谢。

        1、全球国家数量揭秘:目前究竟有多少个国家

        2、你知道世界上有多少个国家吗?各国的国旗都认识吗?

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜郎king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值