当前位置: 首页 > news >正文

GeoTools 将 Shp 导入PostGIS 空间数据库

前言

GeoTools 在空间数据转换处理方面具有强大的能力,能够高效、简洁的操纵 Shp 数据。特别是与空间数据库PostGIS 相结合,更能展示出其空间数据处理的优势,借助 GeoTools,我们可以实现 Shp 数据高效入库。

本文上接系列文章

1. 环境搭建

在进行GeoTools开发前,需要先完成一些准备工作。俗话说,工欲善其事,必先利其器,只有将前期工作做好了,才能更好的推进往后的开发工作。

以下是环境搭建的一些软件工具,包括JDKMaven以及IDE

  • JDK:当前例子中使用的 JDK版本为11,需要先行下载,并设置好环境变量。
  • Maven:当前例子中使用的 Maven版本是 3.6.3,需要先行下载,并配置好仓库地址。
  • IDE:当前例子中使用的 IDEIDEA 2020.3,需要先行下载,并进行项目配置。
  • GeoTools:当前例子中使用的版本是 34-SNAPSHOT

2. 下载依赖

在以前依赖的基础上,需要下载以下两个包。对于其他依赖,请参考之前的文章。

<!-- postgis-jdbc -->
<dependency>
  <groupId>org.geotools.jdbc</groupId>
  <artifactId>gt-jdbc-postgis</artifactId> 
  <version>${geotools.version}</version>
</dependency>
<!-- PostgreSQL 驱动 -->
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.7.3</version>
</dependency>

3. 数据入库

3.1. 读取数据

在目标路径下新建一个类Shp2PostGIS,用于操作将Shp数据导入到PostGIS空间数据库。在以下代码中读取Shp文件,并将其转换为URL

String shpPath = "C:\Users\hasee\Desktop\county\county.shp";
File shpFile = new File(shpPath);

Map<String,Object> params = new HashMap<>();
params.put("url",shpFile.toURI().toURL());

// 数据存储器
DataStore dataStore = DataStoreFinder.getDataStore(params);
String typeName = dataStore.getTypeNames()[0];
FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = dataStore.getFeatureSource(typeName);

3.2. 创建数据库连接

本例中数据库连接参数要使用PostgisNGDataStoreFactory.DBTYPE.key构建。注意一下PORTPASSWD参数为字符串类型,需要使用双引号,否则会导致数据库连接失败。SCHEMA模式参数也需要特别指定,通常为"public"

// 连接PostGIS数据库
Map<String,Object> pgParams = new HashMap<>();
pgParams.put(PostgisNGDataStoreFactory.DBTYPE.key,"postgis");
pgParams.put(PostgisNGDataStoreFactory.HOST.key,"localhost");
pgParams.put(PostgisNGDataStoreFactory.PORT.key,"5432");
pgParams.put(PostgisNGDataStoreFactory.DATABASE.key,"geodata");
pgParams.put(PostgisNGDataStoreFactory.USER.key,"postgres");
pgParams.put(PostgisNGDataStoreFactory.PASSWD.key,"123456");
pgParams.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");

在进行数据操作前,需要对数据库是否正常连接进行检查。

DataStore pgDataStore = DataStoreFinder.getDataStore(pgParams);
if(pgDataStore == null){
    System.err.println("数据库连接失败分析?:");
    PostgisNGDataStoreFactory factory = new PostgisNGDataStoreFactory();
    if (!factory.canProcess(params)) {
        System.err.println("参数不满足工厂要求");
    }
    if (!factory.isAvailable()) {
        System.err.println("工厂类未加载");
    }
    throw new RuntimeException("数据库连接失败,请检查上述原因");
}
System.out.println("数据库成功连接!");

3.3. 数据入库

如果数据连接成功,则可以操纵数据入库。使用数据源名称在数据库中创建一张同名表,将事务操作模式修改为"import",然后遍历所有数据,将其写入数据库表中。

// 获取数据表名称
SimpleFeatureType schema = featureSource.getSchema();
// 在数据库中创建表
pgDataStore.createSchema(schema);

// 数据导入
Transaction transaction = new DefaultTransaction("import");
try(FeatureWriter<SimpleFeatureType,SimpleFeature> writer =
            pgDataStore.getFeatureWriterAppend(schema.getTypeName(),transaction)){

    FeatureCollection<SimpleFeatureType,SimpleFeature> features  = featureSource.getFeatures();
    try(FeatureIterator<SimpleFeature> iterator = features.features()){
        while (iterator.hasNext()){
            SimpleFeature feature = iterator.next();
            SimpleFeature newFeature = writer.next();
            newFeature.setAttributes(feature.getAttributes());
            writer.write();
        }
    }
    transaction.commit();
}catch (Exception e){
    transaction.rollback();
    throw e;
}

示例中Shp数据名称为county,为全国县级行政区数据,导入效果如下。

"layer"为新字段名称,"LAYER"为旧字段名称targetFeature.setAttribute("layer",feature.getAttribute("LAYER"));

4. 高级操作

4.1. 删除表

在数据正式入库前,判断目标表是否存在,如果存在则将其删除,否则创建新表。

DataStore pgDataStore = DataStoreFinder.getDataStore(pgParams);
if(pgDataStore == null){
    System.err.println("数据库连接失败分析?:");
    PostgisNGDataStoreFactory factory = new PostgisNGDataStoreFactory();
    if (!factory.canProcess(params)) {
        System.err.println("参数不满足工厂要求");
    }
    if (!factory.isAvailable()) {
        System.err.println("工厂类未加载");
    }
    throw new RuntimeException("数据库连接失败,请检查上述原因");
}
System.out.println("数据库成功连接!");

String[] typeNames = pgDataStore.getTypeNames();
Boolean tableExists = false;
// 检查数据表是否存在
for(String name :typeNames){
    if(name.equals(tableName)){
        tableExists = true;
        break;
    }
}
if(tableExists){
    System.out.println("开始删除数据表!");
    pgDataStore.removeSchema(tableName);
    System.out.println("删除数据表完成!");
}
// 在数据库中创建表
pgDataStore.createSchema(schema);

4.2. 修改数据字段

原始数据中LAYER、NAME字段为大写形式,并且几何字段为默认的the_geom,不符合我的需求,我需要将大写字段修改为小写,然后将the_geom字段删除,添加新的几何字段geom设置目标表明,并且添加和删除或者修改目标字段。

// 目标表名称
String tableName = "county";

// 定义新字段结构
SimpleFeatureType sourceType = dataStore.getSchema(typeName);
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.init(sourceType);
// 数据库表名
typeBuilder.setName(tableName);

// 重命名字段
typeBuilder.remove("the_geom");
typeBuilder.add("gid",Long.class);
typeBuilder.remove("LAYER");      // 删除旧字段
typeBuilder.add("layer",sourceType.getDescriptor("LAYER").getType().getBinding());

typeBuilder.remove("NAME");      // 删除旧字段
typeBuilder.add("name",sourceType.getDescriptor("NAME").getType().getBinding());
// 几何字段
typeBuilder.add("geom",sourceType.getGeometryDescriptor().getType().getBinding());

使用setAttribute填入属性值,gid为自定义的自增键。

targetFeature.setAttribute("gid", idInit++);
targetFeature.setAttribute("layer",feature.getAttribute("LAYER"));
targetFeature.setAttribute("name",feature.getAttribute("NAME"));
targetFeature.setAttribute("kind",feature.getAttribute("kind"));
targetFeature.setAttribute("geom",feature.getDefaultGeometry());

修改数据后导入效果如下。

5. 完整代码

public static void main(String args[]) throws Exception{
    String shpPath = "C:\Users\hasee\Desktop\county\county.shp";
    File shpFile = new File(shpPath);

    Map<String,Object> params = new HashMap<>();
    params.put("url",shpFile.toURI().toURL());
    params.put("create spatial index", Boolean.TRUE);
    // 禁用fid生成参数设置
    params.put("useExistingSchema", Boolean.TRUE);
    // 数据存储器
    DataStore dataStore = DataStoreFinder.getDataStore(params);
    String typeName = dataStore.getTypeNames()[0];

    // 目标表名称
    String tableName = "county";

    // 定义新字段结构
    SimpleFeatureType sourceType = dataStore.getSchema(typeName);
    SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
    typeBuilder.init(sourceType);
    // 数据库表名
    typeBuilder.setName(tableName);

    // 重命名字段
    typeBuilder.remove("the_geom");
    typeBuilder.add("gid",Long.class);
    typeBuilder.remove("LAYER");      // 删除旧字段
    typeBuilder.add("layer",sourceType.getDescriptor("LAYER").getType().getBinding());

    typeBuilder.remove("NAME");      // 删除旧字段
    typeBuilder.add("name",sourceType.getDescriptor("NAME").getType().getBinding());
    // 几何字段
    typeBuilder.add("geom",sourceType.getGeometryDescriptor().getType().getBinding());

    SimpleFeatureType schema = typeBuilder.buildFeatureType();

    FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = dataStore.getFeatureSource(typeName);

    // 连接PostGIS数据库
    Map<String,Object> pgParams = new HashMap<>();
    pgParams.put(PostgisNGDataStoreFactory.DBTYPE.key,"postgis");
    pgParams.put(PostgisNGDataStoreFactory.HOST.key,"localhost");
    pgParams.put(PostgisNGDataStoreFactory.PORT.key,"5432");
    pgParams.put(PostgisNGDataStoreFactory.DATABASE.key,"geodata");
    pgParams.put(PostgisNGDataStoreFactory.USER.key,"postgres");
    pgParams.put(PostgisNGDataStoreFactory.PASSWD.key,"123456");
    pgParams.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");         // 明确指定schema
    params.put(PostgisNGDataStoreFactory.EXPOSE_PK.key, true);  // 暴露主键

   try{
       DataStore pgDataStore = DataStoreFinder.getDataStore(pgParams);
       if(pgDataStore == null){
           System.err.println("数据库连接失败分析?:");
           PostgisNGDataStoreFactory factory = new PostgisNGDataStoreFactory();
           if (!factory.canProcess(params)) {
               System.err.println("参数不满足工厂要求");
           }
           if (!factory.isAvailable()) {
               System.err.println("工厂类未加载");
           }
           throw new RuntimeException("数据库连接失败,请检查上述原因");
       }
       System.out.println("数据库成功连接!");

       String[] typeNames = pgDataStore.getTypeNames();
       Boolean tableExists = false;
       // 检查数据表是否存在
       for(String name :typeNames){
           if(name.equals(tableName)){
               tableExists = true;
               break;
           }
       }
       if(tableExists){
           System.out.println("开始删除数据表!");
           pgDataStore.removeSchema(tableName);
           System.out.println("删除数据表完成!");
       }

       // 获取数据表名称
       // SimpleFeatureType schema = featureSource.getSchema();

       // 在数据库中创建表
       pgDataStore.createSchema(schema);

       // 属性字段
       for(AttributeDescriptor descriptor:schema.getAttributeDescriptors()){
           System.out.println(descriptor.getLocalName()+":"+descriptor.getType().getBinding().getSimpleName());
       }
       // 数据导入
       Transaction transaction = new DefaultTransaction("import");
       try(FeatureWriter<SimpleFeatureType,SimpleFeature> writer =
                   pgDataStore.getFeatureWriterAppend(schema.getTypeName(),transaction)){

           FeatureCollection<SimpleFeatureType,SimpleFeature> features  = featureSource.getFeatures();
           long idInit = 1; // 自增ID起始值
           try(FeatureIterator<SimpleFeature> iterator = features.features()){
               while (iterator.hasNext()){
                   SimpleFeature feature = iterator.next();
                   SimpleFeature targetFeature = writer.next();
                   // targetFeature.setAttributes(feature.getAttributes());
                   // 填入属性值
                   // 设置gid(自增或其他逻辑)
                   targetFeature.setAttribute("gid", idInit++);
                   targetFeature.setAttribute("layer",feature.getAttribute("LAYER"));
                   targetFeature.setAttribute("name",feature.getAttribute("NAME"));
                   targetFeature.setAttribute("kind",feature.getAttribute("kind"));
                   targetFeature.setAttribute("geom",feature.getDefaultGeometry());

                   writer.write();
               }
           }
           transaction.commit();
       }catch (Exception e){
           transaction.rollback();
           throw e;
       }
   }catch (Exception e){
       throw e;
   }

}

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !

相关文章:

  • 路径规划算法BFS/Astar/HybridAstar简单实现
  • 如何实现Aurora MySQL 零停机升级
  • linux线程同步
  • ES6 扩展运算符与 Rest 参数
  • yum命令常用选项
  • nginx 基于IP和用户的访问
  • leetcode hot100刷题日记——15.岛屿数量
  • Docker 安装 Harbor 教程(搭建 Docker 私有仓库 harbor 避坑指南)【woodwhales.cn】
  • java基础(面向对象进阶)
  • STM32中的IIC协议和OLED显示屏
  • ARM笔记-ARM指令集
  • 算法学习——从零实现循环神经网络
  • 7:QT加载保存参数(读写日志)
  • 5 分钟速通密码学!
  • List<Integer> list=new ArrayList<>()
  • Nginx stub_status 指南从启用到监控落地的全流程详解
  • 廉价却有效?ESD防护中的电容
  • 企业批量处理刚需PrintPDF 网络财务办公打印 网页到 Office 一键转 PDF
  • 【PhysUnits】10 减一操作(sub1.rs)
  • css五边形
  • 114物流网站怎么做/百度怎么发布广告
  • 黄冈市住房和城乡建设厅网站/武汉seo搜索引擎
  • 国家建设部网站2018年/seo前景
  • 家用宽带怎么做网站 访问/软文推广软文营销
  • 嘉兴做微网站多少钱/足球世界排名
  • 网站建设与实现 文献综述/图片搜索