864 lines
34 KiB
Java
864 lines
34 KiB
Java
|
|
package org.example;
|
|||
|
|
|
|||
|
|
import org.apache.poi.openxml4j.util.ZipSecureFile;
|
|||
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|||
|
|
import org.apache.poi.ss.usermodel.Row;
|
|||
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|||
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|||
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|||
|
|
|
|||
|
|
import java.io.File;
|
|||
|
|
import java.io.FileInputStream;
|
|||
|
|
import java.sql.Connection;
|
|||
|
|
import java.sql.PreparedStatement;
|
|||
|
|
import java.sql.ResultSet;
|
|||
|
|
import java.sql.Timestamp;
|
|||
|
|
import java.util.ArrayList;
|
|||
|
|
import java.util.List;
|
|||
|
|
import java.util.UUID;
|
|||
|
|
import java.util.regex.Matcher;
|
|||
|
|
import java.util.regex.Pattern;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ---------纵断面数据导入器(根据实际Excel格式修正版)
|
|||
|
|
*/
|
|||
|
|
public class IaShzhVsurfaceDataImporter2 {
|
|||
|
|
|
|||
|
|
// 纵断面主表插入SQL
|
|||
|
|
private static final String INSERT_VSURFACE_SQL =
|
|||
|
|
"INSERT INTO SHZH_JCSJ.IA_M_VSURFACE " +
|
|||
|
|
"(ZECD, ADCD, CHANNEL, ADDRESS, ISCTOWN, BASEELE, BASELGTD, BASELTTD, ELETYPE, " +
|
|||
|
|
"METHOD, SIGNER, AUDID, STATUS, REMARK, MODITIME, ISENABLE, IMPORTYEAR, AUDBATCH, " +
|
|||
|
|
"CADCD, GUID, INPUTTYPE, WSCD, SURFACE_CLASSIFY, OBJECT_NAME) " +
|
|||
|
|
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
|||
|
|
|
|||
|
|
// 纵断面点表插入SQL
|
|||
|
|
private static final String INSERT_VSPOINT_SQL =
|
|||
|
|
"INSERT INTO SHZH_JCSJ.IA_M_VSPOINT " +
|
|||
|
|
"(ZSURFACEID, TRANSECTNAME, FID, POINT, DISTANCE, DIRECTION, HDEELE, SMEELE, " +
|
|||
|
|
"LGTD, LTTD, MODITIME, REMARK, GUID, CHANNEL) " +
|
|||
|
|
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
|||
|
|
|
|||
|
|
// 检查纵断面主表重复的SQL
|
|||
|
|
private static final String CHECK_VSURFACE_DUPLICATE_SQL =
|
|||
|
|
"SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_VSURFACE WHERE ZECD = ? and SURFACE_CLASSIFY = ?";
|
|||
|
|
|
|||
|
|
// 检查纵断面点表重复的SQL
|
|||
|
|
private static final String CHECK_VSPOINT_DUPLICATE_SQL =
|
|||
|
|
"SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_VSPOINT WHERE ZSURFACEID = ? AND FID = ?";
|
|||
|
|
|
|||
|
|
public static void main(String[] args) {
|
|||
|
|
// 测试用的固定路径
|
|||
|
|
// args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\111"};
|
|||
|
|
// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"};
|
|||
|
|
// args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"};
|
|||
|
|
// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"};
|
|||
|
|
|
|||
|
|
args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\111"};
|
|||
|
|
if (args.length == 0) {
|
|||
|
|
System.out.println("请提供湖工大9.29目录路径作为参数");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
String baseDir = args[0];
|
|||
|
|
File baseDirectory = new File(baseDir);
|
|||
|
|
|
|||
|
|
if (!baseDirectory.exists() || !baseDirectory.isDirectory()) {
|
|||
|
|
System.out.println("指定的目录不存在或不是有效目录: " + baseDir);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("开始处理目录: " + baseDir);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
processAllCounties(baseDirectory);
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("处理过程中发生错误: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void processAllCounties(File baseDir) {
|
|||
|
|
File[] countyDirs = baseDir.listFiles(File::isDirectory);
|
|||
|
|
if (countyDirs == null) {
|
|||
|
|
System.out.println("在基础目录下未找到任何县市文件夹");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int totalProcessed = 0;
|
|||
|
|
int totalSuccess = 0;
|
|||
|
|
int totalDuplicates = 0;
|
|||
|
|
int totalPointDuplicates = 0;
|
|||
|
|
|
|||
|
|
System.out.println("找到 " + countyDirs.length + " 个县市文件夹");
|
|||
|
|
|
|||
|
|
for (File countyDir : countyDirs) {
|
|||
|
|
String countyName = extractCountyName(countyDir.getName());
|
|||
|
|
System.out.println("\n=== 处理县市: " + countyName + " ===");
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
ProcessResult result = processCountyData(countyDir, countyName);
|
|||
|
|
totalProcessed += result.processed;
|
|||
|
|
totalDuplicates += result.duplicates;
|
|||
|
|
totalPointDuplicates += result.pointDuplicates;
|
|||
|
|
totalSuccess++;
|
|||
|
|
System.out.println("✓ 成功处理 " + countyName +
|
|||
|
|
",导入 " + result.processed + " 条记录,跳过 " + result.duplicates +
|
|||
|
|
" 条重复记录,断面点跳过 " + result.pointDuplicates + " 条重复记录");
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("\n=== 处理完成 ===");
|
|||
|
|
System.out.println("成功处理县市: " + totalSuccess + " 个");
|
|||
|
|
System.out.println("总导入记录: " + totalProcessed + " 条");
|
|||
|
|
System.out.println("纵断面主表跳过重复记录: " + totalDuplicates + " 条");
|
|||
|
|
System.out.println("纵断面点表跳过重复记录: " + totalPointDuplicates + " 条");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ProcessResult processCountyData(File countyDir, String countyName) throws Exception {
|
|||
|
|
int totalProcessed = 0;
|
|||
|
|
int totalDuplicates = 0;
|
|||
|
|
int totalPointDuplicates = 0;
|
|||
|
|
|
|||
|
|
// 查找小流域目录
|
|||
|
|
File watershedDir = findWatershedDirectory(countyDir);
|
|||
|
|
if (watershedDir == null) {
|
|||
|
|
System.out.println("在 " + countyName + " 下未找到小流域目录");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
System.out.println("找到小流域目录: " + watershedDir.getName());
|
|||
|
|
|
|||
|
|
// 查找所有水系目录
|
|||
|
|
File[] sxDirs = findSxDirectories(watershedDir);
|
|||
|
|
if (sxDirs == null || sxDirs.length == 0) {
|
|||
|
|
System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("找到 " + sxDirs.length + " 个水系文件夹:");
|
|||
|
|
for (File sxDir : sxDirs) {
|
|||
|
|
System.out.println(" - " + sxDir.getName());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 遍历处理每个水系文件夹
|
|||
|
|
for (File sxDir : sxDirs) {
|
|||
|
|
System.out.println("\n处理水系: " + sxDir.getName());
|
|||
|
|
ProcessResult result = processSxData(sxDir, countyName);
|
|||
|
|
totalProcessed += result.processed;
|
|||
|
|
totalDuplicates += result.duplicates;
|
|||
|
|
totalPointDuplicates += result.pointDuplicates;
|
|||
|
|
System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " +
|
|||
|
|
result.duplicates + " 条重复记录,断面点跳过 " + result.pointDuplicates + " 条重复记录");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new ProcessResult(totalProcessed, totalDuplicates, totalPointDuplicates);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ProcessResult processSxData(File sxDir, String countyName) throws Exception {
|
|||
|
|
int processedCount = 0;
|
|||
|
|
int duplicateCount = 0;
|
|||
|
|
int pointDuplicateCount = 0;
|
|||
|
|
|
|||
|
|
// 按照新的目录结构查找文件
|
|||
|
|
File crossSectionDir = findCrossSectionDirectory(sxDir);
|
|||
|
|
if (crossSectionDir == null) {
|
|||
|
|
System.out.println("在 " + sxDir.getPath() + " 下未找到纵断面成果表目录");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
System.out.println("找到纵断面成果表目录: " + crossSectionDir.getPath());
|
|||
|
|
|
|||
|
|
// 查找所有Excel文件
|
|||
|
|
File[] excelFiles = findExcelFiles(crossSectionDir);
|
|||
|
|
if (excelFiles == null || excelFiles.length == 0) {
|
|||
|
|
System.out.println("在 " + crossSectionDir.getPath() + " 下未找到纵断面Excel文件");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("找到 " + excelFiles.length + " 个纵断面Excel文件:");
|
|||
|
|
for (File excelFile : excelFiles) {
|
|||
|
|
System.out.println(" - " + excelFile.getName());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提取流域编码
|
|||
|
|
String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName());
|
|||
|
|
System.out.println("流域编码: " + watershedCode);
|
|||
|
|
|
|||
|
|
// 处理每个Excel文件
|
|||
|
|
for (File excelFile : excelFiles) {
|
|||
|
|
System.out.println("\n处理文件: " + excelFile.getName());
|
|||
|
|
try {
|
|||
|
|
// 验证文件是否为有效Excel文件
|
|||
|
|
if (!isValidExcelFile(excelFile)) {
|
|||
|
|
System.err.println("跳过无效的Excel文件: " + excelFile.getName());
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ProcessResult result = readExcelAndImport(excelFile, countyName, watershedCode);
|
|||
|
|
processedCount += result.processed;
|
|||
|
|
duplicateCount += result.duplicates;
|
|||
|
|
pointDuplicateCount += result.pointDuplicates;
|
|||
|
|
System.out.println("文件 " + excelFile.getName() + " 导入 " + result.processed +
|
|||
|
|
" 条记录,跳过 " + result.duplicates + " 条重复记录");
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("处理文件 " + excelFile.getName() + " 时出错: " + e.getMessage());
|
|||
|
|
if (e.getMessage().contains("valid OOXML")) {
|
|||
|
|
System.err.println(" 文件可能损坏或格式不正确,跳过此文件");
|
|||
|
|
}
|
|||
|
|
// 继续处理下一个文件
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new ProcessResult(processedCount, duplicateCount, pointDuplicateCount);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 验证文件是否为有效的Excel文件
|
|||
|
|
*/
|
|||
|
|
private static boolean isValidExcelFile(File file) {
|
|||
|
|
if (!file.exists() || !file.isFile()) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查文件扩展名
|
|||
|
|
String fileName = file.getName().toLowerCase();
|
|||
|
|
if (!fileName.endsWith(".xlsx")) {
|
|||
|
|
System.err.println("文件扩展名不是.xlsx: " + file.getName());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查文件大小
|
|||
|
|
if (file.length() == 0) {
|
|||
|
|
System.err.println("文件大小为0: " + file.getName());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 尝试打开文件验证格式
|
|||
|
|
try (FileInputStream fis = new FileInputStream(file)) {
|
|||
|
|
// 只读取文件头进行验证,不加载整个文件
|
|||
|
|
byte[] header = new byte[4];
|
|||
|
|
if (fis.read(header) != 4) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
// Excel文件的文件头特征
|
|||
|
|
if (header[0] != 0x50 || header[1] != 0x4B || header[2] != 0x03 || header[3] != 0x04) {
|
|||
|
|
System.err.println("文件头不符合Excel格式: " + file.getName());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("验证Excel文件失败: " + file.getName() + " - " + e.getMessage());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private static ProcessResult readExcelAndImport(File excelFile, String countyName, String wscd) throws Exception {
|
|||
|
|
int importedCount = 0;
|
|||
|
|
int duplicateCount = 0;
|
|||
|
|
int pointDuplicateCount = 0;
|
|||
|
|
|
|||
|
|
// 先读取所有数据到内存
|
|||
|
|
List<Object[]> vsurfaceDataList = new ArrayList<>();
|
|||
|
|
List<Object[]> vspointDataList = new ArrayList<>();
|
|||
|
|
|
|||
|
|
readExcelData(wscd, excelFile, vsurfaceDataList, vspointDataList);
|
|||
|
|
|
|||
|
|
if (vsurfaceDataList.isEmpty()) {
|
|||
|
|
System.out.println("未读取到有效数据");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("成功读取 " + vsurfaceDataList.size() + " 条纵断面数据,包含 " +
|
|||
|
|
vspointDataList.size() + " 个断面点,开始导入数据库...");
|
|||
|
|
|
|||
|
|
// 批量导入数据库
|
|||
|
|
ProcessResult result = batchInsertData(vsurfaceDataList, vspointDataList);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void readExcelData(String wscd, File excelFile,
|
|||
|
|
List<Object[]> vsurfaceDataList,
|
|||
|
|
List<Object[]> vspointDataList) throws Exception {
|
|||
|
|
|
|||
|
|
// 保存原始设置
|
|||
|
|
double originalRatio = ZipSecureFile.getMinInflateRatio();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 临时调整安全阈值
|
|||
|
|
ZipSecureFile.setMinInflateRatio(0.001);
|
|||
|
|
|
|||
|
|
try (FileInputStream fis = new FileInputStream(excelFile);
|
|||
|
|
Workbook workbook = new XSSFWorkbook(fis)) {
|
|||
|
|
|
|||
|
|
String surfaceClassify=excelFile.getName();
|
|||
|
|
Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+");
|
|||
|
|
Matcher matcher = pattern.matcher(surfaceClassify);
|
|||
|
|
if(matcher.find()){
|
|||
|
|
surfaceClassify=matcher.group();
|
|||
|
|
}else{
|
|||
|
|
System.out.println("工作表表名有问题: " + surfaceClassify);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 遍历所有工作表
|
|||
|
|
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
|
|||
|
|
Sheet sheet = workbook.getSheetAt(sheetIndex);
|
|||
|
|
String sheetName = sheet.getSheetName();
|
|||
|
|
|
|||
|
|
// 跳过填表说明等非数据工作表
|
|||
|
|
if (sheetName.contains("填表说明") || sheetName.contains("说明")) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("处理工作表: " + sheetName);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 解析纵断面主表数据
|
|||
|
|
Object[] vsurfaceData = parseVsurfaceData(sheet, sheetName, wscd, surfaceClassify);
|
|||
|
|
if (vsurfaceData != null) {
|
|||
|
|
vsurfaceDataList.add(vsurfaceData);
|
|||
|
|
System.out.println("✓ 解析纵断面主表数据成功: " + sheetName);
|
|||
|
|
|
|||
|
|
// 解析断面点数据
|
|||
|
|
List<Object[]> points = parseVspointData(sheet, (String) vsurfaceData[19]);
|
|||
|
|
vspointDataList.addAll(points);
|
|||
|
|
System.out.println("✓ 解析 " + points.size() + " 个断面点数据");
|
|||
|
|
}
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("解析工作表 " + sheetName + " 时出错: " + e.getMessage());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} finally {
|
|||
|
|
// 恢复原始设置
|
|||
|
|
ZipSecureFile.setMinInflateRatio(originalRatio);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static Object[] parseVsurfaceData(Sheet sheet, String sheetName, String wscd, String surfaceClassify) {
|
|||
|
|
try {
|
|||
|
|
Object[] data = new Object[24]; // 对应24个插入参数
|
|||
|
|
|
|||
|
|
int index = 0;
|
|||
|
|
|
|||
|
|
// 根据Excel格式解析数据
|
|||
|
|
// 第1行:C列-所在位置
|
|||
|
|
String location = getCellValue(sheet, 0, 2); // C1单元格
|
|||
|
|
|
|||
|
|
// 第2行:C列-所在沟道,G列-行政区划代码
|
|||
|
|
String channel = getCellValue(sheet, 1, 2); // C2单元格
|
|||
|
|
String adminCode = getCellValue(sheet, 1, 6); // G2单元格
|
|||
|
|
|
|||
|
|
// 第3行:C列-是否跨县
|
|||
|
|
String isCrossCounty = getCellValue(sheet, 2, 2); // C3单元格
|
|||
|
|
|
|||
|
|
// 第4行:C列-控制点纬度,G列-控制点高程
|
|||
|
|
String baseLatitude = getCellValue(sheet, 3, 2); // C4单元格 - 控制点纬度
|
|||
|
|
String baseElevation = getCellValue(sheet, 3, 6); // G4单元格 - 控制点高程
|
|||
|
|
|
|||
|
|
// 第5行:C列-高程系,G列-测量方法
|
|||
|
|
String elevationType = getCellValue(sheet, 4, 2); // C5单元格 - 高程系
|
|||
|
|
String method = getCellValue(sheet, 4, 6); // G5单元格 - 测量方法
|
|||
|
|
|
|||
|
|
// 控制点经度(在Excel中没有明确位置,设为空)
|
|||
|
|
String baseLongitude = null;
|
|||
|
|
|
|||
|
|
// 1. ZECD - 纵断面编码 (工作表名)
|
|||
|
|
data[index++] = sheetName;
|
|||
|
|
|
|||
|
|
// 2. ADCD - 行政区划代码
|
|||
|
|
data[index++] = getSafeString(adminCode);
|
|||
|
|
|
|||
|
|
// 3. CHANNEL - 所在沟道
|
|||
|
|
data[index++] = getSafeString(channel);
|
|||
|
|
|
|||
|
|
// 4. ADDRESS - 所在位置
|
|||
|
|
data[index++] = getSafeString(location);
|
|||
|
|
|
|||
|
|
// 5. ISCTOWN - 是否跨县
|
|||
|
|
data[index++] = getSafeString(isCrossCounty);
|
|||
|
|
|
|||
|
|
// 6. BASEELE - 控制点高程
|
|||
|
|
data[index++] = getSafeString(baseElevation);
|
|||
|
|
|
|||
|
|
// 7. BASELGTD - 控制点经度
|
|||
|
|
data[index++] = getSafeString(baseLongitude);
|
|||
|
|
|
|||
|
|
// 8. BASELTTD - 控制点纬度
|
|||
|
|
data[index++] = getSafeString(baseLatitude);
|
|||
|
|
|
|||
|
|
// 9. ELETYPE - 高程系
|
|||
|
|
data[index++] = getSafeString(elevationType);
|
|||
|
|
|
|||
|
|
// 10. METHOD - 测量方法
|
|||
|
|
data[index++] = getSafeString(method);
|
|||
|
|
|
|||
|
|
// 11. SIGNER - 填写人姓名(默认为空)
|
|||
|
|
data[index++] = null;
|
|||
|
|
|
|||
|
|
// 12. AUDID - 审核批次号(默认为空)
|
|||
|
|
data[index++] = null;
|
|||
|
|
|
|||
|
|
// 13. STATUS - 状态(默认1-待审核)
|
|||
|
|
data[index++] = "1";
|
|||
|
|
|
|||
|
|
// 14. REMARK - 备注
|
|||
|
|
data[index++] = null;
|
|||
|
|
|
|||
|
|
// 15. MODITIME - 时间戳
|
|||
|
|
data[index++] = new Timestamp(System.currentTimeMillis());
|
|||
|
|
|
|||
|
|
// 16. ISENABLE - 启用状态
|
|||
|
|
data[index++] = "1";
|
|||
|
|
|
|||
|
|
// 17. IMPORTYEAR - 导入年份
|
|||
|
|
data[index++] = "2025";
|
|||
|
|
|
|||
|
|
// 18. AUDBATCH - 审核批次
|
|||
|
|
data[index++] = "BATCH_" + System.currentTimeMillis();
|
|||
|
|
|
|||
|
|
// 19. CADCD - 县级编码(从行政区划代码提取)
|
|||
|
|
data[index++] = adminCode != null && adminCode.length() >= 6 ?
|
|||
|
|
adminCode.substring(0, 6)+"000000000" : "";
|
|||
|
|
|
|||
|
|
// 20. GUID - 唯一标识
|
|||
|
|
String guid = UUID.randomUUID().toString();
|
|||
|
|
data[index++] = guid;
|
|||
|
|
|
|||
|
|
// 21. INPUTTYPE - 录入方式
|
|||
|
|
data[index++] = "1";
|
|||
|
|
|
|||
|
|
// 22. WSCD - 流域编码
|
|||
|
|
data[index++] = wscd;
|
|||
|
|
|
|||
|
|
// 23. SURFACE_CLASSIFY - 断面分类
|
|||
|
|
data[index++] = surfaceClassify;
|
|||
|
|
|
|||
|
|
// 24. OBJECT_NAME - 对象名称(使用沟道名称)
|
|||
|
|
data[index++] = null;
|
|||
|
|
|
|||
|
|
return data;
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("解析纵断面主表数据失败: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static List<Object[]> parseVspointData(Sheet sheet, String vsurfaceId) {
|
|||
|
|
List<Object[]> points = new ArrayList<>();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 找到数据开始行(从第7行开始,序号列开始)
|
|||
|
|
int startRow = 6; // 根据Excel格式,数据从第7行开始
|
|||
|
|
System.out.println("断面点数据从第 " + (startRow + 1) + " 行开始");
|
|||
|
|
|
|||
|
|
for (int i = startRow; i <= sheet.getLastRowNum(); i++) {
|
|||
|
|
Row row = sheet.getRow(i);
|
|||
|
|
if (row == null) continue;
|
|||
|
|
|
|||
|
|
// 检查序号列是否为空
|
|||
|
|
Cell serialCell = row.getCell(0);
|
|||
|
|
if (serialCell == null || isCellEmpty(serialCell)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Object[] pointData = parseVspointRowData(row, vsurfaceId, i - startRow + 1);
|
|||
|
|
if (pointData != null) {
|
|||
|
|
points.add(pointData);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("解析断面点数据失败: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return points;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static Object[] parseVspointRowData(Row row, String vsurfaceId, int fid) {
|
|||
|
|
try {
|
|||
|
|
Object[] data = new Object[14]; // 对应14个插入参数
|
|||
|
|
|
|||
|
|
int index = 0;
|
|||
|
|
|
|||
|
|
// 1. ZSURFACEID - 纵断面主表ID
|
|||
|
|
data[index++] = vsurfaceId;
|
|||
|
|
|
|||
|
|
// 2. TRANSECTNAME - 断面名称(使用测量点)
|
|||
|
|
String measurePoint = getCellStringValue(row.getCell(1));
|
|||
|
|
data[index++] = getSafeString(measurePoint);
|
|||
|
|
|
|||
|
|
// 3. FID - 断面序号
|
|||
|
|
data[index++] = fid;
|
|||
|
|
|
|||
|
|
// 4. POINT - 断面信息-测量点
|
|||
|
|
data[index++] = getSafeString(measurePoint);
|
|||
|
|
|
|||
|
|
// 5. DISTANCE - 断面信息-距离(m) - 第3列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(2)));
|
|||
|
|
|
|||
|
|
// 6. DIRECTION - 量距方向(°) - 第4列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3)));
|
|||
|
|
|
|||
|
|
// 7. HDEELE - 断面信息-河底高程(m) - 第5列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(4)));
|
|||
|
|
|
|||
|
|
// 8. SMEELE - 断面信息-水面高程(m) - 第6列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(5)));
|
|||
|
|
|
|||
|
|
// 9. LGTD - 经度(°) - 第7列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(6)));
|
|||
|
|
|
|||
|
|
// 10. LTTD - 纬度(°) - 第8列
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(7)));
|
|||
|
|
|
|||
|
|
// 11. MODITIME - 时间戳
|
|||
|
|
data[index++] = new Timestamp(System.currentTimeMillis());
|
|||
|
|
|
|||
|
|
// 12. REMARK - 备注
|
|||
|
|
data[index++] = null;
|
|||
|
|
|
|||
|
|
// 13. GUID - 唯一标识
|
|||
|
|
data[index++] = UUID.randomUUID().toString();
|
|||
|
|
|
|||
|
|
// 14. CHANNEL - 量距方向(°) - 使用第4列的值
|
|||
|
|
data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3)));
|
|||
|
|
|
|||
|
|
return data;
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("解析断面点行数据失败: " + e.getMessage());
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ProcessResult batchInsertData(List<Object[]> vsurfaceDataList, List<Object[]> vspointDataList) {
|
|||
|
|
int importedCount = 0;
|
|||
|
|
int duplicateCount = 0;
|
|||
|
|
int pointDuplicateCount = 0;
|
|||
|
|
|
|||
|
|
Connection conn = null;
|
|||
|
|
PreparedStatement vsurfacePstmt = null;
|
|||
|
|
PreparedStatement vspointPstmt = null;
|
|||
|
|
PreparedStatement checkVsurfaceDupPstmt = null;
|
|||
|
|
PreparedStatement checkVspointDupPstmt = null;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
conn = DatabaseUtil.getConnection();
|
|||
|
|
if (conn == null) {
|
|||
|
|
System.err.println("无法获取数据库连接");
|
|||
|
|
return new ProcessResult(0, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
vsurfacePstmt = conn.prepareStatement(INSERT_VSURFACE_SQL);
|
|||
|
|
vspointPstmt = conn.prepareStatement(INSERT_VSPOINT_SQL);
|
|||
|
|
checkVsurfaceDupPstmt = conn.prepareStatement(CHECK_VSURFACE_DUPLICATE_SQL);
|
|||
|
|
checkVspointDupPstmt = conn.prepareStatement(CHECK_VSPOINT_DUPLICATE_SQL);
|
|||
|
|
|
|||
|
|
conn.setAutoCommit(false); // 开启事务
|
|||
|
|
|
|||
|
|
// 处理纵断面主表数据
|
|||
|
|
for (Object[] rowData : vsurfaceDataList) {
|
|||
|
|
try {
|
|||
|
|
String zecd = (String) rowData[0];
|
|||
|
|
String surface_clasify = (String) rowData[22];
|
|||
|
|
// 检查纵断面是否重复
|
|||
|
|
checkVsurfaceDupPstmt.setString(1, zecd);
|
|||
|
|
checkVsurfaceDupPstmt.setString(2, surface_clasify);
|
|||
|
|
try (ResultSet rs = checkVsurfaceDupPstmt.executeQuery()) {
|
|||
|
|
if (rs.next() && rs.getInt(1) > 0) {
|
|||
|
|
duplicateCount++;
|
|||
|
|
System.out.println("跳过重复纵断面: " + zecd);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 插入数据 - 设置所有参数
|
|||
|
|
setVsurfaceParameters(vsurfacePstmt, rowData);
|
|||
|
|
vsurfacePstmt.executeUpdate();
|
|||
|
|
importedCount++;
|
|||
|
|
System.out.println("✓ 插入纵断面记录: " + zecd);
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("纵断面数据插入失败: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理纵断面点表数据
|
|||
|
|
int pointImportedCount = 0;
|
|||
|
|
for (Object[] pointData : vspointDataList) {
|
|||
|
|
try {
|
|||
|
|
String vsurfaceId = (String) pointData[0];
|
|||
|
|
Integer fid = (Integer) pointData[2];
|
|||
|
|
|
|||
|
|
// 检查断面点是否重复
|
|||
|
|
checkVspointDupPstmt.setString(1, vsurfaceId);
|
|||
|
|
checkVspointDupPstmt.setInt(2, fid);
|
|||
|
|
try (ResultSet rs = checkVspointDupPstmt.executeQuery()) {
|
|||
|
|
if (rs.next() && rs.getInt(1) > 0) {
|
|||
|
|
pointDuplicateCount++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 插入数据 - 设置所有参数
|
|||
|
|
setVspointParameters(vspointPstmt, pointData);
|
|||
|
|
vspointPstmt.addBatch();
|
|||
|
|
pointImportedCount++;
|
|||
|
|
|
|||
|
|
// 每10条执行一次批量插入
|
|||
|
|
if (pointImportedCount % 10 == 0) {
|
|||
|
|
vspointPstmt.executeBatch();
|
|||
|
|
vspointPstmt.clearBatch(); // 清空批量
|
|||
|
|
System.out.println("已批量插入 " + pointImportedCount + " 条断面点记录");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("断面点数据插入失败: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行剩余的断面点批量插入
|
|||
|
|
if (pointImportedCount > 0) {
|
|||
|
|
vspointPstmt.executeBatch();
|
|||
|
|
System.out.println("最终批量插入完成,共 " + pointImportedCount + " 条断面点记录");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
conn.commit(); // 提交事务
|
|||
|
|
System.out.println("事务提交成功");
|
|||
|
|
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("批量插入数据失败: " + e.getMessage());
|
|||
|
|
e.printStackTrace();
|
|||
|
|
if (conn != null) {
|
|||
|
|
try {
|
|||
|
|
conn.rollback();
|
|||
|
|
System.out.println("事务回滚成功");
|
|||
|
|
} catch (Exception rollbackEx) {
|
|||
|
|
System.err.println("事务回滚失败: " + rollbackEx.getMessage());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} finally {
|
|||
|
|
// 关闭资源
|
|||
|
|
closeResource(checkVspointDupPstmt);
|
|||
|
|
closeResource(checkVsurfaceDupPstmt);
|
|||
|
|
closeResource(vspointPstmt);
|
|||
|
|
closeResource(vsurfacePstmt);
|
|||
|
|
closeResource(conn);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new ProcessResult(importedCount, duplicateCount, pointDuplicateCount);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置纵断面主表参数
|
|||
|
|
private static void setVsurfaceParameters(PreparedStatement pstmt, Object[] rowData) throws Exception {
|
|||
|
|
for (int i = 0; i < rowData.length; i++) {
|
|||
|
|
Object value = rowData[i];
|
|||
|
|
if (value == null) {
|
|||
|
|
pstmt.setNull(i + 1, java.sql.Types.NULL);
|
|||
|
|
} else if (value instanceof String) {
|
|||
|
|
pstmt.setString(i + 1, (String) value);
|
|||
|
|
} else if (value instanceof Double) {
|
|||
|
|
pstmt.setDouble(i + 1, (Double) value);
|
|||
|
|
} else if (value instanceof Integer) {
|
|||
|
|
pstmt.setInt(i + 1, (Integer) value);
|
|||
|
|
} else if (value instanceof Timestamp) {
|
|||
|
|
pstmt.setTimestamp(i + 1, (Timestamp) value);
|
|||
|
|
} else {
|
|||
|
|
pstmt.setObject(i + 1, value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置纵断面点表参数
|
|||
|
|
private static void setVspointParameters(PreparedStatement pstmt, Object[] pointData) throws Exception {
|
|||
|
|
for (int i = 0; i < pointData.length; i++) {
|
|||
|
|
Object value = pointData[i];
|
|||
|
|
if (value == null) {
|
|||
|
|
pstmt.setNull(i + 1, java.sql.Types.NULL);
|
|||
|
|
} else if (value instanceof String) {
|
|||
|
|
pstmt.setString(i + 1, (String) value);
|
|||
|
|
} else if (value instanceof Double) {
|
|||
|
|
pstmt.setDouble(i + 1, (Double) value);
|
|||
|
|
} else if (value instanceof Integer) {
|
|||
|
|
pstmt.setInt(i + 1, (Integer) value);
|
|||
|
|
} else if (value instanceof Timestamp) {
|
|||
|
|
pstmt.setTimestamp(i + 1, (Timestamp) value);
|
|||
|
|
} else {
|
|||
|
|
pstmt.setObject(i + 1, value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 安全关闭资源的方法
|
|||
|
|
private static void closeResource(AutoCloseable resource) {
|
|||
|
|
if (resource != null) {
|
|||
|
|
try {
|
|||
|
|
resource.close();
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
System.err.println("关闭资源时出错: " + e.getMessage());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 辅助方法:安全获取字符串,避免null
|
|||
|
|
private static String getSafeString(String value) {
|
|||
|
|
return value != null ? value : "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 辅助方法:解析Double,提供默认值
|
|||
|
|
private static Double parseDoubleWithDefault(String value) {
|
|||
|
|
if (value != null && !value.trim().isEmpty()) {
|
|||
|
|
try {
|
|||
|
|
return Double.parseDouble(value.trim());
|
|||
|
|
} catch (NumberFormatException e) {
|
|||
|
|
return 0.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 辅助方法
|
|||
|
|
private static class ProcessResult {
|
|||
|
|
int processed;
|
|||
|
|
int duplicates;
|
|||
|
|
int pointDuplicates;
|
|||
|
|
|
|||
|
|
ProcessResult(int processed, int duplicates, int pointDuplicates) {
|
|||
|
|
this.processed = processed;
|
|||
|
|
this.duplicates = duplicates;
|
|||
|
|
this.pointDuplicates = pointDuplicates;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 目录查找方法(保持不变)
|
|||
|
|
private static File findWatershedDirectory(File countyDir) {
|
|||
|
|
File[] subDirs = countyDir.listFiles(File::isDirectory);
|
|||
|
|
if (subDirs != null) {
|
|||
|
|
for (File subDir : subDirs) {
|
|||
|
|
if (subDir.getName().contains("小流域")) {
|
|||
|
|
return subDir;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (subDirs.length > 0) return subDirs[0];
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static File[] findSxDirectories(File watershedDir) {
|
|||
|
|
File[] subDirs = watershedDir.listFiles(File::isDirectory);
|
|||
|
|
if (subDirs != null) {
|
|||
|
|
List<File> sxDirs = new ArrayList<>();
|
|||
|
|
for (File subDir : subDirs) {
|
|||
|
|
if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWFF.*")) {
|
|||
|
|
sxDirs.add(subDir);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return sxDirs.toArray(new File[0]);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static File findCrossSectionDirectory(File sxDir) {
|
|||
|
|
// 按照新目录结构:水系目录 > 电子数据 > 测量数据 > 防治对象断面成果 > 纵断面成果表
|
|||
|
|
File electronicDataDir = findSubDirectory(sxDir, "电子数据");
|
|||
|
|
if (electronicDataDir == null) {
|
|||
|
|
System.out.println("在 " + sxDir.getPath() + " 下未找到电子数据目录");
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
File measureDataDir = findSubDirectory(electronicDataDir, "测量数据");
|
|||
|
|
if (measureDataDir == null) {
|
|||
|
|
System.out.println("在 " + electronicDataDir.getPath() + " 下未找到测量数据目录");
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
File sectionResultDir = findSubDirectory(measureDataDir, "防治对象断面成果");
|
|||
|
|
if (sectionResultDir == null) {
|
|||
|
|
System.out.println("在 " + measureDataDir.getPath() + " 下未找到防治对象断面成果目录");
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
File crossSectionDir = findSubDirectory(sectionResultDir, "纵断面成果表");
|
|||
|
|
if (crossSectionDir == null) {
|
|||
|
|
System.out.println("在 " + sectionResultDir.getPath() + " 下未找到纵断面成果表目录");
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return crossSectionDir;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static File findSubDirectory(File parentDir, String dirName) {
|
|||
|
|
File[] subDirs = parentDir.listFiles(File::isDirectory);
|
|||
|
|
if (subDirs != null) {
|
|||
|
|
for (File subDir : subDirs) {
|
|||
|
|
if (subDir.getName().equals(dirName)) {
|
|||
|
|
return subDir;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 如果没有精确匹配,尝试包含匹配
|
|||
|
|
for (File subDir : subDirs) {
|
|||
|
|
if (subDir.getName().contains(dirName)) {
|
|||
|
|
return subDir;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static File[] findExcelFiles(File crossSectionDir) {
|
|||
|
|
File[] files = crossSectionDir.listFiles((dir, name) ->
|
|||
|
|
name.toLowerCase().endsWith(".xlsx"));
|
|||
|
|
return files != null ? files : new File[0];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static String extractCountyName(String dirName) {
|
|||
|
|
return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static String getCellValue(Sheet sheet, int rowNum, int colNum) {
|
|||
|
|
Row row = sheet.getRow(rowNum);
|
|||
|
|
if (row != null) {
|
|||
|
|
Cell cell = row.getCell(colNum);
|
|||
|
|
return getCellStringValue(cell);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static String getCellStringValue(Cell cell) {
|
|||
|
|
if (cell == null) return null;
|
|||
|
|
try {
|
|||
|
|
switch (cell.getCellType()) {
|
|||
|
|
case STRING:
|
|||
|
|
return cell.getStringCellValue().trim();
|
|||
|
|
case NUMERIC:
|
|||
|
|
double num = cell.getNumericCellValue();
|
|||
|
|
return (num == (long) num) ? String.valueOf((long) num) : String.valueOf(num);
|
|||
|
|
case BOOLEAN:
|
|||
|
|
return String.valueOf(cell.getBooleanCellValue());
|
|||
|
|
default:
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static boolean isCellEmpty(Cell cell) {
|
|||
|
|
if (cell == null) return true;
|
|||
|
|
switch (cell.getCellType()) {
|
|||
|
|
case BLANK:
|
|||
|
|
return true;
|
|||
|
|
case STRING:
|
|||
|
|
return cell.getStringCellValue().trim().isEmpty();
|
|||
|
|
default:
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|