# geometry-shp 文件导出

1,导入依赖

<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-swing</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-geojson</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools.jdbc</groupId>
    <artifactId>gt-jdbc-postgis</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-opengis</artifactId>
    <version>${geotools.version}</version>
</dependency>

2,导入工具类

package com.supermap.jczcpt.pipe.manage.planninganalysis.util;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.*;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
 
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
 
public class ShapeUtil {
 
    /**
     * 生成 shape 文件
     *
     * @param shpPath 生成 shape 文件路径(包含文件名称)
     * @param encode  编码
     * @param geoType 图幅类型,Point 和 Rolygon
     * @param geoms   图幅集合
     */
    public static void write2Shape(String shpPath, String encode, String geoType, List<Geometry> geoms) {
        try {
            // 创建 shape 文件对象
            File file = new File(shpPath);
            Map<String, Serializable> params = new HashMap<>();
            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            // 定义图形信息和属性信息
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(DefaultGeographicCRS.WGS84);
            tb.setName("shapefile");
 
            if ("Polygon".equals(geoType)) {
                tb.add("the_geom", Polygon.class);
            } else if ("MultiPolygon".equals(geoType)) {
                tb.add("the_geom", MultiPolygon.class);
            } else if ("Point".equals(geoType)) {
                tb.add("the_geom", Point.class);
            } else if ("MultiPoint".equals(geoType)) {
                tb.add("the_geom", MultiPoint.class);
            } else if ("LineString".equals(geoType)) {
                tb.add("the_geom", LineString.class);
            } else if ("MultiLineString".equals(geoType)) {
                tb.add("the_geom", MultiLineString.class);
            } else {
                throw new Exception("Geometry中没有该类型:" + geoType);
            }
 
            ds.createSchema(tb.buildFeatureType());
            // 设置编码
            Charset charset = Charset.forName(encode);
            ds.setCharset(charset);
            // 设置 Writer
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
            for (Geometry geom : geoms) {
                //String type = geom.getGeometryType();
 
                // 写下一条
                SimpleFeature feature = writer.next();
 
                feature.setAttribute("the_geom", geom);
            }
            writer.write();
            writer.close();
            ds.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 生成 shape 文件
     *
     * @param shpPath  生成 shape 文件路径(包含文件名称)
     * @param encode   编码
     * @param geoType  图幅类型,Point 和 Rolygon
     * @param shpKey   data 中图幅的 key
     * @param attrKeys 属性 key 集合
     * @param data     图幅和属性集合
     */
    public static void write2Shape(String shpPath, String encode, String geoType, String shpKey, List<String> attrKeys, List<Map<String, Object>> data) {
        try {
            if (data == null || data.size() == 0) {
                return;
            }
            // 创建 shape 文件对象
            File file = new File(shpPath);
            Map<String, Serializable> params = new HashMap<>();
            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
 
            // 定义图形信息和属性信息
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(DefaultGeographicCRS.WGS84);
            tb.setName("shapefile");
 
            if ("Polygon".equals(geoType)) {
                tb.add("the_geom", Polygon.class);
            } else if ("MultiPolygon".equals(geoType)) {
                tb.add("the_geom", MultiPolygon.class);
            } else if ("Point".equals(geoType)) {
                tb.add("the_geom", Point.class);
            } else if ("MultiPoint".equals(geoType)) {
                tb.add("the_geom", MultiPoint.class);
            } else if ("LineString".equals(geoType)) {
                tb.add("the_geom", LineString.class);
            } else if ("MultiLineString".equals(geoType)) {
                tb.add("the_geom", MultiLineString.class);
            } else {
                throw new Exception("Geometry中没有该类型:" + geoType);
            }
 
            for (String field : attrKeys) {
                tb.add(field.toUpperCase(), String.class);
            }
 
            ds.createSchema(tb.buildFeatureType());
            // 设置编码
            Charset charset = Charset.forName(encode);
            ds.setCharset(charset);
            // 设置 Writer
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
            // 写入文件信息
            for (int i = 0; i < data.size(); i++) {
                SimpleFeature feature = writer.next();
                Map<String, Object> row = data.get(i);
                Geometry geom = (Geometry) row.get(shpKey);
                feature.setAttribute("the_geom", geom);
                for (String key : row.keySet()) {
                    if (!key.equals(shpKey)) {
                        if (row.get(key) != null) {
                            feature.setAttribute(key.toUpperCase(), row.get(key).toString());
                        } else {
                            feature.setAttribute(key.toUpperCase(), "");
                        }
                    }
                }
            }
            writer.write();
            writer.close();
            ds.dispose();
 
            // 添加到压缩文件
            //zipShapeFile(shpPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
 
    /**
     * 压缩 shape 文件
     *
     * @param shpPath shape 文件路径(包含 shape 文件名称)
     */
    public static void zipShapeFile(String shpPath) {
        try {
            File shpFile = new File(shpPath);
            String shpRoot = shpFile.getParentFile().getPath();
            String shpName = shpFile.getName().substring(0, shpFile.getName().lastIndexOf("."));
 
            String zipPath = shpRoot + File.separator + shpName + ".zip";
            File zipFile = new File(zipPath);
            InputStream input = null;
            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
            //zip 的名称为
            zipOut.setComment(shpName);
            String[] shpFiles = new String[]{
                    shpRoot + File.separator + shpName + ".dbf",
                    shpRoot + File.separator + shpName + ".prj",
                    shpRoot + File.separator + shpName + ".shp",
                    shpRoot + File.separator + shpName + ".shx",
                    shpRoot + File.separator + shpName + ".fix"
            };
 
            for (int i = 0; i < shpFiles.length; i++) {
                File file = new File(shpFiles[i]);
                input = new FileInputStream(file);
                zipOut.putNextEntry(new ZipEntry(file.getName()));
                int temp = 0;
                while ((temp = input.read()) != -1) {
                    zipOut.write(temp);
                }
                input.close();
            }
            zipOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.supermap.jczcpt.pipe.manage.planninganalysis.util;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
/**
 * @ClassName WKTUtil
 * @Description @TODO
 * @Date 2019/11/18 12:01
 * @Version v1.0
 **/
public class WKTUtil {
 
    public static String geomToWkt(Geometry geometry) {
        String wkt = null;
        WKTWriter writer = new WKTWriter();
        wkt = writer.write(geometry);
        return wkt;
    }
 
    public static Geometry wktToGeom(String wkt)  {
        Geometry geometry = null;
        WKTReader reader = new WKTReader();
        try {
            geometry = reader.read(wkt);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        //geometry.setSRID(4326);
        return geometry;
    }
}

导出 web 下载

/**
     * 将管段数据导出为 shp 文件
     * @param
     * @return
     * @author dkx
     * @date 2024/8/8 23:36
     */
    @PostMapping("/exportShp")
    @Operation(summary = "将管段数据导出为shp文件")
    @Parameter(name = "ids", description = "id集合")
    public void exportShp(@RequestParam("ids") List<String> ids, HttpServletResponse response) throws IOException {
        String val = formatListToString(ids, ",", "\'", "\'");
        List<FacGasPipeSection> sectionGeo = facGasPipeSectionMapper.getSectionGeo(val);
        if (CollectionUtil.isNotEmpty(sectionGeo)) {
            List<String> list = element(sectionGeo);
            List<Geometry> geometryList = new ArrayList<>();
            for (String str : list) {
                Geometry geom = WKTUtil.wktToGeom(str);
                geometryList.add(geom);
            }
            // 临时生成 Shape 文件并压缩为 zip
            String tempDir = System.getProperty("java.io.tmpdir");
            String shapeFilePath = tempDir + File.separator + "ceshi2222.shp";
            String zipFilePath = tempDir + File.separator + "ceshi2222.zip";
            // 写入 Shape 文件并压缩为 ZIP
            ShapeUtil.write2Shape(shapeFilePath, "utf-8", "Polygon", geometryList);
            ShapeUtil.zipShapeFile(shapeFilePath);
            // 确保文件正确生成
            File zipFile = new File(zipFilePath);
            if (zipFile.exists()) {
                // 设置响应头,提示浏览器下载文件
                response.setContentType("application/zip");
                response.setHeader("Content-Disposition", "attachment; filename=ceshi2222.zip");
                response.setContentLength((int) zipFile.length());
                // 将文件写入响应流
                try (ServletOutputStream outputStream = response.getOutputStream();
                     FileInputStream fis = new FileInputStream(zipFile)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                    outputStream.flush();
                } finally {
                    // 删除临时文件
                    Files.deleteIfExists(Paths.get(shapeFilePath));
                    Files.deleteIfExists(Paths.get(zipFilePath));
                }
            } else {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("Error generating the ZIP file.");
            }
        } else {
            // 处理无数据的情况
            response.setStatus(HttpServletResponse.SC_NO_CONTENT);
        }
    }
    private static List<String> element(List<FacGasPipeSection> sectionGeo) {
        ArrayList<String> list = new ArrayList<>();
        for (FacGasPipeSection dwdProFacGasPipeSection : sectionGeo) {
            if(ObjectUtil.isNotEmpty(dwdProFacGasPipeSection)) {
                if(!StringUtil.isNullOrEmpty(dwdProFacGasPipeSection.getGeometry())) {
                    // 解析 JSON 字符串
                    JSONObject jsonObject = new JSONObject(dwdProFacGasPipeSection.getGeometry());
                    // 获取 geometry 对象
                    JSONObject geometry = jsonObject.getJSONObject("geometry");
                    // 获取 coordinates 数组
                    JSONArray coordinates = geometry.getJSONArray("coordinates");
                    // 将 coordinates 数组转换为字符串
                    String result = coordinates.toString();
                    list.add(result);
                }
            }
        }
        return list;
    }
    /**
     * 将列表转换为以指定分隔符分隔的字符串,并在每个元素之前和之后添加指定的前缀和后缀。
     * @param list 要转换的列表
     * @param delimiter 分隔符
     * @param prefix 每个元素的前缀
     * @param suffix 每个元素的后缀
     * @return 格式化后的字符串
     */
    public static <T> String formatListToString(List<T> list, String delimiter, String prefix, String suffix) {
        return list.stream()
                .map(item -> prefix + item.toString() + suffix)
                .collect(Collectors.joining(delimiter));
    }