当前位置:   article > 正文

基于Java和GDAL实现的GeoJSON数据读取与入库实践

基于Java和GDAL实现的GeoJSON数据读取与入库实践

目录

前言

一、基础数据介绍

1、 数据格式

2、数据参数

二、空间数据库设计

1、主体表模型

2、DDL语句与空间索引

三、GDAL解析及入库

1、GDAL中GeoJSON驱动

2、解析GeoJSON

3、Java模型

4、数据入库

总结


前言

        在面向空间的矢量数据处理过程当中,虽然shapefile等文件是常用矢量文件的载体。也是大多数应用用来支持矢量文件存储的对象。其实除了shagefile这种格式,还有很多种格式。今天介绍一种在webgis比较常见的数据格式,它就是GeoJSON。

        GeoJSON是一种对各种地理数据结构进行编码的格式,基于Javascript对象表示法(JavaScript Object Notation, 简称JSON)的地理空间信息数据交换格式。GeoJSON对象可以表示几何、特征或者特征集合。GeoJSON支持下面这几种几何类型:点、线、面、多点、多线、多面和几何集合。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。

        一个完整的GeoJSON数据结构总是一个(JSON术语里的)对象。在GeoJSON里,对象由名/值对--也称作成员的集合组成。对每个成员来说,名字总是字符串。成员的值要么是字符串、数字、对象、数组,要么是下面文本常量中的一个:"true","false"和"null"。数组的值是上面所说的元素组成。

        GeoJSON的格式

GeoJSON总是由一个单独的对象组成。这个对象(指的是下面的GeoJSON对象)表示几何、特征或者特征集合。

  • GeoJSON对象可能有任何数目成员(名/值对)。

  • GeoJSON对象必须有一个名字为"type"的成员。这个成员的值是由GeoJSON对象的类型所确定的字符串。

  • type成员的值必须是下面之一:"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "GeometryCollection", "Feature", 或者 "FeatureCollection"。这些值分别对应:点、多点、线、多线、面、多面、几何集合、特征、特征集合。

  • GeoJSON对象可能有一个可选的"crs"成员,它的值必须是一个坐标参考系统的对象。

  • GeoJSON对象可能有一个"bbox"成员,它的值必须是边界框数组。

  1. {
  2. "type": "FeatureCollection",
  3. "features": [{
  4. "type": "Feature",
  5. "geometry": {
  6. "type": "Point",
  7. "coordinates": [102.0, 0.5]
  8. },
  9. "properties": {
  10. "prop0": "value0"
  11. }
  12. }, {
  13. "type": "Feature",
  14. "geometry": {
  15. "type": "LineString",
  16. "coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]
  17. },
  18. "properties": {
  19. "prop0": "value0",
  20. "prop1": 0.0
  21. }
  22. }, {
  23. "type": "Feature",
  24. "geometry": {
  25. "type": "Polygon",
  26. "coordinates": [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]
  27. },
  28. "properties": {
  29. "prop0": "value0",
  30. "prop1": {
  31. "this": "that"
  32. }
  33. }
  34. }
  35. ]
  36. }

        本文将重点讲解在Java中如何调用GDAL进行GeoJSON矢量数据处理,首先使用QGIS工具展示待处理的地名GeoJSON数据,然后介绍在PostGIS空间数据库中创建空间表,最后介绍基于Java语言调用GDAL将GeoJSON进行空间数据入库。如果当前您也有GeoJSON数据的处理,不妨来博客指导一二。

一、基础数据介绍

        今天要处理的示例数据是地名数据,原始数据由GISer last 分享,大家有兴趣的可以在他的个人公众号下回复消息,及时获取信息。时间大概是2015年左右的全国分级数据,有省会城市地名、地级市地名、县级市地名、区县地名等,都是以GeoJSON形式的保存的。       

        本小节以Qgis为例,对下载下来的GeoJSON数据进行处理。包括空间可视化、属性数据展示、地图标注等。GeoJSON其实也是一种json,只是在普通的json上面增加了空间数据的属性和规范。所以我们可以直接使用文本的形式来进行数据的编辑与展示。

1、 数据格式

        地名数据主要是一些点位数据,除了在乡镇一级数据条数多一点之外,其它都还可以都没有超过MB。下面使用Qgis对这些数据打开来看一下。

        将GeoJSON数据加载到Qgis当中去之后,查看这些空间数据的属性。比如投影信息、属性信息等等。为了方便数据的展示,辅助添加了省级行政区划矢量数据。打开相关标注后,可以看到x效果如下:

 省会地名数据示意图

 地级市地名示意图

 县级市地名示意图

2、数据参数

        在qgis中查看数据的属性信息,可以看到如下信息。

序号参数说明
1存储类型

GeoJSON

2编码UTF-8
3几何图形

Point (Point)

4坐标参考系

EPSG:4326 - WGS 84 - 地理的

5范围

87.6149638000000550,20.0500348290000261 : 126.5286520170000131,45.8019539320000604

6单位

        数据属性信息如下:

序号属性名数据类型说明
1NAMEString地名
2PIINYINString地名拼音
3CLASSString类型
4BZString备注
5SLXString应该是标记,暂无特殊含义

序号数据名称数据条数
1省会城市地名29
2地级市地名283
3县级市地名339
4区县地名2567

 有了上面的数据参数基础和属性数据基础之后。下面我们介绍如何进行空间数据库表的设计。

二、空间数据库设计

        为了将GeoJSON数据保存到空间数据,我们需要设计对应的数据库表。这里我们采用PostGIS数据库,数据表采用PostGIS中的空间表。本小节将重点讲解讲解空间表的设计。

1、主体表模型

        为了实现数据对象到数据库物理模型的对应。针对上述业务,我们建立1对1的映射。保留原有空间属性的独立性,同时增加表主键以及关键的空间信息字段geom。为了后续我们方便的对空间数据进行空间索引查询,在geom列上,我们构建了关键的GIST空间索引。

2、DDL语句与空间索引

        请注意,空间索引必须要创建,否则在进行空间查询时性能很慢。提前新建好索引,对后续的性能提升有很大的帮助。

  1. CREATE TABLE "public"."biz_geographic_name" (
  2. "pk_id" int8 NOT NULL,
  3. "name" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
  4. "pinyin" varchar(255) COLLATE "pg_catalog"."default",
  5. "classz" varchar(4) COLLATE "pg_catalog"."default",
  6. "bz" varchar(100) COLLATE "pg_catalog"."default",
  7. "slx" varchar(20) COLLATE "pg_catalog"."default",
  8. "geom" "public"."geometry" NOT NULL,
  9. CONSTRAINT "pk_biz_geographic_name" PRIMARY KEY ("pk_id")
  10. )
  11. ;
  12. ALTER TABLE "public"."biz_geographic_name"
  13. OWNER TO "ghy01";
  14. CREATE INDEX "idex_biz_geographic_name_classz" ON "public"."biz_geographic_name" USING btree (
  15. "classz" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
  16. );
  17. CREATE INDEX "idx_biz_geographic_name_geom" ON "public"."biz_geographic_name" USING gist (
  18. "geom" "public"."gist_geometry_ops_2d"
  19. );
  20. COMMENT ON COLUMN "public"."biz_geographic_name"."pk_id" IS '主键id';
  21. COMMENT ON COLUMN "public"."biz_geographic_name"."name" IS '地名';
  22. COMMENT ON COLUMN "public"."biz_geographic_name"."pinyin" IS '汉语拼音';
  23. COMMENT ON COLUMN "public"."biz_geographic_name"."classz" IS 'classz';
  24. COMMENT ON COLUMN "public"."biz_geographic_name"."bz" IS '备注';
  25. COMMENT ON COLUMN "public"."biz_geographic_name"."slx" IS 'slx';
  26. COMMENT ON COLUMN "public"."biz_geographic_name"."geom" IS '空间对象';
  27. COMMENT ON TABLE "public"."biz_geographic_name" IS '地名基础信息表,用于存储中国范围内的地名信息';

        至此,我们完成了地名表的空间数据库表的设计,同时根据业务需要,创建了数据索引。 

三、GDAL解析及入库

        本节主要讲解如何利用GDAL来进行数据的解析,使用详细的代码讲解如何解析GeoJSON数据,最后调用MP框架实现将GeoJSON数据保存到空间数据库。

1、GDAL中GeoJSON驱动

        在Gdal中,针对不同的数据格式,使用不同的驱动包来解析支持。与解析shapefile的方式一致。解析GeoJSON使用GeoJSON驱动。此驱动程序实现对访问编码在中的功能的读/写支持 GeoJSON 格式。GeoJSON是一种基于 JavaScript Object Notation
(JSON) . JSON是一种用于数据交换的轻量级纯文本格式,GeoJSON只不过是它对地理内容的专门化。

  • FLATTEN_NESTED_ATTRIBUTES =是/否:是否递归地探索嵌套对象并生成扁平OGR属性。默认为否。

  • NESTED_ATTRIBUTE_SEPARATOR =字符:嵌套属性组件之间的分隔符。默认为“

  • FEATURE_SERVER_PAGING =是/否:是否使用ArcGIS功能服务终结点自动滚动结果。

  • NATIVE_DATA =是/否:(GDAL>=2.1)是否在FeatureCollection和Feature级别存储本机JSon表示。默认为否。此选项可用于通过保留一些额外的JSon对象来改进从GeoJSON到GeoJSON的往返,否则OGR抽象将忽略这些额外的JSon对象。请注意,ogr2ogr在默认情况下启用此选项,除非指定其-noNativeData开关。

  • ARRAY_AS_STRING =YES/NO:(GDAL>=2.1)是否将字符串、整数或实数的JSon数组作为OGR字符串公开。默认为“否”。也可以使用 OGR_GEOJSON_ARRAY_AS_STRING 配置选项。

  • DATE_AS_STRING =YES/NO:(GDAL>=3.0.3)是使用专用的OGR日期/时间/日期时间类型还是作为OGR字符串公开日期/时间/日期时间内容。默认值为NO(即检测到日期/时间/日期-时间)。也可以用 OGR_GEOJSON_DATE_AS_STRING 配置选项。

2、解析GeoJSON

        在Java中解析GeoJSON的关键代码如下:

  1. @Test
  2. public void readDjsGeoJSON() {
  3. // 指定文件的名字和路径
  4. String strVectorFile = "path/2015省市区县乡镇地名数据/地名点_地级市.geojson";
  5. // 注册所有的驱动
  6. ogr.RegisterAll();
  7. gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
  8. gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
  9. String strDriverName = "GeoJSON";
  10. org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
  11. if (oDriver == null) {
  12. System.out.println(strDriverName + " 驱动不可用!\n");
  13. return;
  14. }
  15. DataSource dataSource = oDriver.Open(strVectorFile);
  16. Layer layer = dataSource.GetLayer(0);
  17. SpatialReference spatialReference = layer.GetSpatialRef();
  18. String srid = spatialReference.GetAttrValue("AUTHORITY", 1);
  19. long featureCount = layer.GetFeatureCount();
  20. List<GeographicName> list = new ArrayList<GeographicName>();
  21. for (int i = 0; i < featureCount; i++) {
  22. Feature feature = layer.GetFeature(i);
  23. String name = feature.GetFieldAsString("NAME");
  24. String pinyin = feature.GetFieldAsString("PINYIN");
  25. String classz = feature.GetFieldAsString("CLASS");
  26. String bz = feature.GetFieldAsString("BZ");
  27. String slx = feature.GetFieldAsString("SLX");
  28. Geometry geom = feature.GetGeometryRef();
  29. //step 1、生成原始wkt
  30. String wkt = geom.ExportToWkt();
  31. wkt = "SRID=" + srid +";" + wkt;//拼接srid,实现动态写入
  32. list.add(new GeographicName(name, pinyin, classz, bz, slx, wkt));
  33. System.out.println("name=" + name + "\tclassz=" + classz+ "\twkt="+ wkt);
  34. }
  35. geographicNameService.saveBatch(list,300);
  36. dataSource.delete();
  37. gdal.GDALDestroyDriverManager();
  38. }

3、Java模型

        下面提供基础的Java实体模型,其它比如Mapper和Service对象,不进行代码说明。

  1. package com.yelang.project.extend.earthquake.domain;
  2. import java.io.Serializable;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableId;
  5. import com.baomidou.mybatisplus.annotation.TableName;
  6. import com.yelang.framework.handler.PgGeometryTypeHandler;
  7. import lombok.AllArgsConstructor;
  8. import lombok.Data;
  9. import lombok.NoArgsConstructor;
  10. import lombok.ToString;
  11. @Data
  12. @ToString
  13. @AllArgsConstructor
  14. @NoArgsConstructor
  15. @TableName(value ="biz_geographic_name",autoResultMap = true)
  16. public class GeographicName implements Serializable{
  17. private static final long serialVersionUID = -3694849578429480952L;
  18. @TableId(value = "pk_id")
  19. private Long pkId;
  20. private String name;
  21. private String pinyin;
  22. private String classz;
  23. private String bz;
  24. private String slx;
  25. public GeographicName(String name, String pinyin, String classz, String bz, String slx, String geom) {
  26. super();
  27. this.name = name;
  28. this.pinyin = pinyin;
  29. this.classz = classz;
  30. this.bz = bz;
  31. this.slx = slx;
  32. this.geom = geom;
  33. }
  34. @TableField(typeHandler = PgGeometryTypeHandler.class)
  35. private String geom;
  36. @TableField(exist=false)
  37. private String geomJson;
  38. }

4、数据入库

        使用junit进行代码测试,将数据批量插入到数据库中。

        在程序的控制台中可以看到以下的输出,表名在执行数据库的插入操作:

        最后来数据库中是否有批量插入的地名信息,使用以下查询语句:

select * from biz_geographic_name;

        使用navicat可以连接数据库,看到在数据库中已经成功的将地级市的地名数据插入到空间数据中。 

总结

        以上就是本文的主要内容,本文将重点讲解在Java中如何调用GDAL进行GeoJSON矢量数据处理,首先使用QGIS工具展示待处理的地名GeoJSON数据,然后介绍在PostGIS空间数据库中创建空间表,最后介绍基于Java语言调用GDAL将GeoJSON进行空间数据入库。文章行文仓促,定有不足支持,关于文章的任何不足之处,都欢迎各位朋友在评论区留言批评指正交流,不慎感谢。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/515369
推荐阅读
相关标签
  

闽ICP备14008679号