前言
?GeoTools 在空間數據轉換處理方面具有強大的能力,能夠高效、簡潔的操縱 Shp 數據。特別是與空間數據庫PostGIS 相結合,更能展示出其空間數據處理的優勢,借助 GeoTools,我們可以實現 Shp 數據高效入庫。
本文上接系列文章
1. 環境搭建
在進行GeoTools
開發前,需要先完成一些準備工作。俗話說,工欲善其事,必先利其器,只有將前期工作做好了,才能更好的推進往后的開發工作。
以下是環境搭建的一些軟件工具,包括JDK
、Maven
以及IDE
-
JDK
:當前例子中使用的JDK
版本為11,需要先行下載,并設置好環境變量。 -
Maven
:當前例子中使用的Maven
版本是3.6.3
,需要先行下載,并配置好倉庫地址。 -
IDE
:當前例子中使用的IDE
是IDEA 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
構建。注意一下PORT
和PASSWD
參數為字符串類型,需要使用雙引號,否則會導致數據庫連接失敗。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之路】 已經接入了智能助手,歡迎關注,歡迎提問。
歡迎訪問我的博客網站-長談GIS:
http://shanhaitalk.com
都看到這了,不要忘記點贊、收藏 + 關注 哦 !
本號不定時更新有關?GIS開發 相關內容,歡迎關注?!