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

需求

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

具体实现

实现数据查询

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

json 复制代码
"geometry":"POLYGON ((110.97538610392178 21.560137351924578,110.97979054002349 21.560079864736938,110.97929410551264 21.55479668272995,110.97338335499501 21.554995383717067,110.97538610392178 21.560137351924578))"

主要查询:

java 复制代码
List<Map<String, Object>> resultList = analysisMapper.queryContains(layer, wktPolygon);

sql语句

java 复制代码
<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库,在调用前,需要先注册一下:

java 复制代码
 ogr.RegisterAll();

主要的思路如下:

  • 由于从数据库中查询的结果是一个表,要生成shp,需要先创建一个shp,在定义属性名及类型,然后写入普通属性,写入空间属性
  • 创建shp
java 复制代码
   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);
  • 添加字段
java 复制代码
 // 添加字段,假设第一个元素包含所有字段
        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));
                }
            }
        }
  • 天才数据
java 复制代码
// 填充数据
        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();

压缩数据

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

java 复制代码
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,最后,再将数据打包

java 复制代码
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文件删除

java 复制代码
 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

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

java 复制代码
 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);
                }
相关推荐
张张张31212 分钟前
4.2学习总结 Java:list系列集合
java·学习
KATA~15 分钟前
解决MyBatis-Plus枚举映射错误:No enum constant问题
java·数据库·mybatis
xyliiiiiL30 分钟前
一文总结常见项目排查
java·服务器·数据库
shaoing32 分钟前
MySQL 错误 报错:Table ‘performance_schema.session_variables’ Doesn’t Exist
java·开发语言·数据库
腥臭腐朽的日子熠熠生辉1 小时前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian1 小时前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之1 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码2 小时前
Spring Task 定时任务
java·前端·spring
俏布斯2 小时前
算法日常记录
java·算法·leetcode
27669582922 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿