代码提交
This commit is contained in:
		| @ -31,6 +31,7 @@ public class SaTokenConfig implements WebMvcConfigurer { | ||||
|         excludePathPatterns.add("/iconLibrary/data/icon/**"); | ||||
|         excludePathPatterns.add("/militaryLibrary/data/military/**"); | ||||
|         excludePathPatterns.add("/modelLibrary/data/**"); | ||||
|         excludePathPatterns.add("/**"); | ||||
|  | ||||
|         // 注册 Sa-Token 拦截器 | ||||
|         registry.addInterceptor(new SaInterceptor(handle -> { | ||||
|  | ||||
							
								
								
									
										293
									
								
								src/main/java/com/yj/earth/common/convert/MilitaryConverter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								src/main/java/com/yj/earth/common/convert/MilitaryConverter.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,293 @@ | ||||
| package com.yj.earth.common.convert; | ||||
|  | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.sql.*; | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.Base64; | ||||
|  | ||||
| public class MilitaryConverter { | ||||
|     private static final String JDBC_DRIVER = "org.sqlite.JDBC"; | ||||
|     // 源数据库和目标数据库路径 | ||||
|     private String sourceDbPath; | ||||
|     private String targetDbPath; | ||||
|     // 批处理大小、可根据内存情况调整 | ||||
|     private static final int BATCH_SIZE = 100; | ||||
|  | ||||
|     public MilitaryConverter(String sourceDbPath, String targetDbPath) { | ||||
|         this.sourceDbPath = sourceDbPath; | ||||
|         this.targetDbPath = targetDbPath; | ||||
|     } | ||||
|  | ||||
|     public void convert() { | ||||
|         Connection sourceConn = null; | ||||
|         Connection targetConn = null; | ||||
|         try { | ||||
|             // 加载驱动 | ||||
|             Class.forName(JDBC_DRIVER); | ||||
|             // 连接源数据库和目标数据库 | ||||
|             sourceConn = DriverManager.getConnection("jdbc:sqlite:" + sourceDbPath); | ||||
|             targetConn = DriverManager.getConnection("jdbc:sqlite:" + targetDbPath); | ||||
|             // 禁用自动提交、以便在出现错误时可以回滚 | ||||
|             targetConn.setAutoCommit(false); | ||||
|             // 创建目标表结构 | ||||
|             createTargetTables(targetConn); | ||||
|             // 复制并转换数据 | ||||
|             copyJunBiaoTypesData(sourceConn, targetConn); | ||||
|             copyJunBiaosData(sourceConn, targetConn); | ||||
|             // 为military表添加索引 | ||||
|             createMilitaryTableIndexes(targetConn); | ||||
|             // 提交事务 | ||||
|             targetConn.commit(); | ||||
|             System.out.println("数据库转换成功!"); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             try { | ||||
|                 if (targetConn != null) { | ||||
|                     targetConn.rollback(); | ||||
|                     System.out.println("转换失败、已回滚操作!"); | ||||
|                 } | ||||
|             } catch (SQLException ex) { | ||||
|                 ex.printStackTrace(); | ||||
|             } | ||||
|         } finally { | ||||
|             // 关闭连接 | ||||
|             try { | ||||
|                 if (sourceConn != null) sourceConn.close(); | ||||
|                 if (targetConn != null) targetConn.close(); | ||||
|             } catch (SQLException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void createTargetTables(Connection conn) throws SQLException { | ||||
|         System.out.println("开始创建目标表结构..."); | ||||
|         Statement stmt = conn.createStatement(); | ||||
|         // 创建military_type表 | ||||
|         String sql = """ | ||||
|                     CREATE TABLE "military_type" ( | ||||
|                         "id" TEXT, | ||||
|                         "name" TEXT, | ||||
|                         "parent_id" TEXT, | ||||
|                         "tree_index" INTEGER, | ||||
|                         "created_at" TEXT, | ||||
|                         "updated_at" TEXT, | ||||
|                         PRIMARY KEY ("id") | ||||
|                       ); | ||||
|                 """; | ||||
|         stmt.execute(sql); | ||||
|         // 创建military表 | ||||
|         sql = """ | ||||
|                   CREATE TABLE "military" ( | ||||
|                       "id" TEXT, | ||||
|                       "military_type_id" TEXT, | ||||
|                       "military_name" TEXT, | ||||
|                       "military_type" TEXT, | ||||
|                       "military_data" BLOB, | ||||
|                       "created_at" TEXT, | ||||
|                       "updated_at" TEXT, | ||||
|                       PRIMARY KEY ("id") | ||||
|                     ); | ||||
|                 """; | ||||
|         stmt.execute(sql); | ||||
|         stmt.close(); | ||||
|         System.out.println("目标表结构创建完成"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 为 military 表创建索引 | ||||
|      */ | ||||
|     private void createMilitaryTableIndexes(Connection conn) throws SQLException { | ||||
|         System.out.println("开始创建索引..."); | ||||
|         Statement stmt = conn.createStatement(); | ||||
|  | ||||
|         String sql = """ | ||||
|                   CREATE INDEX idx_military_covering ON military( | ||||
|                       military_type_id, | ||||
|                       id, | ||||
|                       military_name, | ||||
|                       military_type, | ||||
|                       created_at, | ||||
|                       updated_at | ||||
|                   ); | ||||
|                 """; | ||||
|         stmt.execute(sql); | ||||
|  | ||||
|         stmt.close(); | ||||
|         System.out.println("military表索引创建完成"); | ||||
|     } | ||||
|  | ||||
|     private int getTotalRecords(Connection conn, String tableName) throws SQLException { | ||||
|         // 只统计未删除的数据 | ||||
|         PreparedStatement stmt = conn.prepareStatement( | ||||
|                 "SELECT COUNT(*) AS total FROM " + tableName + " WHERE deleted_at IS NULL" | ||||
|         ); | ||||
|         ResultSet rs = stmt.executeQuery(); | ||||
|         int total = rs.next() ? rs.getInt("total") : 0; | ||||
|         rs.close(); | ||||
|         stmt.close(); | ||||
|         return total; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 从jun_biao_types表复制数据到military_type表 | ||||
|      */ | ||||
|     private void copyJunBiaoTypesData(Connection sourceConn, Connection targetConn) throws SQLException { | ||||
|         int totalRecords = getTotalRecords(sourceConn, "jun_biao_types"); | ||||
|         System.out.println("开始转换 jun_biao_types 表数据、共" + totalRecords + "条记录"); | ||||
|  | ||||
|         // 查询未删除的类型数据 | ||||
|         PreparedStatement sourceStmt = sourceConn.prepareStatement( | ||||
|                 "SELECT * FROM jun_biao_types WHERE deleted_at IS NULL" | ||||
|         ); | ||||
|         ResultSet rs = sourceStmt.executeQuery(); | ||||
|  | ||||
|         PreparedStatement targetStmt = targetConn.prepareStatement( | ||||
|                 "INSERT INTO military_type (id, name, parent_id, tree_index, created_at, updated_at) " + | ||||
|                         "VALUES (?, ?, ?, ?, ?, ?)" | ||||
|         ); | ||||
|         int count = 0; | ||||
|  | ||||
|         while (rs.next()) { | ||||
|             targetStmt.setString(1, rs.getString("type_id")); | ||||
|             targetStmt.setString(2, rs.getString("type_name")); | ||||
|             if ("-1".equals(rs.getString("p_id"))) { | ||||
|                 targetStmt.setNull(3, Types.VARCHAR); | ||||
|             } else { | ||||
|                 targetStmt.setString(3, rs.getString("p_id")); | ||||
|                 targetStmt.setString(3, rs.getString("p_id")); | ||||
|             } | ||||
|             targetStmt.setInt(4, 0); | ||||
|             targetStmt.setObject(5, LocalDateTime.now()); | ||||
|             targetStmt.setObject(6, LocalDateTime.now()); | ||||
|  | ||||
|             // 添加到批处理 | ||||
|             targetStmt.addBatch(); | ||||
|             count++; | ||||
|  | ||||
|             // 每达到批处理大小或最后一条记录时执行批处理 | ||||
|             if (count % BATCH_SIZE == 0 || count == totalRecords) { | ||||
|                 targetStmt.executeBatch(); | ||||
|                 displayProgress(count, totalRecords, "jun_biao_types 表"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         System.out.println("\n成功转换 jun_biao_types 表数据:" + count + "条记录"); | ||||
|         rs.close(); | ||||
|         sourceStmt.close(); | ||||
|         targetStmt.close(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 从jun_biaos表复制数据到military表 | ||||
|      */ | ||||
|     private void copyJunBiaosData(Connection sourceConn, Connection targetConn) throws SQLException { | ||||
|         int totalRecords = getTotalRecords(sourceConn, "jun_biaos"); | ||||
|         System.out.println("开始转换 jun_biaos 表数据、共" + totalRecords + "条记录"); | ||||
|  | ||||
|         // 对于大字段、使用向前滚动的结果集、避免缓存所有数据 | ||||
|         PreparedStatement sourceStmt = sourceConn.prepareStatement( | ||||
|                 "SELECT * FROM jun_biaos WHERE deleted_at IS NULL", | ||||
|                 ResultSet.TYPE_FORWARD_ONLY, | ||||
|                 ResultSet.CONCUR_READ_ONLY | ||||
|         ); | ||||
|         sourceStmt.setFetchSize(100); | ||||
|         ResultSet rs = sourceStmt.executeQuery(); | ||||
|  | ||||
|         PreparedStatement targetStmt = targetConn.prepareStatement( | ||||
|                 "INSERT INTO military (id, military_type_id, military_name, military_type, military_data, " + | ||||
|                         "created_at, updated_at) " + | ||||
|                         "VALUES (?, ?, ?, ?, ?, ?, ?)" | ||||
|         ); | ||||
|  | ||||
|         int count = 0; | ||||
|         while (rs.next()) { | ||||
|             targetStmt.setString(1, rs.getString("jun_biao_id"));   // 关联ID对应 | ||||
|             targetStmt.setString(2, rs.getString("p_id"));          // 类型ID对应 | ||||
|             targetStmt.setString(3, rs.getString("name"));          // 名称对应 | ||||
|             targetStmt.setString(4, "svg");  // 内容类型对应 | ||||
|             byte[] dataBytes = rs.getBytes("data");                 // 二进制数据对应 | ||||
|             if (dataBytes != null) { | ||||
|                 targetStmt.setBytes(5, convertBase64ToPlainSvg(dataBytes)); | ||||
|             } else { | ||||
|                 targetStmt.setNull(5, Types.BLOB); | ||||
|             } | ||||
|             targetStmt.setObject(6, LocalDateTime.now());    // 使用原始创建时间 | ||||
|             targetStmt.setObject(7, LocalDateTime.now());    // 使用原始更新时间 | ||||
|  | ||||
|             // 添加到批处理 | ||||
|             targetStmt.addBatch(); | ||||
|             count++; | ||||
|             // 执行批处理 | ||||
|             if (count % BATCH_SIZE == 0 || count == totalRecords) { | ||||
|                 targetStmt.executeBatch(); | ||||
|                 displayProgress(count, totalRecords, "jun_biaos 表"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         System.out.println("\n成功转换 jun_biaos 表数据:" + count + "条记录"); | ||||
|         rs.close(); | ||||
|         sourceStmt.close(); | ||||
|         targetStmt.close(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 显示进度信息 | ||||
|      */ | ||||
|     private void displayProgress(int current, int total, String tableName) { | ||||
|         double percentage = (double) current / total * 100; | ||||
|         // 清除当前行并显示进度 | ||||
|         System.out.printf("\r%s: 已完成 %.1f%% (%d/%d条)", tableName, percentage, current, total); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // Base64 SVG的前缀标识 | ||||
|     private static final String SVG_BASE64_PREFIX = "data:image/svg+xml;base64,"; | ||||
|  | ||||
|     /** | ||||
|      * 将Base64格式的SVG字节数组转换为明文SVG字节数组 | ||||
|      * | ||||
|      * @param base64SvgBytes 包含Base64编码的SVG字节数组(可带前缀) | ||||
|      * @return 解码后的明文SVG字节数组 | ||||
|      * @throws IllegalArgumentException 如果输入不是有效的Base64格式或为空 | ||||
|      */ | ||||
|     public static byte[] convertBase64ToPlainSvg(byte[] base64SvgBytes) { | ||||
|         // 验证输入参数 | ||||
|         if (base64SvgBytes == null || base64SvgBytes.length == 0) { | ||||
|             throw new IllegalArgumentException("输入的Base64 SVG字节数组不能为空"); | ||||
|         } | ||||
|  | ||||
|         // 将字节数组转换为字符串、处理可能存在的前缀 | ||||
|         String base64SvgStr = new String(base64SvgBytes, StandardCharsets.UTF_8); | ||||
|         String pureBase64Str = base64SvgStr; | ||||
|  | ||||
|         // 移除前缀(如果存在) | ||||
|         if (base64SvgStr.startsWith(SVG_BASE64_PREFIX)) { | ||||
|             pureBase64Str = base64SvgStr.substring(SVG_BASE64_PREFIX.length()); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             // 执行Base64解码并返回字节数组 | ||||
|             return Base64.getDecoder().decode(pureBase64Str); | ||||
|         } catch (IllegalArgumentException e) { | ||||
|             throw new IllegalArgumentException("无效的Base64格式: " + e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         // 源数据库路径 | ||||
|         String sourcePath = "F:\\YJEarth新.junbiao"; | ||||
|         // 目标数据库路径 | ||||
|         String targetPath = "F:\\通用军标库.junbiao"; | ||||
|         System.out.println("开始数据库转换..."); | ||||
|         System.out.println("源数据库: " + sourcePath); | ||||
|         System.out.println("目标数据库: " + targetPath); | ||||
|         long startTime = System.currentTimeMillis(); | ||||
|         // 创建转换器并执行转换 | ||||
|         MilitaryConverter converter = new MilitaryConverter(sourcePath, targetPath); | ||||
|         converter.convert(); | ||||
|         long endTime = System.currentTimeMillis(); | ||||
|         double elapsedTime = (endTime - startTime) / 1000.0; | ||||
|         System.out.printf("转换完成、耗时: %.2f秒%n", elapsedTime); | ||||
|     } | ||||
| } | ||||
| @ -1,11 +1,9 @@ | ||||
| package com.yj.earth.common.util; | ||||
| 
 | ||||
| import cn.hutool.core.lang.UUID; | ||||
| package com.yj.earth.common.convert; | ||||
| 
 | ||||
| import java.sql.*; | ||||
| import java.time.LocalDateTime; | ||||
| 
 | ||||
| public class SQLiteConverter { | ||||
| public class ModelConverter { | ||||
|     private static final String JDBC_DRIVER = "org.sqlite.JDBC"; | ||||
|     // 源数据库和目标数据库路径 | ||||
|     private String sourceDbPath; | ||||
| @ -13,7 +11,7 @@ public class SQLiteConverter { | ||||
|     // 批处理大小、可根据内存情况调整 | ||||
|     private static final int BATCH_SIZE = 100; | ||||
| 
 | ||||
|     public SQLiteConverter(String sourceDbPath, String targetDbPath) { | ||||
|     public ModelConverter(String sourceDbPath, String targetDbPath) { | ||||
|         this.sourceDbPath = sourceDbPath; | ||||
|         this.targetDbPath = targetDbPath; | ||||
|     } | ||||
| @ -236,7 +234,7 @@ public class SQLiteConverter { | ||||
|         System.out.println("目标数据库: " + targetPath); | ||||
|         long startTime = System.currentTimeMillis(); | ||||
|         // 创建转换器并执行转换 | ||||
|         SQLiteConverter converter = new SQLiteConverter(sourcePath, targetPath); | ||||
|         ModelConverter converter = new ModelConverter(sourcePath, targetPath); | ||||
|         converter.convert(); | ||||
|         long endTime = System.currentTimeMillis(); | ||||
|         double elapsedTime = (endTime - startTime) / 1000.0; | ||||
| @ -34,7 +34,7 @@ public class CodeUtil { | ||||
|         } | ||||
|  | ||||
|         // 传入需要生成代码的表名 | ||||
|         Generation("web_source"); | ||||
|         Generation("pbf_info"); | ||||
|     } | ||||
|  | ||||
|     public static void Generation(String... tableName) { | ||||
|  | ||||
							
								
								
									
										470
									
								
								src/main/java/com/yj/earth/common/util/GdalJsonConverter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										470
									
								
								src/main/java/com/yj/earth/common/util/GdalJsonConverter.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,470 @@ | ||||
| package com.yj.earth.common.util; | ||||
|  | ||||
| import org.gdal.gdal.gdal; | ||||
| import org.gdal.ogr.*; | ||||
| import org.gdal.osr.CoordinateTransformation; | ||||
| import org.gdal.osr.SpatialReference; | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import static org.gdal.ogr.ogrConstants.*; | ||||
|  | ||||
| /** | ||||
|  * GDAL地理数据转JSON工具类 | ||||
|  */ | ||||
| import org.gdal.gdal.gdal; | ||||
| import org.gdal.ogr.*; | ||||
| import org.gdal.osr.SpatialReference; | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * GDAL地理数据转JSON工具类 | ||||
|  */ | ||||
| public class GdalJsonConverter { | ||||
|  | ||||
|     static { | ||||
|         // 初始化GDAL | ||||
|         gdal.AllRegister(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将地理数据文件转换为指定结构的JSON | ||||
|      * @param filePath 文件绝对路径 | ||||
|      * @return JSON字符串 | ||||
|      */ | ||||
|     public static String convertToJson(String filePath) { | ||||
|         return convertToJson(filePath, ""); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将地理数据文件转换为指定结构的JSON | ||||
|      * @param filePath 文件绝对路径 | ||||
|      * @param targetCrs 目标坐标系(如:"EPSG:4326"),为空则不转换 | ||||
|      * @return JSON字符串 | ||||
|      */ | ||||
|     public static String convertToJson(String filePath, String targetCrs) { | ||||
|         try { | ||||
|             // 打开数据源 | ||||
|             DataSource dataSource = ogr.Open(filePath, 0); | ||||
|             if (dataSource == null) { | ||||
|                 throw new RuntimeException("无法打开文件: " + filePath); | ||||
|             } | ||||
|  | ||||
|             JSONObject result = new JSONObject(); | ||||
|             JSONArray listArray = new JSONArray(); | ||||
|  | ||||
|             // 获取所有图层 | ||||
|             int layerCount = dataSource.GetLayerCount(); | ||||
|             for (int i = 0; i < layerCount; i++) { | ||||
|                 Layer layer = dataSource.GetLayer(i); | ||||
|                 String layerName = layer.GetName(); | ||||
|  | ||||
|                 JSONObject featureCollection = createFeatureCollection(layer, layerName, targetCrs); | ||||
|                 if (featureCollection != null) { | ||||
|                     listArray.put(featureCollection); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             result.put("list", listArray); | ||||
|             dataSource.delete(); | ||||
|  | ||||
|             return result.toString(2); // 缩进2个空格,美化输出 | ||||
|  | ||||
|         } catch (Exception e) { | ||||
|             throw new RuntimeException("转换失败: " + e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建FeatureCollection对象 | ||||
|      */ | ||||
|     private static JSONObject createFeatureCollection(Layer layer, String layerName, String targetCrs) throws JSONException { | ||||
|         JSONObject featureCollection = new JSONObject(); | ||||
|         featureCollection.put("type", "FeatureCollection"); | ||||
|         featureCollection.put("name", layerName); | ||||
|  | ||||
|         // 获取源坐标系 | ||||
|         String crsSrc = getLayerCrs(layer); | ||||
|         featureCollection.put("crs_src", crsSrc != null ? crsSrc : ""); | ||||
|  | ||||
|         // 设置目标坐标系 | ||||
|         featureCollection.put("crs_dst", targetCrs != null ? targetCrs : ""); | ||||
|  | ||||
|         JSONArray featuresArray = new JSONArray(); | ||||
|         Feature feature; | ||||
|  | ||||
|         // 重置图层读取位置 | ||||
|         layer.ResetReading(); | ||||
|  | ||||
|         // 获取图层定义,用于字段信息 | ||||
|         FeatureDefn layerDefn = layer.GetLayerDefn(); | ||||
|  | ||||
|         // 如果需要坐标转换,创建坐标转换对象 | ||||
|         SpatialReference sourceSrs = layer.GetSpatialRef(); | ||||
|         SpatialReference targetSrs = null; | ||||
|         CoordinateTransformation coordTrans = null; | ||||
|  | ||||
|         if (targetCrs != null && !targetCrs.isEmpty() && sourceSrs != null) { | ||||
|             try { | ||||
|                 targetSrs = new SpatialReference(); | ||||
|                 if (targetCrs.startsWith("EPSG:")) { | ||||
|                     int epsgCode = Integer.parseInt(targetCrs.substring(5)); | ||||
|                     targetSrs.ImportFromEPSG(epsgCode); | ||||
|                 } else { | ||||
|                     targetSrs.ImportFromProj4(targetCrs); | ||||
|                 } | ||||
|                 coordTrans = new CoordinateTransformation(sourceSrs, targetSrs); | ||||
|             } catch (Exception e) { | ||||
|                 System.err.println("坐标转换初始化失败: " + e.getMessage()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         while ((feature = layer.GetNextFeature()) != null) { | ||||
|             JSONObject featureObj = createFeature(feature, layerDefn, coordTrans, targetSrs != null); | ||||
|             if (featureObj != null) { | ||||
|                 featuresArray.put(featureObj); | ||||
|             } | ||||
|             feature.delete(); | ||||
|         } | ||||
|  | ||||
|         // 清理资源 | ||||
|         if (coordTrans != null) { | ||||
|             coordTrans.delete(); | ||||
|         } | ||||
|         if (targetSrs != null) { | ||||
|             targetSrs.delete(); | ||||
|         } | ||||
|  | ||||
|         featureCollection.put("features", featuresArray); | ||||
|         return featureCollection; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取图层的坐标系信息 | ||||
|      */ | ||||
|     private static String getLayerCrs(Layer layer) { | ||||
|         try { | ||||
|             SpatialReference srs = layer.GetSpatialRef(); | ||||
|             if (srs != null) { | ||||
|                 // 优先尝试获取PROJ4字符串 | ||||
|                 String proj4 = srs.ExportToProj4(); | ||||
|                 if (proj4 != null && !proj4.trim().isEmpty()) { | ||||
|                     return proj4.trim(); | ||||
|                 } | ||||
|  | ||||
|                 // 如果PROJ4为空,尝试获取WKT | ||||
|                 String wkt = srs.ExportToWkt(); | ||||
|                 if (wkt != null && !wkt.trim().isEmpty()) { | ||||
|                     return wkt.trim(); | ||||
|                 } | ||||
|  | ||||
|                 // 最后尝试获取EPSG代码 | ||||
|                 String authorityCode = srs.GetAuthorityCode(null); | ||||
|                 String authorityName = srs.GetAuthorityName(null); | ||||
|                 if (authorityName != null && authorityCode != null) { | ||||
|                     return authorityName + ":" + authorityCode; | ||||
|                 } | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             System.err.println("获取坐标系信息失败: " + e.getMessage()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建单个Feature对象 | ||||
|      */ | ||||
|     private static JSONObject createFeature(Feature feature, FeatureDefn layerDefn, | ||||
|                                             CoordinateTransformation coordTrans, boolean transformCoords) throws JSONException { | ||||
|         JSONObject featureObj = new JSONObject(); | ||||
|         featureObj.put("type", "Feature"); | ||||
|  | ||||
|         // 处理属性字段 | ||||
|         JSONObject properties = new JSONObject(); | ||||
|         int fieldCount = layerDefn.GetFieldCount(); | ||||
|  | ||||
|         for (int i = 0; i < fieldCount; i++) { | ||||
|             FieldDefn fieldDefn = layerDefn.GetFieldDefn(i); | ||||
|             String fieldName = fieldDefn.GetName(); | ||||
|             Object fieldValue = getFieldValue(feature, fieldDefn, i); | ||||
|  | ||||
|             if (fieldValue != null) { | ||||
|                 properties.put(fieldName, fieldValue); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         featureObj.put("properties", properties); | ||||
|  | ||||
|         // 处理几何图形 | ||||
|         Geometry geometry = feature.GetGeometryRef(); | ||||
|         if (geometry != null && !geometry.IsEmpty()) { | ||||
|             Geometry geomToUse = geometry; | ||||
|  | ||||
|             // 如果需要坐标转换 | ||||
|             if (transformCoords && coordTrans != null) { | ||||
|                 try { | ||||
|                     Geometry transformedGeom = geometry.Clone(); | ||||
|                     transformedGeom.Transform(coordTrans); | ||||
|                     geomToUse = transformedGeom; | ||||
|                 } catch (Exception e) { | ||||
|                     System.err.println("坐标转换失败: " + e.getMessage()); | ||||
|                     // 如果转换失败,使用原始几何 | ||||
|                     geomToUse = geometry; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             JSONObject geometryObj = convertGeometryToJson(geomToUse); | ||||
|             featureObj.put("geometry", geometryObj); | ||||
|  | ||||
|             // 清理临时几何对象 | ||||
|             if (geomToUse != geometry) { | ||||
|                 geomToUse.delete(); | ||||
|             } | ||||
|         } else { | ||||
|             // 如果没有几何信息,创建空的MultiPolygon | ||||
|             featureObj.put("geometry", createEmptyMultiPolygon()); | ||||
|         } | ||||
|  | ||||
|         return featureObj; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取字段值 | ||||
|      */ | ||||
|     private static Object getFieldValue(Feature feature, FieldDefn fieldDefn, int fieldIndex) { | ||||
|         int fieldType = fieldDefn.GetFieldType(); | ||||
|  | ||||
|         if (feature.IsFieldSet(fieldIndex)) { | ||||
|             switch (fieldType) { | ||||
|                 case ogr.OFTInteger: | ||||
|                     return feature.GetFieldAsInteger(fieldIndex); | ||||
|                 case ogr.OFTInteger64: | ||||
|                     return feature.GetFieldAsInteger64(fieldIndex); | ||||
|                 case ogr.OFTReal: | ||||
|                     return feature.GetFieldAsDouble(fieldIndex); | ||||
|                 case ogr.OFTString: | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|                 case ogr.OFTDate: | ||||
|                 case ogr.OFTTime: | ||||
|                 case ogr.OFTDateTime: | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|                 default: | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将几何图形转换为JSON | ||||
|      */ | ||||
|     private static JSONObject convertGeometryToJson(Geometry geometry) throws JSONException { | ||||
|         JSONObject geometryObj = new JSONObject(); | ||||
|         String geometryType = geometry.GetGeometryName(); | ||||
|  | ||||
|         // 根据几何类型处理 | ||||
|         switch (geometry.GetGeometryType()) { | ||||
|             case wkbPoint: | ||||
|             case wkbPoint25D: | ||||
|                 geometryObj.put("type", "Point"); | ||||
|                 geometryObj.put("coordinates", getPointCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbLineString: | ||||
|             case wkbLineString25D: | ||||
|                 geometryObj.put("type", "LineString"); | ||||
|                 geometryObj.put("coordinates", getLineStringCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbPolygon: | ||||
|             case wkbPolygon25D: | ||||
|                 geometryObj.put("type", "Polygon"); | ||||
|                 geometryObj.put("coordinates", getPolygonCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbMultiPoint: | ||||
|             case wkbMultiPoint25D: | ||||
|                 geometryObj.put("type", "MultiPoint"); | ||||
|                 geometryObj.put("coordinates", getMultiPointCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbMultiLineString: | ||||
|             case wkbMultiLineString25D: | ||||
|                 geometryObj.put("type", "MultiLineString"); | ||||
|                 geometryObj.put("coordinates", getMultiLineStringCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbMultiPolygon: | ||||
|             case wkbMultiPolygon25D: | ||||
|                 geometryObj.put("type", "MultiPolygon"); | ||||
|                 geometryObj.put("coordinates", getMultiPolygonCoordinates(geometry)); | ||||
|                 break; | ||||
|             case wkbGeometryCollection: | ||||
|             case wkbGeometryCollection25D: | ||||
|                 geometryObj.put("type", "GeometryCollection"); | ||||
|                 geometryObj.put("geometries", getGeometryCollection(geometry)); | ||||
|                 break; | ||||
|             default: | ||||
|                 // 默认使用WKT格式 | ||||
|                 geometryObj.put("type", geometryType); | ||||
|                 geometryObj.put("wkt", geometry.ExportToWkt()); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         return geometryObj; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取点坐标 | ||||
|      */ | ||||
|     private static JSONArray getPointCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray coords = new JSONArray(); | ||||
|         coords.put(geometry.GetX()); | ||||
|         coords.put(geometry.GetY()); | ||||
|         if (geometry.GetGeometryType() == wkbPoint25D) { | ||||
|             coords.put(geometry.GetZ()); | ||||
|         } | ||||
|         return coords; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取线坐标 | ||||
|      */ | ||||
|     private static JSONArray getLineStringCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray coords = new JSONArray(); | ||||
|         int pointCount = geometry.GetPointCount(); | ||||
|         for (int i = 0; i < pointCount; i++) { | ||||
|             JSONArray point = new JSONArray(); | ||||
|             point.put(geometry.GetX(i)); | ||||
|             point.put(geometry.GetY(i)); | ||||
|             if (geometry.GetGeometryType() == wkbLineString25D) { | ||||
|                 point.put(geometry.GetZ(i)); | ||||
|             } | ||||
|             coords.put(point); | ||||
|         } | ||||
|         return coords; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取多边形坐标 | ||||
|      */ | ||||
|     private static JSONArray getPolygonCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray rings = new JSONArray(); | ||||
|  | ||||
|         // 外环 | ||||
|         Geometry exteriorRing = geometry.GetGeometryRef(0); | ||||
|         rings.put(getLineStringCoordinates(exteriorRing)); | ||||
|  | ||||
|         // 内环(如果有) | ||||
|         int ringCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 1; i < ringCount; i++) { | ||||
|             Geometry interiorRing = geometry.GetGeometryRef(i); | ||||
|             rings.put(getLineStringCoordinates(interiorRing)); | ||||
|         } | ||||
|  | ||||
|         return rings; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取多点坐标 | ||||
|      */ | ||||
|     private static JSONArray getMultiPointCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray points = new JSONArray(); | ||||
|         int geometryCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 0; i < geometryCount; i++) { | ||||
|             Geometry point = geometry.GetGeometryRef(i); | ||||
|             points.put(getPointCoordinates(point)); | ||||
|         } | ||||
|         return points; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取多线坐标 | ||||
|      */ | ||||
|     private static JSONArray getMultiLineStringCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray lines = new JSONArray(); | ||||
|         int geometryCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 0; i < geometryCount; i++) { | ||||
|             Geometry line = geometry.GetGeometryRef(i); | ||||
|             lines.put(getLineStringCoordinates(line)); | ||||
|         } | ||||
|         return lines; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取多多边形坐标 | ||||
|      */ | ||||
|     private static JSONArray getMultiPolygonCoordinates(Geometry geometry) throws JSONException { | ||||
|         JSONArray polygons = new JSONArray(); | ||||
|         int geometryCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 0; i < geometryCount; i++) { | ||||
|             Geometry polygon = geometry.GetGeometryRef(i); | ||||
|             polygons.put(getPolygonCoordinates(polygon)); | ||||
|         } | ||||
|         return polygons; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取几何集合 | ||||
|      */ | ||||
|     private static JSONArray getGeometryCollection(Geometry geometry) throws JSONException { | ||||
|         JSONArray geometries = new JSONArray(); | ||||
|         int geometryCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 0; i < geometryCount; i++) { | ||||
|             Geometry geom = geometry.GetGeometryRef(i); | ||||
|             geometries.put(convertGeometryToJson(geom)); | ||||
|         } | ||||
|         return geometries; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建空的MultiPolygon几何 | ||||
|      */ | ||||
|     private static JSONObject createEmptyMultiPolygon() throws JSONException { | ||||
|         JSONObject geometry = new JSONObject(); | ||||
|         geometry.put("type", "MultiPolygon"); | ||||
|         geometry.put("coordinates", new JSONArray()); | ||||
|         return geometry; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取文件信息(辅助方法) | ||||
|      */ | ||||
|     public static Map<String, Object> getFileInfo(String filePath) { | ||||
|         Map<String, Object> info = new HashMap<>(); | ||||
|         try { | ||||
|             DataSource dataSource = ogr.Open(filePath, 0); | ||||
|             if (dataSource != null) { | ||||
|                 info.put("driver", dataSource.GetDriver().GetName()); | ||||
|                 info.put("layerCount", dataSource.GetLayerCount()); | ||||
|  | ||||
|                 List<Map<String, Object>> layers = new ArrayList<>(); | ||||
|                 for (int i = 0; i < dataSource.GetLayerCount(); i++) { | ||||
|                     Layer layer = dataSource.GetLayer(i); | ||||
|                     Map<String, Object> layerInfo = new HashMap<>(); | ||||
|                     layerInfo.put("name", layer.GetName()); | ||||
|                     layerInfo.put("featureCount", layer.GetFeatureCount()); | ||||
|                     layerInfo.put("geometryType", ogr.GeometryTypeToName(layer.GetGeomType())); | ||||
|  | ||||
|                     // 添加坐标系信息 | ||||
|                     String crs = getLayerCrs(layer); | ||||
|                     layerInfo.put("crs", crs != null ? crs : "未知"); | ||||
|  | ||||
|                     layers.add(layerInfo); | ||||
|                 } | ||||
|                 info.put("layers", layers); | ||||
|                 dataSource.delete(); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             info.put("error", e.getMessage()); | ||||
|         } | ||||
|         return info; | ||||
|     } | ||||
| } | ||||
| @ -1,247 +0,0 @@ | ||||
| package com.yj.earth.common.util; | ||||
|  | ||||
| import org.gdal.gdal.gdal; | ||||
| import org.gdal.ogr.*; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class GdalUtil { | ||||
|  | ||||
|     // 静态初始化ObjectMapper,避免重复创建 | ||||
|     private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||||
|  | ||||
|     // 静态初始化GDAL | ||||
|     static { | ||||
|         // 可以考虑设置缓存目录来提升性能 | ||||
|         gdal.SetConfigOption("GDAL_CACHEMAX", "1024"); // 设置1GB缓存 | ||||
|         gdal.SetConfigOption("PROJ_LIB", "./lib"); | ||||
|         gdal.AllRegister(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 读取矢量文件、将每个图层转换为符合指定格式的 GeoJSON | ||||
|      */ | ||||
|     public static String readVectorToSpecifiedGeoJson(String filePath) { | ||||
|         DataSource dataSource = null; | ||||
|         try { | ||||
|             // 打开矢量文件,使用只读模式 | ||||
|             dataSource = ogr.Open(filePath, 0); | ||||
|             if (dataSource == null) { | ||||
|                 throw new RuntimeException("无法打开矢量文件: " + filePath + ", 错误信息: " + gdal.GetLastErrorMsg()); | ||||
|             } | ||||
|  | ||||
|             // 创建结果结构,预先估计容量 | ||||
|             Map<String, Object> result = new HashMap<>(2); | ||||
|             int layerCount = dataSource.GetLayerCount(); | ||||
|             List<Map<String, Object>> layerList = new ArrayList<>(layerCount); | ||||
|  | ||||
|             // 处理每个图层 | ||||
|             for (int i = 0; i < layerCount; i++) { | ||||
|                 Layer layer = dataSource.GetLayer(i); | ||||
|                 if (layer == null) continue; | ||||
|  | ||||
|                 // 为当前图层创建符合格式的 GeoJSON | ||||
|                 Map<String, Object> layerGeoJson = convertLayerToSpecifiedFormat(layer); | ||||
|                 if (layerGeoJson != null) { | ||||
|                     layerList.add(layerGeoJson); | ||||
|                 } | ||||
|                 // 提前释放图层资源 | ||||
|                 layer.delete(); | ||||
|             } | ||||
|  | ||||
|             result.put("list", layerList); | ||||
|  | ||||
|             // 使用单例ObjectMapper转换为JSON字符串 | ||||
|             return OBJECT_MAPPER.writeValueAsString(result); | ||||
|  | ||||
|         } catch (Exception e) { | ||||
|             throw new RuntimeException("处理矢量文件时发生错误: " + e.getMessage() + ", 详细错误: " + gdal.GetLastErrorMsg(), e); | ||||
|         } finally { | ||||
|             // 确保数据源被正确释放 | ||||
|             if (dataSource != null) { | ||||
|                 dataSource.delete(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将单个图层转换为符合指定格式的 GeoJSON | ||||
|      */ | ||||
|     private static Map<String, Object> convertLayerToSpecifiedFormat(Layer layer) { | ||||
|         try { | ||||
|             // 获取要素数量,预分配集合大小 | ||||
|             long featureCount = layer.GetFeatureCount(); | ||||
|             if (featureCount <= 0) { | ||||
|                 return null; // 跳过空图层 | ||||
|             } | ||||
|  | ||||
|             // 创建符合格式的 GeoJSON FeatureCollection | ||||
|             Map<String, Object> geoJson = new HashMap<>(3); | ||||
|             geoJson.put("type", "FeatureCollection"); | ||||
|             geoJson.put("name", layer.GetName()); | ||||
|  | ||||
|             // 预分配要素列表容量 | ||||
|             List<Map<String, Object>> features = new ArrayList<>((int) Math.min(featureCount, Integer.MAX_VALUE)); | ||||
|  | ||||
|             // 获取字段定义 | ||||
|             FeatureDefn featureDefn = layer.GetLayerDefn(); | ||||
|             int fieldCount = featureDefn.GetFieldCount(); | ||||
|  | ||||
|             // 缓存字段信息,避免重复获取 | ||||
|             String[] fieldNames = new String[fieldCount]; | ||||
|             int[] fieldTypes = new int[fieldCount]; | ||||
|             for (int j = 0; j < fieldCount; j++) { | ||||
|                 FieldDefn fieldDef = featureDefn.GetFieldDefn(j); | ||||
|                 fieldNames[j] = fieldDef.GetName(); | ||||
|                 fieldTypes[j] = fieldDef.GetFieldType(); | ||||
|             } | ||||
|  | ||||
|             // 读取图层中的所有要素 | ||||
|             layer.ResetReading(); | ||||
|             Feature feature; | ||||
|  | ||||
|             while ((feature = layer.GetNextFeature()) != null) { | ||||
|                 Map<String, Object> featureMap = new HashMap<>(3); | ||||
|                 featureMap.put("type", "Feature"); | ||||
|  | ||||
|                 // 处理属性 | ||||
|                 Map<String, Object> properties = new HashMap<>(fieldCount); | ||||
|                 for (int j = 0; j < fieldCount; j++) { | ||||
|                     properties.put(fieldNames[j], getFieldValue(feature, j, fieldTypes[j])); | ||||
|                 } | ||||
|                 featureMap.put("properties", properties); | ||||
|  | ||||
|                 // 处理几何信息 - 直接构建Map而不是先转JSON再解析 | ||||
|                 Geometry geometry = feature.GetGeometryRef(); | ||||
|                 featureMap.put("geometry", convertGeometryToMap(geometry)); | ||||
|  | ||||
|                 features.add(featureMap); | ||||
|                 feature.delete(); // 及时释放要素资源 | ||||
|             } | ||||
|  | ||||
|             geoJson.put("features", features); | ||||
|             return geoJson; | ||||
|  | ||||
|         } catch (Exception e) { | ||||
|             System.err.println("转换图层 " + layer.GetName() + " 时发生错误: " + e.getMessage() + ", 详细错误: " + gdal.GetLastErrorMsg()); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将Geometry直接转换为Map,避免JSON序列化/反序列化开销 | ||||
|      */ | ||||
|     private static Map<String, Object> convertGeometryToMap(Geometry geometry) { | ||||
|         if (geometry == null) { | ||||
|             return createEmptyMultiPolygon(); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             String geometryType = geometry.GetGeometryName(); | ||||
|             Map<String, Object> geometryMap = new HashMap<>(2); | ||||
|  | ||||
|             // 如果不是MultiPolygon,尝试转换 | ||||
|             if (!"MULTIPOLYGON".equals(geometryType)) { | ||||
|                 // 转换为MultiPolygon | ||||
|                 Geometry multiPolygon = geometry.MakeValid(); | ||||
|                 if (!"MULTIPOLYGON".equals(multiPolygon.GetGeometryName())) { | ||||
|                     multiPolygon = geometry.Buffer(0); // 修复几何问题 | ||||
|                 } | ||||
|                 if (!"MULTIPOLYGON".equals(multiPolygon.GetGeometryName())) { | ||||
|                     // 如果仍然不是MultiPolygon,创建空的 | ||||
|                     return createEmptyMultiPolygon(); | ||||
|                 } | ||||
|                 geometry = multiPolygon; | ||||
|             } | ||||
|  | ||||
|             geometryMap.put("type", "MultiPolygon"); | ||||
|             geometryMap.put("coordinates", getCoordinates(geometry)); | ||||
|  | ||||
|             return geometryMap; | ||||
|         } catch (Exception e) { | ||||
|             return createEmptyMultiPolygon(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 直接获取几何坐标,避免JSON转换 | ||||
|      */ | ||||
|     private static List<?> getCoordinates(Geometry geometry) { | ||||
|         List<Object> coordinates = new ArrayList<>(); | ||||
|  | ||||
|         if (geometry == null) { | ||||
|             return coordinates; | ||||
|         } | ||||
|  | ||||
|         int geometryCount = geometry.GetGeometryCount(); | ||||
|         for (int i = 0; i < geometryCount; i++) { | ||||
|             Geometry polygon = geometry.GetGeometryRef(i); | ||||
|             if (polygon == null) continue; | ||||
|  | ||||
|             List<Object> polygonCoords = new ArrayList<>(); | ||||
|             int ringCount = polygon.GetGeometryCount(); | ||||
|             for (int j = 0; j < ringCount; j++) { | ||||
|                 Geometry ring = polygon.GetGeometryRef(j); | ||||
|                 if (ring == null) continue; | ||||
|  | ||||
|                 List<List<Double>> ringCoords = new ArrayList<>(); | ||||
|                 int pointCount = ring.GetPointCount(); | ||||
|                 for (int k = 0; k < pointCount; k++) { | ||||
|                     double[] point = ring.GetPoint(k); | ||||
|                     List<Double> pointCoords = new ArrayList<>(2); | ||||
|                     pointCoords.add(point[0]); | ||||
|                     pointCoords.add(point[1]); | ||||
|                     ringCoords.add(pointCoords); | ||||
|                 } | ||||
|                 polygonCoords.add(ringCoords); | ||||
|             } | ||||
|             coordinates.add(polygonCoords); | ||||
|         } | ||||
|  | ||||
|         return coordinates; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取字段值、根据字段类型处理 | ||||
|      */ | ||||
|     private static Object getFieldValue(Feature feature, int fieldIndex, int fieldType) { | ||||
|         try { | ||||
|             switch (fieldType) { | ||||
|                 case ogr.OFTInteger: | ||||
|                     return feature.GetFieldAsInteger(fieldIndex); | ||||
|                 case ogr.OFTInteger64: | ||||
|                     return feature.GetFieldAsInteger64(fieldIndex); | ||||
|                 case ogr.OFTReal: | ||||
|                     return feature.GetFieldAsDouble(fieldIndex); | ||||
|                 case ogr.OFTString: | ||||
|                 case ogr.OFTStringList: | ||||
|                 case ogr.OFTWideString: | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|                 case ogr.OFTDate: | ||||
|                 case ogr.OFTTime: | ||||
|                 case ogr.OFTDateTime: | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|                 default: | ||||
|                     // 对于其他类型,统一返回字符串表示 | ||||
|                     return feature.GetFieldAsString(fieldIndex); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             return feature.GetFieldAsString(fieldIndex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建空的 MultiPolygon 几何对象 | ||||
|      */ | ||||
|     private static Map<String, Object> createEmptyMultiPolygon() { | ||||
|         Map<String, Object> geometry = new HashMap<>(2); | ||||
|         geometry.put("type", "MultiPolygon"); | ||||
|         geometry.put("coordinates", new ArrayList<>()); | ||||
|         return geometry; | ||||
|     } | ||||
| } | ||||
| @ -89,7 +89,8 @@ public class SQLiteUtil { | ||||
|             stmt.execute("PRAGMA temp_store=MEMORY;");      // 临时表/索引存内存(减少磁盘IO) | ||||
|             stmt.execute("PRAGMA busy_timeout=2000;");       // 忙等待超时:2秒(避免瞬时并发锁等待) | ||||
|         } catch (SQLException e) { | ||||
|             throw new RuntimeException("初始化SQLite数据源失败(路径:" + dbFilePath + ")", e); | ||||
|             e.printStackTrace(); | ||||
|             throw new RuntimeException("初始化SQLite数据源失败(路径:" + dbFilePath + ")+ 原因是:" + e.getMessage()); | ||||
|         } | ||||
|  | ||||
|         return dataSource; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 ZZX9599
					ZZX9599