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-only
        if (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复制图层到DXF
        Layer 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(); // 关闭Shapefile
        dxfDataSource.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.mfbz.cn/a/583803.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c#数据库: 6.查询成绩合格的学生/7.输出全部学生信息

SQL Server Management Studio Management Studio 中的学生信息表: 查询上图成绩合格的学生信息&#xff0c;并将信息从控制台输出 using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Text…

【弱监督语义分割】AllSpark:从transformer中的未标记特征重生标记特征,用于半监督语义分割

AllSpark: Reborn Labeled Features from Unlabeled in Transformer for Semi-Supervised Semantic Segmentation 摘要&#xff1a; 目前最先进的方法是用真实标签训练标注数据&#xff0c;用伪标签训练未标注数据。然而&#xff0c;这两个训练流程是分开的&#xff0c;这就使…

《Fundamentals of Power Electronics》——正激变换器

正激变换器电路如图6.24所示&#xff1a; 该变压器隔离型转换器基于Buck电路&#xff0c;需要一个晶体管&#xff0c;因此常被使用在比全桥和半桥功率等级低的应用中。其非脉动输出电流与其他降压衍生变换器相同&#xff0c;使正激变换器非常适合涉及高输出电流的应用。晶体管最…

Slave SQL线程与PXB FTWRL死锁问题分析

1. 问题背景 2.27号凌晨生产环境MySQL备库在执行备份期间出现因FLUSH TABLES WITH READ LOCK未释放导致备库复制延时拉大&#xff0c;慢日志内看持锁接近25分钟未释放。 版本&#xff1a; MySQL 5.7.21PXB 2.4.18 慢查询日志&#xff1a; 备份脚本中的备份命令&#xff1a;…

QT 开发COM(ActiveX)组件基础介绍和方案验证

一、COM简介 1.1 COM是什么&#xff1f; COM&#xff0c;Component Object Model&#xff0c;即组件对象模型&#xff0c;是一种以组件为发布单元的对象模型&#xff0c;这种模型使各软件组件可以用一种统一的方式进行交互。COM 既提供了组件之间进行交互的规范&#xff0c;也…

LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测(Matlab)

LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09; 目录 LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.LSTM-KDE的长短期…

微服务入门学习笔记(黑马商城)

课程转跳&#xff1a;SpringCloud微服务Day1-01.微服务课程介绍_哔哩哔哩_bilibili 一、服务拆分 新建一个maven项目将商品服务拆分出去 更改包扫描 新建一个数据库用于商品服务&#xff0c;同样将表拆分出去 更改配置文件的服务名和数据库名 启动多个实例&#xff1a; 复制配…

解决Pycharm全局搜索与输入法简繁切换快捷键冲突问题

Pycharm中全局搜索快捷键Ctrl Shift F 如图所示&#xff1a; 微软输入法简繁切换快捷键设置&#xff1a; 解决办法&#xff1a; 关掉输入法的切换功能即可&#xff0c;或者更改简繁切换快捷键&#xff0c;毕竟简繁切换使用频率极低。

特别的时钟:上次那个时钟布局和计算有问题,重新修改一下,用JS创建180多个li标签,自动生成数字

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>特别的时钟</title> </head> <st…

Github Action Bot 开发教程

Github Action Bot 开发教程 在使用 Github 时&#xff0c;你可能在一些著名的开源项目&#xff0c;例如 Kubernetes&#xff0c;Istio 中看到如下的一些评论&#xff1a; /lgtm /retest /area bug /assign xxxx ...等等&#xff0c;诸如此类的一些功能性评论。在这些评论出现…

合泰杯(HT32F52352)RTC的应用(计时)--->掉电不丢失VBAT(代码已经实现附带源码)

摘要 在HT32F52352合泰单片机开发中&#xff0c;rtc在网上还是挺少人应用的&#xff0c;找了很久没什么资料&#xff0c;现在我根据手册和官方的代码进行配置理解。 RTC在嵌入式单片机中是一个很重要的应用资源。 记录事件时间戳&#xff1a;RTC可以记录事件发生的精确时间&…

踏上R语言之旅:解锁数据世界的神秘密码(四)

文章目录 前言一、多元线性回归1.多元线性回归模型的建立2.多元线性回归模型的检验 二、多元线性相关分析1.矩阵相关分析2.复相关分析 三、回归变量的选择方法1.变量选择准则2.变量选择的常用准则3.逐步回归分析 总结 前言 回归分析研究的主要对象是客观事物变量间的统计关系。…

Macs Fan Control Pro for mac激活版:macOS 平台的风扇控制软件

Macs Fan Control Pro是一款用于 macOS 平台的风扇控制软件&#xff0c;它允许用户监控和调整 Mac 电脑的风扇转速。以下是该软件的一些特点和功能&#xff1a; Macs Fan Control Pro for mac激活版下载 风扇监控&#xff1a;Macs Fan Control Pro 提供实时的风扇转速监控&…

vue+elementui(笔记)

vueelementui 表格 <div class"tableStyle"><el-table :data"pointsSettingsTableData" style"width: 70%" :stripe"true" size"mini"header-cell-class-name"headerClassName" :cell-style"{ tex…

Llama3 在线试用与本地部署

美国当地时间4月18日&#xff0c;Meta 开源了 Llama3 大模型&#xff0c;目前开源版本为 8B 和 70B 。Llama 3 模型相比 Llama 2 具有重大飞跃&#xff0c;并在 8B 和 70B 参数尺度上建立了 LLM 模型的新技术。由于预训练和后训练的改进&#xff0c;Llama3 模型是目前在 8B 和 …

应急响应-webserver

一.环境准备 1.镜像文件 2.任务说明 3.用户密码 二.应急响应 环境启动 1.导入镜像文件并修改网络 2.远程连接 ss -ntl #列出系统中运行的所有进程 用远程连接工具连接 任务一 Linux 服务日志默认存储在/var/log目录下 默认网站根目录&#xff1a;/var/www/html/ 1.查看…

【Doris系列】 SQL 多方言兼容

目前 Doris 引擎提供了两种方式实现对 sql 多方言的支持。即&#xff0c;提交指定方言的 sql&#xff0c;Doris 可以成功解析&#xff0c;并返回正确的计算结果。本文就简单来测试验证下这两种方式的效果。 一、Doris Sql Convertor Doris 官方提供了一个 sql convertor 工具…

ES全文检索支持拼音和繁简检索

ES全文检索支持拼音和繁简检索 1. 实现目标2. 引入pinyin插件2.1 编译 elasticsearch-analysis-pinyin 插件2.2 安装拼音插件 3. 引入ik分词器插件3.1 已有作者编译后的包文件3.2 只有源代码的版本3.3 安装ik分词插件 4. 建立es索引5.测试检索6. 繁简转换 1. 实现目标 ES检索时…

力扣33. 搜索旋转排序数组

Problem: 33. 搜索旋转排序数组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化左右指针&#xff1a;首先&#xff0c;定义两个指针left和right&#xff0c;分别指向数组的开始和结束位置。 2.计算中间值&#xff1a;在left和right之间找到中间位置mid。 3.比较中间值…

使用Python爬取淘宝商品并做数据分析

使用Python爬取淘宝商品并做数据分析&#xff0c;可以按照以下步骤进行操作&#xff1a; 确定需求&#xff1a;确定要爬取的淘宝商品的种类、数量、关键词等信息。 编写爬虫程序&#xff1a;使用Python编写爬虫程序&#xff0c;通过模拟浏览器请求&#xff0c;获取淘宝商品的页…
最新文章