Java调用GDAL实现postgresql数据生成shp和dxf

2024-04-30 08:44

本文主要是介绍Java调用GDAL实现postgresql数据生成shp和dxf,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

需求

由于shp数据存储到postgresql数据库中,前端调用数据库实现数据的渲染,最近有一个新的需求,前端圈选数据,实现数据的下载,数据可以是shp、dxf、excel格式,这里主要记录在后端通过调用gdal来实现这个需求

具体实现

实现数据查询

前端传递一个polygon,需要在后端计算这个polygon裁剪的数据,这样才能得出圈选的数据,polygon格式如下:

"geometry":"POLYGON ((110.97538610392178 21.560137351924578,110.97979054002349 21.560079864736938,110.97929410551264 21.55479668272995,110.97338335499501 21.554995383717067,110.97538610392178 21.560137351924578))"

主要查询:

List<Map<String, Object>> resultList = analysisMapper.queryContains(layer, wktPolygon);

sql语句

<select id="queryContains" resultType="java.util.Map">SELECT  ST_AsGeoJSON(geom) as geometry,*FROM"${tableName}"WHERE st_contains(st_setsrid('${polygon}'::geometry,4326),st_setsrid(geom,4326))or ST_Intersects(st_setsrid('${polygon}'::geometry,4326), st_setsrid(geom,4326))order by gid</select>

生成shp数据

生成数据需要使用GDAL库,在调用前,需要先注册一下:

 ogr.RegisterAll();

主要的思路如下:

  • 由于从数据库中查询的结果是一个表,要生成shp,需要先创建一个shp,在定义属性名及类型,然后写入普通属性,写入空间属性
  • 创建shp
   gdal.SetConfigOption("SHAPE_ENCODING", "");// 假设所有要素都有相同的几何类型,仅查看第一个要素String geomTypeStr = (String) resultList.get(0).get("the_geom");String upperWkt = geomTypeStr.toUpperCase();int geomType = ogr.wkbUnknown; // 默认值if (upperWkt.startsWith("POINT")) {geomType = ogr.wkbPoint;} else if (upperWkt.startsWith("LINESTRING")) {geomType = ogr.wkbLineString;} else if (upperWkt.startsWith("POLYGON")) {geomType = ogr.wkbPolygon;} else if (upperWkt.startsWith("MULTIPOINT")) {geomType = ogr.wkbPoint;} else if (upperWkt.startsWith("MULTILINESTRING")) {geomType = ogr.wkbLineString;} else if (upperWkt.startsWith("MULTIPOLYGON")) {geomType = ogr.wkbPolygon;} else if (upperWkt.startsWith("GEOMETRYCOLLECTION")) {geomType = ogr.wkbGeometryCollection;}Driver shpDriver = ogr.GetDriverByName("ESRI Shapefile");DataSource shpDS = shpDriver.CreateDataSource(filePath);Layer glayer = shpDS.CreateLayer(layer, null, geomType);
  • 添加字段
 // 添加字段,假设第一个元素包含所有字段Set<String> keys = resultList.get(0).keySet();for (String key : keys) {if (!"geom".equals(key)) {  // 排除几何字段Object value = resultList.get(0).get(key);if (value instanceof Integer) {glayer.CreateField(new FieldDefn(key, 0));} else if (value instanceof Double) {glayer.CreateField(new FieldDefn(key, 2));} else if (value instanceof String) {glayer.CreateField(new FieldDefn(key, 4));}}}
  • 天才数据
// 填充数据for (Map<String, Object> featureData : resultList) {Feature feature = new Feature(glayer.GetLayerDefn());for(Map.Entry<String,Object>entry:featureData.entrySet()){String key = entry.getKey();Object value = entry.getValue();if("the_geom".equals(key)){int[] pnSRID = new int[1];try{String  geoJsonString = (String)value;org.gdal.ogr.Geometry geom = org.gdal.ogr.Geometry.CreateFromWkt(geoJsonString);feature.SetGeometry(geom);geom.delete();}catch (Exception e){e.printStackTrace();}}else if(!"geom".equals(key)) {// 设置属性数据int fieldIndex = feature.GetFieldIndex(key);if (value instanceof Integer) {feature.SetField(fieldIndex, (Integer) value);} else if (value instanceof Double) {feature.SetField(fieldIndex, (Double) value);} else if (value instanceof String) {feature.SetField(fieldIndex, (String) value);}}}glayer.CreateFeature(feature);feature.delete();}shpDS.delete();

压缩数据

由于被圈选的图层不止一个,因此多个数据传输比较麻烦,最好将生成的数据打包成压缩包,最终传输给前端

public void zipShapefile(String shapefilePath ,String zipFilePath){byte[] buffer = new byte[1024];try{FileOutputStream fos = new FileOutputStream(zipFilePath);ZipOutputStream zos = new ZipOutputStream(fos);File dir = new File(shapefilePath);File[] files = dir.listFiles();for(File file:files){FileInputStream fis = new FileInputStream(file);zos.putNextEntry(new ZipEntry(file.getName()));int length;while ((length = fis.read(buffer)) > 0) {zos.write(buffer, 0, length);}zos.closeEntry();fis.close();}zos.close();}catch(IOException ioe){ioe.printStackTrace();}}

生成dxf

由于shp数据在生成的时候存放在本地的文件夹内,而gdal从shp生成dxf比较简单,因此这里生成dxf会直接先生成shp文件,再从shp文件转成dxf,最后,再将数据打包

public void ShapefileToDXF(String shpFilePath){File folder = new File(shpFilePath);if(folder.isDirectory()){File[] files = folder.listFiles();if(files !=null){for(File file:files){if(file.getName().endsWith(".shp")){// 调用转换函数convertShpToDxf(file.getAbsolutePath(), file.getAbsolutePath().replace(".shp", ".dxf"));}}}deleteFilesInFolder(folder,"shp");}}public static void convertShpToDxf(String shpPath, String dxfPath) {// 获取Shapefile驱动Driver shpDriver = ogr.GetDriverByName("ESRI Shapefile");if (shpDriver == null) {System.err.println("Shapefile driver not available.");return;}// 打开Shapefile数据源DataSource shpDataSource = shpDriver.Open(shpPath, 0); // 0 means read-onlyif (shpDataSource == null) {System.err.println("Failed to open shapefile.");return;}if (shpDataSource.GetLayerCount() == 0) {System.err.println("No layers found in shapefile.");shpDataSource.delete();return;}// 获取DXF驱动Driver dxfDriver = ogr.GetDriverByName("DXF");if (dxfDriver == null) {System.err.println("DXF driver not available.");return;}// 创建DXF文件DataSource dxfDataSource = dxfDriver.CreateDataSource(dxfPath, null);if (dxfDataSource == null) {System.err.println("Failed to create DXF file.");return;}// 从Shapefile复制图层到DXFLayer shpLayer = shpDataSource.GetLayerByIndex(0);if (shpLayer == null) {System.err.println("Failed to get layer from shapefile.");return;}// 创建DXF图层,只包含几何数据Layer dxfLayer = dxfDataSource.CreateLayer("dxf_layer", shpLayer.GetSpatialRef(), shpLayer.GetGeomType());if (dxfLayer == null) {System.err.println("Failed to create DXF layer.");System.exit(1);}// 复制几何对象到新图层Feature shpFeature;while ((shpFeature = shpLayer.GetNextFeature()) != null) {// 创建一个新特征,可能需要根据DXF的要求调整几何类型或属性Feature newFeature = new Feature(dxfLayer.GetLayerDefn());newFeature.SetGeometry(shpFeature.GetGeometryRef());// 可能需要调整属性设置代码if (dxfLayer.CreateFeature(newFeature) != 0) {System.err.println("Failed to add feature to DXF.");}newFeature.delete(); // 清理新创建的特征对象}
//        // 复制图层到DXF文件中
//        Layer newLayer = dxfDataSource.CopyLayer(shpLayer, "new_layer_name", null);
//        if (newLayer == null) {
//            System.err.println("Failed to copy layer to DXF.");
//        }// 清理资源shpDataSource.delete(); // 关闭ShapefiledxfDataSource.delete(); // 关闭DXF文件}

删除冗余文件

由于每次请求都会在本地生成文件,因此会造成数据的冗余,因此,再每开启下一次请求时,需要找到存储的文件夹,进行清空,使之一直保持只保存一次请求的文件;再者,再生成dxf时,会先生成shp,相当于shp是中间文件,再传输给前端时会对dxf进行压缩,此时中间文件就可能被压缩进去,因此此时也需要把shp文件删除

 public static void deleteFilesInFolder(final File folder,String delType) {if (!folder.exists()) {return;}File[] files = folder.listFiles();if (files != null) {  // 为空的文件夹路径可能导致 null 返回for (File f : files) {if(delType.equals("all")){if (f.isFile()) {f.delete(); // 删除每个文件}}else if(delType.equals("shp")){if(f.getName().endsWith(".dbf")||f.getName().endsWith(".shp")||f.getName().endsWith(".shx")){if (f.isFile()) {f.delete(); // 删除每个文件}}}}}}

生成excel

这个步骤比较简单,代码如下:

 Workbook workbook = new HSSFWorkbook();Sheet sheet = workbook.createSheet("Sheet1");Row headerRow = sheet.createRow(0);//创建表头单元格,并设置单元格的值Set<String> keys = resultList.get(0).keySet();Map<String,Integer> excelKey = new HashMap<>();int colIndex = 0;for (String key : keys) {Cell headerCell1 = headerRow.createCell(colIndex);excelKey.put(key,colIndex);headerCell1.setCellValue(key);colIndex++;}//填充数据int rowIndex = 1;for (Map<String, Object> featureData : resultList){Row row = sheet.createRow(rowIndex++);for(Map.Entry<String,Object>entry:featureData.entrySet()){String key = entry.getKey();Object value = entry.getValue();colIndex = excelKey.get(key);Cell cell = row.createCell(colIndex);cell.setCellValue(value.toString());}}//保存excel文件try(FileOutputStream outputStream = new FileOutputStream(filePath+"\\"+layer+".xls")){workbook.write(outputStream);}

这篇关于Java调用GDAL实现postgresql数据生成shp和dxf的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/948408

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三