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
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82180.shtml
英文地址,請注明出處:http://en.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系列),這與任務需求匹配(模…