修复下载GDB没有ID字段BUG
This commit is contained in:
@@ -44,6 +44,7 @@ import org.opengis.feature.simple.SimpleFeatureType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -76,6 +77,9 @@ public class ExportController{
|
||||
private final UserService userService;
|
||||
private final ExportService exportService;
|
||||
|
||||
@Value("${gdal.proj.lib:}")
|
||||
private String configuredProjLib;
|
||||
|
||||
@Autowired
|
||||
public ExportController(ITaskService taskService, IBaseService baseService, UserService userService, ExportService exportService){
|
||||
this.taskService = taskService;
|
||||
@@ -302,16 +306,135 @@ public String taskTableDataExport(Integer taskId, String tableName,
|
||||
// return ResultMessage.success(null).toString();
|
||||
//}
|
||||
/**
|
||||
* 下载数据接口,导出单个任务为gdb
|
||||
* 初始化 GDAL/OGR 环境
|
||||
*/
|
||||
@RequestMapping(value = "taskGdbExport", produces = "text/html;charset=UTF-8")
|
||||
public String taskGdbExport(Integer taskId, HttpServletResponse response) throws IOException {
|
||||
private void initializeGdal() {
|
||||
ogr.RegisterAll();
|
||||
gdal.AllRegister();
|
||||
// 支持中文路径和中文字段名
|
||||
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
|
||||
gdal.SetConfigOption("SHAPE_ENCODING", "");
|
||||
|
||||
// 尝试设置 PROJ_LIB 以避免版本冲突
|
||||
// 优先级:配置文件 > 环境变量 > 自动查找
|
||||
String projLib = null;
|
||||
|
||||
// 1. 首先检查配置文件中的设置
|
||||
if (StringUtils.isNotBlank(configuredProjLib)) {
|
||||
File configProjDb = new File(configuredProjLib, "proj.db");
|
||||
if (configProjDb.exists()) {
|
||||
projLib = configuredProjLib;
|
||||
logger.info("使用配置文件中的 PROJ_LIB: {}", projLib);
|
||||
} else {
|
||||
logger.warn("配置文件中指定的 PROJ_LIB 路径不存在或未找到 proj.db: {}", configuredProjLib);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 如果配置文件未设置,检查环境变量
|
||||
if (StringUtils.isBlank(projLib)) {
|
||||
projLib = System.getenv("PROJ_LIB");
|
||||
if (StringUtils.isNotBlank(projLib)) {
|
||||
File envProjDb = new File(projLib, "proj.db");
|
||||
if (envProjDb.exists()) {
|
||||
logger.info("使用环境变量中的 PROJ_LIB: {}", projLib);
|
||||
} else {
|
||||
logger.warn("环境变量 PROJ_LIB 指定的路径未找到 proj.db: {}", projLib);
|
||||
projLib = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 如果都未设置,尝试从 Java 库路径自动查找
|
||||
if (StringUtils.isBlank(projLib)) {
|
||||
String javaLibPath = System.getProperty("java.library.path");
|
||||
if (StringUtils.isNotBlank(javaLibPath)) {
|
||||
String[] paths = javaLibPath.split(File.pathSeparator);
|
||||
for (String path : paths) {
|
||||
// 检查直接路径
|
||||
File projDbFile = new File(path, "proj.db");
|
||||
if (projDbFile.exists()) {
|
||||
projLib = path;
|
||||
logger.info("自动找到 PROJ 数据库路径: {}", path);
|
||||
break;
|
||||
}
|
||||
// 检查 share/proj 子目录
|
||||
File projShareDir = new File(path, "share/proj");
|
||||
if (projShareDir.exists() && new File(projShareDir, "proj.db").exists()) {
|
||||
projLib = projShareDir.getAbsolutePath();
|
||||
logger.info("自动找到 PROJ 数据库路径: {}", projLib);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 设置 PROJ_LIB(如果找到)
|
||||
if (StringUtils.isNotBlank(projLib)) {
|
||||
gdal.SetConfigOption("PROJ_LIB", projLib);
|
||||
logger.info("已设置 PROJ_LIB: {}", projLib);
|
||||
} else {
|
||||
logger.warn("未找到有效的 PROJ_LIB 路径,将使用系统默认路径(可能遇到版本冲突)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建空间参考系统(CGCS2000,EPSG:4490)
|
||||
* 如果 ImportFromEPSG 失败,尝试使用 WKT 字符串
|
||||
*/
|
||||
private SpatialReference createSpatialReference() {
|
||||
SpatialReference srs = new SpatialReference();
|
||||
|
||||
// 首先尝试使用 EPSG 代码
|
||||
try {
|
||||
int result = srs.ImportFromEPSG(4490);
|
||||
if (result == 0) {
|
||||
logger.debug("成功使用 EPSG:4490 创建空间参考");
|
||||
return srs;
|
||||
}
|
||||
logger.warn("EPSG:4490 导入返回错误码: {}", result);
|
||||
} catch (Exception e) {
|
||||
logger.warn("EPSG:4490 导入失败,异常: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 如果失败,尝试使用 WKT 字符串(CGCS2000 的 WKT)
|
||||
logger.info("尝试使用 WKT 字符串创建空间参考");
|
||||
try {
|
||||
String wkt = "GEOGCS[\"CGCS2000\",DATUM[\"China_2000\",SPHEROID[\"CGCS2000\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]";
|
||||
int result = srs.ImportFromWkt(wkt);
|
||||
if (result == 0) {
|
||||
logger.info("成功使用 WKT 创建空间参考");
|
||||
return srs;
|
||||
}
|
||||
logger.warn("WKT 导入返回错误码: {}", result);
|
||||
} catch (Exception e) {
|
||||
logger.warn("WKT 导入失败,异常: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 如果都失败,尝试使用 WGS84 作为备选(至少不会崩溃)
|
||||
logger.warn("无法创建 CGCS2000 空间参考,使用 WGS84 (EPSG:4326) 作为备选");
|
||||
try {
|
||||
srs = new SpatialReference();
|
||||
int result = srs.ImportFromEPSG(4326);
|
||||
if (result == 0) {
|
||||
logger.info("成功使用 WGS84 作为备选空间参考");
|
||||
return srs;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("WGS84 导入也失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 最后的备选:创建一个未定义的空间参考
|
||||
logger.error("所有空间参考创建方法都失败,返回未定义的空间参考");
|
||||
return new SpatialReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载数据接口,导出单个任务为gdb
|
||||
*/
|
||||
@RequestMapping(value = "taskGdbExport", produces = "text/html;charset=UTF-8")
|
||||
public String taskGdbExport(Integer taskId, HttpServletResponse response) throws IOException {
|
||||
initializeGdal();
|
||||
|
||||
Task task = taskService.getTaskById(taskId);
|
||||
if (task == null) return ResultMessage.failed("任务不存在").toString();
|
||||
|
||||
@@ -342,11 +465,7 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
public String batchGdbExport(@RequestParam List<Integer> taskIds, HttpServletResponse response) throws IOException {
|
||||
if (taskIds == null || taskIds.isEmpty()) return ResultMessage.failed("任务ID列表为空").toString();
|
||||
|
||||
ogr.RegisterAll();
|
||||
gdal.AllRegister();
|
||||
// 支持中文路径和中文字段名
|
||||
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
|
||||
gdal.SetConfigOption("SHAPE_ENCODING", "");
|
||||
initializeGdal();
|
||||
|
||||
String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis();
|
||||
File exportDirFile = new File(exportDir);
|
||||
@@ -452,8 +571,7 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
* 添加带几何的图层到 GDB(支持 Polygon 和 MultiPolygon)
|
||||
*/
|
||||
private void addGeometryLayerToGdb(DataSource dataSource, Table table, String layerName, List<Map<String, Object>> dataList) {
|
||||
SpatialReference srs = new SpatialReference();
|
||||
srs.ImportFromEPSG(4490); // CGCS2000
|
||||
SpatialReference srs = createSpatialReference(); // 使用改进的空间参考创建方法
|
||||
|
||||
// ✅ 直接从 JSON 中解析几何类型
|
||||
int geomType = ogr.wkbPolygon; // 默认 Polygon
|
||||
@@ -487,6 +605,20 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
List<String> fieldNameOrder = genFieldNameOrderStringArr(table, "");
|
||||
if (fieldNameOrder == null || fieldNameOrder.isEmpty()) return;
|
||||
|
||||
String primaryKey = TableOperationUtil.getPrimaryKey(table);
|
||||
|
||||
// ✅ 主键字段(默认整数型)
|
||||
if (StringUtils.isNotBlank(primaryKey)) {
|
||||
Field pkField = table.getFields().get(primaryKey);
|
||||
FieldDefn pkDefn = new FieldDefn(primaryKey, ogr.OFTInteger);
|
||||
if (pkField != null && StringUtils.isNotBlank(pkField.getName())) {
|
||||
try {
|
||||
pkDefn.SetAlternativeName(pkField.getName());
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
layer.CreateField(pkDefn);
|
||||
}
|
||||
|
||||
// ✅ 字段创建(英文名 + 中文别名)
|
||||
for (String fieldName : fieldNameOrder) {
|
||||
Field field = table.getFields().get(fieldName);
|
||||
@@ -503,6 +635,18 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
for (Map<String, Object> row : dataList) {
|
||||
Feature feature = new Feature(layer.GetLayerDefn());
|
||||
|
||||
// 主键写入
|
||||
if (StringUtils.isNotBlank(primaryKey)) {
|
||||
Object pkVal = row.get(primaryKey);
|
||||
if (pkVal instanceof Number) {
|
||||
feature.SetField(primaryKey, ((Number) pkVal).longValue());
|
||||
} else if (pkVal != null) {
|
||||
feature.SetField(primaryKey, pkVal.toString());
|
||||
} else {
|
||||
feature.SetFieldNull(primaryKey);
|
||||
}
|
||||
}
|
||||
|
||||
// 属性写入
|
||||
for (String fieldName : fieldNameOrder) {
|
||||
Object val = row.get(fieldName);
|
||||
@@ -549,6 +693,19 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(primaryKey)) {
|
||||
Field pkField = table.getFields().get(primaryKey);
|
||||
FieldDefn pkDefn = new FieldDefn(primaryKey, ogr.OFTInteger);
|
||||
if (pkField != null && StringUtils.isNotBlank(pkField.getName())) {
|
||||
try {
|
||||
pkDefn.SetAlternativeName(pkField.getName());
|
||||
} catch (Exception e) {
|
||||
System.err.println("⚠️ 设置主键别名失败:" + primaryKey + " → " + pkField.getName());
|
||||
}
|
||||
}
|
||||
layer.CreateField(pkDefn);
|
||||
}
|
||||
|
||||
// ✅ 创建字段(英文名 + 中文别名)
|
||||
for (String fieldName : fieldNameOrder) {
|
||||
if (fieldName == null || fieldName.trim().isEmpty()) continue;
|
||||
@@ -570,6 +727,17 @@ public String taskGdbExport(Integer taskId, HttpServletResponse response) throws
|
||||
FeatureDefn featureDefn = layer.GetLayerDefn();
|
||||
Feature feature = new Feature(featureDefn);
|
||||
|
||||
if (StringUtils.isNotBlank(primaryKey)) {
|
||||
Object pkVal = row.get(primaryKey);
|
||||
if (pkVal instanceof Number) {
|
||||
feature.SetField(primaryKey, ((Number) pkVal).longValue());
|
||||
} else if (pkVal != null) {
|
||||
feature.SetField(primaryKey, pkVal.toString());
|
||||
} else {
|
||||
feature.SetFieldNull(primaryKey);
|
||||
}
|
||||
}
|
||||
|
||||
for (String fieldName : fieldNameOrder) {
|
||||
Object val = row.get(fieldName);
|
||||
feature.SetField(fieldName, val == null ? "" : val.toString());
|
||||
|
||||
@@ -122,7 +122,7 @@ public class StoreMediaFileUtil{
|
||||
// return destFileName;
|
||||
// }
|
||||
public static String zip(String mediaPath, List<String> filePathList, String password) {
|
||||
String destFileName = mediaPath + "/temp.zip";
|
||||
String destFileName = mediaPath + File.separator + "temp.zip";
|
||||
ZipParameters zipParam = new ZipParameters();
|
||||
zipParam.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
|
||||
zipParam.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
|
||||
@@ -137,8 +137,20 @@ public class StoreMediaFileUtil{
|
||||
ZipFile zipfile = new ZipFile(destFileName);
|
||||
|
||||
for (String filePath : filePathList) {
|
||||
File srcFile = new File(filePath.contains(CommonConstant.STATIC_RESOURCE_ROOT) ? filePath : mediaPath + filePath);
|
||||
//File srcFile = new File(filePath);
|
||||
File srcFile;
|
||||
// 判断是否为绝对路径
|
||||
File pathFile = new File(filePath);
|
||||
if (pathFile.isAbsolute()) {
|
||||
// 绝对路径直接使用
|
||||
srcFile = pathFile;
|
||||
} else if (filePath.contains(CommonConstant.STATIC_RESOURCE_ROOT)) {
|
||||
// 包含静态资源根路径,直接使用
|
||||
srcFile = new File(filePath);
|
||||
} else {
|
||||
// 相对路径,需要拼接 mediaPath
|
||||
srcFile = new File(mediaPath + File.separator + filePath);
|
||||
}
|
||||
|
||||
if (!srcFile.exists()) {
|
||||
System.err.println("⚠️ 文件或目录不存在,跳过:" + srcFile.getAbsolutePath());
|
||||
continue;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
spring.profiles.active=dev
|
||||
|
||||
server.port=9001
|
||||
server.port=9006
|
||||
server.address=0.0.0.0
|
||||
|
||||
spring.datasource.host=localhost
|
||||
spring.datasource.port=5432
|
||||
spring.datasource.database=tj_project
|
||||
spring.datasource.database=eldc1125important
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.datasource.url=jdbc:postgresql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.database}?useSSL=true&allowMultiQueries=true
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=503503
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.idle-timeout=180000
|
||||
spring.datasource.hikari.maximum-pool-size=30
|
||||
@@ -33,7 +33,7 @@ logging.level.cn.edu.whu.boot.*.mapper=debug
|
||||
mybatis.mapper-locations=classpath:mapper/**/*.xml
|
||||
mybatis.configuration.map-underscore-to-camel-case=true
|
||||
|
||||
static.file.path=E:/503/TJ_project/static
|
||||
static.file.path=C:/tj_lydc/static
|
||||
|
||||
ApkFilePath=${static.file.path}/apk
|
||||
photozippath=${static.file.path}/zip
|
||||
@@ -72,3 +72,9 @@ spring.mail.properties.mail.smtp.starttls.enable=true
|
||||
spring.mail.properties.mail.smtp.starttls.required=true
|
||||
spring.mail.properties.mail.smtp.ssl.enable=true
|
||||
email.subject=
|
||||
|
||||
# GDAL/PROJ 配置
|
||||
# PROJ_LIB 路径(可选,如果不设置则自动查找)
|
||||
# 例如:gdal.proj.lib=E:/Java/jdk1.8.0_201/bin
|
||||
# 或者:gdal.proj.lib=E:/Java/jdk1.8.0_201/bin/share/proj
|
||||
gdal.proj.lib=C:/Java/gdal/bin/proj9/share
|
||||
Reference in New Issue
Block a user