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开发 相关内容,欢迎关注 !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/82180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Vue的家政服务系统源码适配H5小程序APP

市场前景 随着社会经济的发展和人口老龄化的加剧&#xff0c;家政服务需求不断增长。我国65岁及以上人口增长较快&#xff0c;2022年我国65岁及以上老年人数量达2.1亿人&#xff0c;占比较2016年增长4.1个百分点&#xff0c;达14.9%。我国65岁及以上人口数量庞大&#xff0c;老…

《企业级日志该怎么打?Java日志规范、分层设计与埋点实践》

大家好呀&#xff01;&#x1f44b; 今天我们要聊一个Java开发中超级重要但又经常被忽视的话题——日志系统&#xff01;&#x1f4dd; 不管你是刚入门的小白&#xff0c;还是工作多年的老司机&#xff0c;日志都是我们每天都要打交道的"好朋友"。那么&#xff0c;如…

1Panel vs 宝塔面板:现代化运维工具的全方位对比

1Panel vs 宝塔面板对比分析 1Panel 和 宝塔面板&#xff08;BT-Panel&#xff09;都是服务器管理工具&#xff0c;旨在简化 Linux 服务器的运维工作&#xff0c;但它们在设计理念、功能侧重点和技术实现上有明显差异。以下从多个维度对两者进行对比分析&#xff1a; 1. 定位与…

怎么开发一个网络协议模块(C语言框架)之(四) 信号量初始化

// 原始代码 /* gVrrpInstance.sem = OsixCreateBSem(OSIX_SEM_Q_PRIORITY, OSIX_SEM_FULL); */ gVrrpInstance.sem = OsixCreateMSem(OSIX_SEM_Q_FIFO | OSIX_SEM_DELETE_SAFE); if (gVrrpInstance.sem == NULL) {printf("[VRRP]:vrrp init error, failed to create vrrp…

电脑C盘清理技巧:释放空间,提升性能

文章目录 一、使用系统自带的磁盘清理工具&#xff08;一&#xff09;打开磁盘清理工具&#xff08;二&#xff09;清理临时文件&#xff08;三&#xff09;清理系统文件 二、使用第三方清理工具&#xff08;一&#xff09;CCleaner&#xff08;极力推荐&#xff09;&#xff0…

ARM笔记-ARM处理器及系统结构

第二章 ARM处理器及系统结构 2.1 ARM处理器简介 采用RISC架构的ARM微处理器的特点&#xff1a; 体积小、功耗低、低成本、高性能&#xff1b;支持 Thumb&#xff08;16位&#xff09;/ARM&#xff08;32位&#xff09;双指令集&#xff0c;能很好地兼容 8位/16位 器件&#x…

关于如何在Springboot项目中通过excel批量导入数据

接口文档 2.5 批量导入学生账号 2.5.1 基本信息 请求路径:/admin/students/batch-import 请求方式:POST 接口描述:通过上传Excel文件批量导入学生账号信息。 2.5.2 请求参数 参数格式:multipart/form-data 参数说明: 参数名称参数类型是否必须备注filefile是包含学…

【TypeScript】知识点梳理(四)

#没事去翻翻官网文档&#xff0c;其实有很多用法是我们还不知道的&#xff0c;官方资料总是最权威的&#xff0c;也推荐大家无聊看看各个官网hhh&#xff0c;不一定是记忆&#xff0c;但在某种场景下我们或许能想到还有多一种解决方式# noImplicitAny 当我们没有表明类型时&…

Python匿名函数(lambda)全面详解

文章目录 Python匿名函数(lambda)全面详解一、lambda函数基础1. 什么是lambda函数&#xff1f;2. lambda函数语法3. 与普通函数的区别 二、lambda函数使用场景1. 作为函数参数2. 在数据结构中使用3. 作为返回值4. 立即调用(IIFE) 三、lambda函数高级用法1. 多参数lambda2. 条件…

Qt Widgets模块功能详细说明,基本控件:QCheckBox(三)

一、基本控件&#xff08;Widgets&#xff09; Qt 提供了丰富的基本控件&#xff0c;如按钮、标签、文本框、复选框、单选按钮、列表框、组合框、菜单、工具栏等。 1、QCheckBox 1.1、概述 (用途、状态、继承关系) QCheckBox 是 Qt 框架中的复选框控件&#xff0c;用于表示二…

HarmonyOS 鸿蒙应用开发基础:转换整个PDF文档为图片功能

在许多应用场景中&#xff0c;将PDF文档的每一页转换为单独的图片文件是非常有帮助的。这可以用于文档的分享、扫描文档的电子化存档、或者进行进一步的文字识别处理等。本文将介绍如何使用华为HarmonyOS提供的PDF处理服务将整个PDF文档转换为图片&#xff0c;并将这些图片存放…

【算法】: 前缀和算法(利用o(1)的时间复杂度快速求区间和)

前缀和算法&#xff1a;高效处理区间求和的利器 目录 引言什么是前缀和前缀和的基本实现前缀和的作用前缀和的典型应用场景前缀和的优缺点分析实战例题解析 引言 区间求和问题的普遍性暴力解法的时间复杂度问题前缀和算法的核心思想 什么是前缀和 前缀和的数学定义 通俗来…

NDVI谐波拟合(基于GEE实现)

在遥感影像中&#xff0c;我们常用 NDVI&#xff08;归一化植被指数&#xff09;来衡量地表植被的绿度。它简单直观&#xff0c;是生态监测、农情分析的基础工具。但你是否注意到&#xff1a; NDVI 虽然“绿”&#xff0c;却常常“乱”。 因为云层、观测频率、天气干扰&#xf…

基于Python+YOLO模型的手势识别系统

本项目是一个基于Python、YOLO模型、PyQt5的实时手势识别系统&#xff0c;通过摄像头或导入图片、视频&#xff0c;能够实时识别并分类不同的手势动作。系统采用训练好的深度学习模型进行手势检测和识别&#xff0c;可应用于人机交互、智能控制等多种场景。 1、系统主要功能包…

黑马点评--短信登录实现

短信登录 导入黑马点评项目 导入资料中提供的SQL文件 其中的核心表有&#xff1a; tb_user &#xff1a;用户表 tb_user_info &#xff1a;用户详情表 tb_shop&#xff1a;用户信息表 tb_shop_type&#xff1a;商户类型表 tb_blog&#xff1a;用户日记表&#xff08;达人…

AWS EC2实例安全远程访问最佳实践

EC2 远程连接方案对比 远程访问 Amazon EC2 实例主要有以下四种方式&#xff1a; Secure Shell (SSH) 远程访问AWS Systems Manager 会话管理器适用于 Linux 实例的 EC2 Serial ConsoleAmazon EC2 Instance Connect SSH 远程访问 SSH&#xff08;Secure Shell&#xff09;广…

Idea如果有参数,怎么debug

如上图&#xff0c;输入输出路径是需要运行的时候给参数。 那么 FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); 给上面的代码给参数的步骤为 1.在类名或者方法名上右键&#xff0c;选择More Run/Debug…

Oracle Apps R12——报表入门2:单表——报表开发流程

☆开发思路 开发表报代码流程中有几个重要的组件和重要的知识点需要搞懂&#xff0c;才能得心应手。报表通常是通过表格的形式来存在的&#xff0c;我们一般在开发代码的时候在【输出】中打印HTML,Css格式的表格&#xff0c;并把查询到的数据插入其中&#xff0c;即可完成一个报…

Servlet的继承关系和生命周期

1.继承关系&#xff1a; javax.servlet.Servlet接口->javax.servlet.GenericServlet抽象类 ->javax.servlet.http.HttpServlet抽象子类 2.相关方法&#xff1a; javax.servlet.Servlet&#xff1a; &#xff08;1&#xff09;void init(config) -初始化方法 &…

PEFT库PromptTuningConfig 配置

PEFT库 PromptTuningConfig 配置 "Prompt Tuning"的参数高效微调 PromptTuningConfig 核心参数解析 1. task_type="CAUSAL_LM" 作用:指定任务类型为因果语言模型(Causal LM)。说明:因果语言模型从左到右生成文本(如GPT系列),这与任务需求匹配(模…