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);}

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

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

相关文章

使用STM32CubeMX对STM32F4进行串口配置

目录 1. 配置1.1 Pin脚1.2 RCC开启外部晶振1.3 时钟1.4 串口配置 2. 代码2.1 默认生成代码2.1 开启串口中断函数2.3 接收中断2.4 接收回调函数2.5 增加Printf 的使用 1. 配置 1.1 Pin脚 1.2 RCC开启外部晶振 1.3 时钟 外部使用8MHz晶振 开启内部16MHz晶振 使用锁相环 开启最高…

ROS2 学习笔记(二)常用小工具

1. rqt_console #启动 ros2 run rqt_console rqt_console日志级别&#xff1a;Fatal --> Error --> Warn --> Info --> Debug #修改允许发布的日志级别 ros2 run <package_name> <executable_name> --ros-args --log-level WARN2. launch文件 ROS2中…

Outlook大附件插件 有效解决附件大小限制问题

很多企业都是使用Outlook来进行邮件的收发&#xff0c;可是由于附件大小有限&#xff0c;导致很多大文件发不出去&#xff0c;就会产生Outlook大附件插件这种业务需求。 邮件系统在发送大文件时面临的限制问题主要如下&#xff1a; 1、附件大小限制&#xff1a;大多数邮件服务…

【MySQL】如何在MySQL中编写循环

是谁的心啊 孤单地留下 他还好吗 我多想爱他 那永恒的泪 凝固那一句话 也许可能蒸发 是谁的爱啊 比泪水坚强 轻声呼唤 就让我融化 每一滴雨水 演化成我翅膀 向着我爱的人 追吧 &#x1f3b5; 飞儿乐团《月牙湾》 MySQL中的循环通常在存储过程中使用&#…

基于Pytorch深度学习——Softmax回归

本文章来源于对李沐动手深度学习代码以及原理的理解&#xff0c;并且由于李沐老师的代码能力很强&#xff0c;以及视频中讲解代码的部分较少&#xff0c;所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉&#xff0c;所以我们会采用逐行解释小…

深度学习基础之《TensorFlow框架(16)—神经网络案例》

一、mnist手写数字识别 1、数据集介绍 mnist数据集是一个经典的数据集&#xff0c;其中包括70000个样本&#xff0c;包括60000个训练样本和10000个测试样本 2、下载地址&#xff1a;http://yann.lecun.com/exdb/mnist/ 3、文件说明 train-images-idx3-ubyte.gz: training s…

Hbase学习笔记

Hbase是什么 HBase是一个高可靠、高性能、面向列、可伸缩的分布式存储系统。它利用Hadoop HDFS作为其文件存储系统,并提供实时的读写的数据库系统。HBase的设计思想来源于Google的BigTable论文,是Apache的Hadoop项目的子项目。它适合于存储大表数据,并可以达到实时级别。HB…

【Redis 开发】Lua语言

Lua Lua语法 Lua语法 Lua是一种小巧的脚本语言&#xff0c;底层用C语言实现&#xff0c;为了嵌入式应用程序中 官网&#xff1a;https://www.lua.org/ 创建lua文件 touch hello.lua 运行lua文件 lua hello.lua 输出语句 print("Hello World!")数据类型 可以通过t…

一篇易懂的SPI通讯指南

SPI概念 SPI&#xff08;Serial Peripheral interface, 串行外设接口&#xff09;是微处理控制单元(MCU)和外围IC&#xff08;如传感器、ADC、DAC、驱动芯片和外部存储设备等&#xff09;之间进行通信的同步串行端口&#xff0c;其通信速率一般可以从几千bps到几百Mbps甚至更高…

QT httpServer多线程后台服务器的例子实现

1.需求 1.1 用户需要其他平台&#xff08;web端&#xff09;调用Qt平台的接口&#xff0c;获取想要的数据并实时显示在网页里&#xff0c;比如实时的温湿度&#xff0c;用户数据等 1.2 用户需要在其他平台&#xff08;web端&#xff09;调用Qt平台的接口&#xff0c;下发数据…

kettle从入门到精通 第五十五课 ETL之kettle Excel输入

想真正学习或者提升自己的ETL领域知识的朋友欢迎进群&#xff0c;一起学习&#xff0c;共同进步。 1、 Excel输入&#xff0c;Microsoft Excel输入步骤的作用是从Microsoft Excel中读取数据&#xff0c;如下图所示&#xff1a; 1&#xff09;Excel输入步骤从文件D:\data\测试数…

Linux实现简单进度条(附原理解释和动图效果)

1&#xff0c;行缓冲区 先看下面的代码和运行结果&#xff0c; #include<stdio.h> #include<unistd.h> int main() {printf("你好\n");sleep(3);return 0; }只是一个简单的打印“你好”然后休眠三秒&#xff0c;最后程序结束 再看下面的代码和运行结果…

Docker-Compose单机多容器应用编排与管理

前言 Docker Compose 作为 Docker 生态系统中的一个重要组件&#xff0c;为开发人员提供了一种简单而强大的方式来定义和运行多个容器化应用。本文将介绍 Docker Compose 的使用背景、优劣势以及利用 Docker Compose 简化应用程序的部署和管理。 目录 一、Docker Compose 简…

数据库学习之常见的一些SQL命令

查看当前DBMS下所有数据库 show databases; 切换到某一个数据库 use 数据库名; 开启root的远程登录 update mysql.user set host"%" where user"root"; 刷新权限列表 flush privileges; 创建数据库 create database 数据库名称 删除数据库 drop…

CUDA架构介绍与设计模式解析

文章目录 **CUDA**架构介绍与设计模式解析**1** CUDA 介绍CUDA发展历程CUDA主要特性CUDA系统架构CUDA应用场景编程语言支持CUDA计算过程线程层次存储层次 **2** CUDA 系统架构分层架构并行计算模式生产-消费者模式工作池模式异步编程模式 **3** CUDA 中的设计模式工厂模式策略模…

django设计模式理解FBV和CBV

在 Web 开发中&#xff0c;FBV&#xff08;Function-Based Views&#xff09;和 CBV&#xff08;Class-Based Views&#xff09;是两种常见的视图设计模式&#xff0c;用于处理 HTTP 请求并生成相应的响应。下面是它们的简要解释&#xff1a; Function-Based Views (FBV) 在 …

闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子

前言 一个在实际应用中 EF Core 集成 FluentValidation 进行数据校验的例子。 Step By Step 步骤 创建一个 Asp.Net Core WebApi 项目 引用以下 Nuget 包 FluentValidation.AspNetCore Microsoft.AspNetCore.Identity.EntityFrameworkCore Microsoft.EntityFrameworkCore.Re…

SQL事前巡检插件

背景: 事故频发 •在工作过程中每年都会看到SQL问题引发的线上问题&#xff0c;一条有问题的SQL足以拖垮整个数据库 不易发觉 •对于SQL性能问题测试在预发环境不易发现&#xff08;数据量小&#xff09; •SAAS系统隔离字段在SQL条件中遗漏&#xff0c;造成越权风险 •业…

密链:openEuler20.03已安装的软件包列表

文章目录 openEuler20.03已安装的软件包列表 openEuler20.03已安装的软件包列表 rpm -qa[rootlocalhost tmp]# rpm -qa librelp-1.2.16-3.oe2003sp4.aarch64 p11-kit-trust-0.23.20-5.oe2003sp4.aarch64 python-setuptools-44.1.1-2.oe2003sp4.noarch luksmeta-9-5.oe2003sp4.…

【算法刷题 | 贪心算法08】4.29(划分字母区间、合并区间)

文章目录 14.划分字母区间14.1题目14.2解法&#xff1a;贪心14.2.1贪心思路14.2.2代码实现 15.合并区间15.1题目15.2解法&#xff1a;贪心15.2.1贪心思路15.2.2代码实现 14.划分字母区间 14.1题目 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一…