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