Przeglądaj źródła

生成shp文件初版

chenendian 4 tygodni temu
rodzic
commit
f7d98d19cd

+ 5 - 0
siwei-modules/siwei-apply/src/main/java/com/siwei/apply/controller/cadastre/ConvergeController.java

@@ -73,4 +73,9 @@ public class ConvergeController extends BaseController {
             return R.fail(e.getMessage());
         }
     }
+
+
+
+
+
 }

+ 15 - 4
siwei-modules/siwei-spatial/src/main/java/com/siwei/spatial/controller/file/SpatialFilesDbController.java

@@ -13,6 +13,7 @@ import com.siwei.spatial.utils.ShpPostgisTableBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -181,10 +182,6 @@ public class SpatialFilesDbController extends BaseController {
     }
 
 
-
-
-
-
     @GetMapping("/test/getShpData")
     public R<List<Map<String,Object>>> getShpData(@RequestParam("tabeName") String tabeName ) {
         List<Map<String,Object>> res = iSpatialFilesDbService.testGetShpData(tabeName);
@@ -193,5 +190,19 @@ public class SpatialFilesDbController extends BaseController {
     }
 
 
+    /**
+     * 根据表生成shp文件,并下载
+     * @param response
+     * @param ywh
+     */
+    @PostMapping("/getShpFile")
+    public void dealShpFileDownLoad(HttpServletResponse response, String  ywh) {
+        try {
+            iSpatialFilesDbService.dealShpFileDownLoad(response,ywh);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
 
 }

+ 5 - 0
siwei-modules/siwei-spatial/src/main/java/com/siwei/spatial/mapper/file/TGeomDbDetailsMapper.java

@@ -99,4 +99,9 @@ public interface TGeomDbDetailsMapper
 
     int insertTableData(@Param("tableName") String tableName, @Param("data") Map<String, Object> data, @Param("shpDbSRID") Integer shpDbSRID);
 
+    List<Map<String,Object>> selectTableDjzq(@Param("ysdm") String ysdm,@Param("validFlag") Integer validFlag);
+
+
+
+
 }

+ 5 - 0
siwei-modules/siwei-spatial/src/main/java/com/siwei/spatial/service/file/ISpatialFilesDbService.java

@@ -3,6 +3,7 @@ package com.siwei.spatial.service.file;
 import com.siwei.spatial.api.domain.file.TGeomDb;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
@@ -28,4 +29,8 @@ public interface ISpatialFilesDbService {
 
     String testInsertShpZD(List<Map<String,Object>> shpDataMapList);
 
+
+    void  dealShpFileDownLoad(HttpServletResponse response, String ysdm );
+
+
 }

+ 193 - 4
siwei-modules/siwei-spatial/src/main/java/com/siwei/spatial/service/file/impl/SpatialFilesDbServiceImpl.java

@@ -10,15 +10,26 @@ import com.siwei.spatial.service.file.ISpatialFilesDbService;
 import com.siwei.spatial.service.file.ITGeomDbDetailsService;
 import com.siwei.spatial.service.file.ITGeomDbService;
 import com.siwei.spatial.utils.FileUtils;
+import org.geotools.data.DefaultTransaction;
 import org.geotools.data.FeatureSource;
+import org.geotools.data.Transaction;
+import org.geotools.data.collection.ListFeatureCollection;
 import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
 import org.geotools.data.simple.SimpleFeatureCollection;
 import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.data.simple.SimpleFeatureStore;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
 import org.geotools.referencing.CRS;
 import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.MultiPolygon;
 import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKBReader;
 import org.locationtech.jts.io.WKTReader;
 import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
 import org.opengis.feature.type.AttributeDescriptor;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.slf4j.Logger;
@@ -28,9 +39,12 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
@@ -589,17 +603,192 @@ public class SpatialFilesDbServiceImpl implements ISpatialFilesDbService {
 
 
 
+    @Override
+    public List<Map<String,Object>> testGetShpData(String tabeName) {
+        List<Map<String,Object>>  geoms = tGeomDbDetailsMapper.selectTableDataAndGeom(tabeName);
+        return geoms;
+    }
+
+
+    /**
+     * 从表中读取带有geom的数据,并生成一个zip文件,文件包含当前表的shp文件
+     * @param response
+     * @param ysdm
+     */
+    @Override
+    public void dealShpFileDownLoad(HttpServletResponse response, String ysdm) {
+        try {
+            List<Map<String, Object>> djzqAndGeomList = tGeomDbDetailsMapper.selectTableDjzq(ysdm, 0);
+            if (djzqAndGeomList == null || djzqAndGeomList.isEmpty()) {
+                throw new RuntimeException("没有找到相关数据");
+            }
 
+            // 1. 创建临时目录
+            String tempDir = System.getProperty("java.io.tmpdir") + File.separator + IdUtils.fastSimpleUUID();
+            File dir = new File(tempDir);
+            if (!dir.exists()) dir.mkdirs();
 
+            // 2. 生成 SHP 文件
+            String shpName = "djzq";
+            File shpFile = new File(tempDir + File.separator + shpName + ".shp");
+            writeShapefile(shpFile, djzqAndGeomList);
 
+            // 生成 .cpg 文件 (解决中文乱码,明确指定编码)
+            File cpgFile = new File(tempDir + File.separator + shpName + ".cpg");
+            try (PrintWriter writer = new PrintWriter(cpgFile)) {
+                writer.print("UTF-8");
+            }
+
+            // 3. 压缩文件
+            File zipFile = new File(tempDir + File.separator + shpName + ".zip");
+            List<File> filesToZip = Arrays.asList(
+                    new File(tempDir + File.separator + shpName + ".shp"),
+                    new File(tempDir + File.separator + shpName + ".shx"),
+                    new File(tempDir + File.separator + shpName + ".dbf"),
+                    new File(tempDir + File.separator + shpName + ".prj"),
+                    new File(tempDir + File.separator + shpName + ".cpg")
+            );
+            FileUtils.zipFiles(filesToZip, zipFile);
+
+            // 4. 设置响应头并下载
+            response.setContentType("application/zip");
+            response.setCharacterEncoding("utf-8");
+            String fileName = shpName + ".zip";
+            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
+
+            try (FileInputStream fis = new FileInputStream(zipFile)) {
+                byte[] buffer = new byte[4096];
+                int len;
+                while ((len = fis.read(buffer)) > 0) {
+                    response.getOutputStream().write(buffer, 0, len);
+                }
+            }
+            response.getOutputStream().flush();
 
+            // 5. 清理临时文件 (异步清理或在方法结束时清理)
+            // 这里简单处理,生产环境建议使用定时任务或更健壮的清理机制
+            // FileUtils.deleteDirectory(dir); 
 
-    @Override
-    public List<Map<String,Object>> testGetShpData(String tabeName) {
-        List<Map<String,Object>>  geoms = tGeomDbDetailsMapper.selectTableDataAndGeom(tabeName);
-        return geoms;
+        } catch (Exception e) {
+            log.error("导出SHP文件失败", e);
+            throw new RuntimeException("导出SHP文件失败: " + e.getMessage());
+        }
     }
 
+    private void writeShapefile(File file, List<Map<String, Object>> dataList) throws Exception {
+        // 1. 定义要素类型 (SimpleFeatureType)
+        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
+        typeBuilder.setName("djzq");
+        
+        // 设置坐标系 CGCS2000 (EPSG:4490)
+        CoordinateReferenceSystem crs = CRS.decode("EPSG:4490");
+        typeBuilder.setCRS(crs);
+
+        // 添加字段 (根据表结构)
+        typeBuilder.add("the_geom", MultiPolygon.class);
+        typeBuilder.add("bsm", Integer.class);
+        typeBuilder.add("ysdm", String.class);
+        typeBuilder.add("djzqdm", String.class);
+        typeBuilder.add("djzqmc", String.class);
+        typeBuilder.add("bz", String.class);
+        typeBuilder.add("valid_flag", Integer.class);
+
+        SimpleFeatureType featureType = typeBuilder.buildFeatureType();
+
+        // 2. 创建要素集合
+        List<SimpleFeature> features = new ArrayList<>();
+        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
+        WKTReader wktReader = new WKTReader();
+        WKBReader wkbReader = new WKBReader();
+
+        for (Map<String, Object> data : dataList) {
+            Object geomObj = data.get("wkt_geom");
+            if (geomObj == null) {
+                geomObj = data.get("geom"); // 备选方案,兼容原有字段名
+            }
+            if (geomObj == null) continue;
+
+            Geometry geometry = null;
+            if (geomObj instanceof Geometry) {
+                geometry = (Geometry) geomObj;
+            } else {
+                String geomStr = geomObj.toString();
+                if (StringUtils.isEmpty(geomStr)) {
+                    continue;
+                }
+                
+                try {
+                    // 尝试判断是否为 Hex EWKB (以 010 或 000 开头)
+                    if (geomStr.startsWith("01") || geomStr.startsWith("00")) {
+                        // 如果是 EWKB,需要注意 JTS WKBReader 可能不直接支持 PostGIS 的 EWKB 标志位
+                        // 优先保证数据库层 ST_AsText 转换
+                        geometry = wkbReader.read(WKBReader.hexToBytes(geomStr));
+                    } else {
+                        // 尝试作为 WKT 解析
+                        String wkt = geomStr;
+                        if (wkt.contains(";")) {
+                            wkt = wkt.split(";")[1];
+                        }
+                        geometry = wktReader.read(wkt);
+                    }
+                } catch (ParseException e) {
+                    log.warn("无法解析几何数据: {}, 错误: {}", geomStr, e.getMessage());
+                    continue;
+                }
+            }
+            
+            if (geometry != null) {
+                // Shapefile 强制要求几何类型一致,这里统一转为 MultiPolygon
+                if (geometry instanceof org.locationtech.jts.geom.Polygon) {
+                    geometry = geometry.getFactory().createMultiPolygon(new org.locationtech.jts.geom.Polygon[]{(org.locationtech.jts.geom.Polygon) geometry});
+                }
+                
+                featureBuilder.add(geometry);
+                featureBuilder.add(data.get("bsm"));
+                featureBuilder.add(data.get("ysdm"));
+                featureBuilder.add(data.get("djzqdm"));
+                featureBuilder.add(data.get("djzqmc"));
+                featureBuilder.add(data.get("bz"));
+                featureBuilder.add(data.get("valid_flag"));
+
+                features.add(featureBuilder.buildFeature(null));
+            }
+        }
+
+        // 3. 写入文件
+        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
+        Map<String, Serializable> params = new HashMap<>();
+        params.put("url", file.toURI().toURL());
+        params.put("create spatial index", Boolean.TRUE);
+
+        ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
+        dataStore.setCharset(Charset.forName("UTF-8")); // 统一使用 UTF-8
+        dataStore.createSchema(featureType);
+
+        Transaction transaction = new DefaultTransaction("create");
+        String typeName = dataStore.getTypeNames()[0];
+        SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
+
+        if (featureSource instanceof SimpleFeatureStore) {
+            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
+            SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
+            featureStore.setTransaction(transaction);
+            try {
+                featureStore.addFeatures(collection);
+                transaction.commit();
+            } catch (Exception e) {
+                transaction.rollback();
+                throw e;
+            } finally {
+                transaction.close();
+            }
+        } else {
+            throw new IOException(typeName + " does not support read/write access");
+        }
+        dataStore.dispose();
+    }
+
+
 
 
 }

+ 26 - 4
siwei-modules/siwei-spatial/src/main/java/com/siwei/spatial/utils/FileUtils.java

@@ -1,14 +1,12 @@
 package com.siwei.spatial.utils;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.nio.charset.Charset;
 import java.util.*;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
 
 /**
  * 文件工具类
@@ -116,4 +114,28 @@ public class FileUtils {
             }
         }
     }
+
+    /**
+     * 将多个文件压缩成ZIP
+     *
+     * @param files       要压缩的文件列表
+     * @param zipFile     目标ZIP文件
+     * @throws IOException
+     */
+    public static void zipFiles(List<File> files, File zipFile) throws IOException {
+        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
+            byte[] buffer = new byte[4096];
+            for (File file : files) {
+                if (!file.exists()) continue;
+                try (FileInputStream fis = new FileInputStream(file)) {
+                    zos.putNextEntry(new ZipEntry(file.getName()));
+                    int len;
+                    while ((len = fis.read(buffer)) > 0) {
+                        zos.write(buffer, 0, len);
+                    }
+                    zos.closeEntry();
+                }
+            }
+        }
+    }
 }

+ 8 - 5
siwei-modules/siwei-spatial/src/main/resources/mapper/postgresql/spatial/file/TGeomDbDetailsMapper.xml

@@ -404,11 +404,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         WHERE 1=1
     </select>
 
-
-
-
-
-
+    <select id="selectTableDjzq"   resultType="Map">
+        SELECT  bsm, ysdm, djzqdm, djzqmc, bz, public.st_astext(geom) as wkt_geom, valid_flag   FROM vector.djzq
+        <where>
+            <if test="ysdm != null  and ysdm != ''"> and ysdm = #{ysdm}</if>
+            <if test="validFlag != null"> and valid_flag = #{validFlag}</if>
+        </where>
+        LIMIT  1000
+    </select>
 
 
 </mapper>