From 8698ce1568746c157696f46c1171f7378f0c9b6c Mon Sep 17 00:00:00 2001 From: wany <13995595726@qq.com> Date: Wed, 29 Oct 2025 15:31:28 +0800 Subject: [PATCH] init --- src/main/java/org/example/CommonUtils.java | 19 + src/main/java/org/example/DatabaseConfig.java | 40 + src/main/java/org/example/DatabaseTest.java | 48 + src/main/java/org/example/DatabaseUtil.java | 51 + .../java/org/example/GetWscdDataImporter.java | 194 ++++ .../java/org/example/IaEftsTownImporter.java | 646 ++++++++++++ .../org/example/IaGlaInfoDataImporter.java | 548 ++++++++++ .../org/example/IaHdpPointDataImporter.java | 613 ++++++++++++ .../org/example/IaRbadInfoDataImporter.java | 546 ++++++++++ .../org/example/IaShzhHdpDataImporter.java | 726 ++++++++++++++ .../example/IaShzhHsurfaceDataImporter.java | 915 +++++++++++++++++ .../example/IaShzhHsurfaceDataImporter2.java | 934 ++++++++++++++++++ .../example/IaShzhVsurfaceDataImporter.java | 846 ++++++++++++++++ .../example/IaShzhVsurfaceDataImporter2.java | 864 ++++++++++++++++ .../java/org/example/IaStHdpDataImporter.java | 588 +++++++++++ .../example/MountainFloodDataImporter.java | 639 ++++++++++++ src/main/java/org/example/Test.java | 8 + .../org/example/WatershedDataCleaner.java | 296 ++++++ 18 files changed, 8521 insertions(+) create mode 100644 src/main/java/org/example/CommonUtils.java create mode 100644 src/main/java/org/example/DatabaseConfig.java create mode 100644 src/main/java/org/example/DatabaseTest.java create mode 100644 src/main/java/org/example/DatabaseUtil.java create mode 100644 src/main/java/org/example/GetWscdDataImporter.java create mode 100644 src/main/java/org/example/IaEftsTownImporter.java create mode 100644 src/main/java/org/example/IaGlaInfoDataImporter.java create mode 100644 src/main/java/org/example/IaHdpPointDataImporter.java create mode 100644 src/main/java/org/example/IaRbadInfoDataImporter.java create mode 100644 src/main/java/org/example/IaShzhHdpDataImporter.java create mode 100644 src/main/java/org/example/IaShzhHsurfaceDataImporter.java create mode 100644 src/main/java/org/example/IaShzhHsurfaceDataImporter2.java create mode 100644 src/main/java/org/example/IaShzhVsurfaceDataImporter.java create mode 100644 src/main/java/org/example/IaShzhVsurfaceDataImporter2.java create mode 100644 src/main/java/org/example/IaStHdpDataImporter.java create mode 100644 src/main/java/org/example/MountainFloodDataImporter.java create mode 100644 src/main/java/org/example/Test.java create mode 100644 src/main/java/org/example/WatershedDataCleaner.java diff --git a/src/main/java/org/example/CommonUtils.java b/src/main/java/org/example/CommonUtils.java new file mode 100644 index 0000000..a6b6412 --- /dev/null +++ b/src/main/java/org/example/CommonUtils.java @@ -0,0 +1,19 @@ +package org.example; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CommonUtils { + + public static String extractWatershedCode(String dirName) { + Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+"); + Matcher matcher = pattern.matcher(dirName); + if(matcher.find()){ + return matcher.group(); + }else{ + System.out.println("小流域编码文件夹有问题: " + dirName); + } + return dirName; + } + +} diff --git a/src/main/java/org/example/DatabaseConfig.java b/src/main/java/org/example/DatabaseConfig.java new file mode 100644 index 0000000..7e50919 --- /dev/null +++ b/src/main/java/org/example/DatabaseConfig.java @@ -0,0 +1,40 @@ +package org.example;// DatabaseConfig.java +import java.io.InputStream; +import java.util.Properties; + +public class DatabaseConfig { + private static final Properties props = new Properties(); + + static { + try (InputStream input = DatabaseConfig.class.getClassLoader() + .getResourceAsStream("database.properties")) { + if (input == null) { + // 使用默认配置 + props.setProperty("db.url", "jdbc:dm://10.0.41.113:5236/SHZH_JCSJ"); + props.setProperty("db.username", "SYSDBA"); + props.setProperty("db.password", "SYSDBA001"); + props.setProperty("db.driver", "dm.jdbc.driver.DmDriver"); + } else { + props.load(input); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String getUrl() { + return props.getProperty("db.url"); + } + + public static String getUsername() { + return props.getProperty("db.username"); + } + + public static String getPassword() { + return props.getProperty("db.password"); + } + + public static String getDriver() { + return props.getProperty("db.driver"); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/DatabaseTest.java b/src/main/java/org/example/DatabaseTest.java new file mode 100644 index 0000000..214db93 --- /dev/null +++ b/src/main/java/org/example/DatabaseTest.java @@ -0,0 +1,48 @@ +// DatabaseTest.java +package org.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class DatabaseTest { + + public static void main(String[] args) { + testConnection(); + } + + public static void testConnection() { + String[] urls = { +// "jdbc:dm://localhost:5236/SHZH_JCSJ", +// "jdbc:dm://127.0.0.1:5236/SHZH_JCSJ", + "jdbc:dm://10.0.41.113:5236/SHZH_JCSJ" + }; + + String username = "SYSDBA"; + String password = "SYSDBA001"; + + for (String url : urls) { + System.out.println("测试连接: " + url); + try { + Class.forName("dm.jdbc.driver.DmDriver"); + Connection conn = DriverManager.getConnection(url, username, password); + + // 测试简单查询 + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT 1 FROM DUAL"); + if (rs.next()) { + System.out.println("✓ 连接成功: " + url); + } + + rs.close(); + stmt.close(); + conn.close(); + return; // 成功则退出 + + } catch (Exception e) { + System.err.println("✗ 连接失败: " + url + " - " + e.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/DatabaseUtil.java b/src/main/java/org/example/DatabaseUtil.java new file mode 100644 index 0000000..f18a215 --- /dev/null +++ b/src/main/java/org/example/DatabaseUtil.java @@ -0,0 +1,51 @@ +// DatabaseUtil.java +package org.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class DatabaseUtil { + + // 达梦数据库配置 +// private static final String DB_URL = "jdbc:dm://10.0.41.113:5236/SHZH_JCSJ"; +// private static final String DB_USERNAME = "SYSDBA"; +// private static final String DB_PASSWORD = "SYSDBA001"; + + private static final String DB_URL = "jdbc:dm://10.42.6.248:5236/SHZH_JCSJ"; + private static final String DB_USERNAME = "SHZH"; + private static final String DB_PASSWORD = "Shzh_890"; + private static final String DB_DRIVER = "dm.jdbc.driver.DmDriver"; + + static { + try { + Class.forName(DB_DRIVER); + System.out.println("达梦数据库驱动加载成功"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("加载数据库驱动失败", e); + } + } + + public static Connection getConnection() throws SQLException { + try { + Connection conn = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD); + System.out.println("数据库连接成功"); + return conn; + } catch (SQLException e) { + System.err.println("数据库连接失败: " + e.getMessage()); + throw e; + } + } + + public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs) { + try { + if (rs != null) rs.close(); + if (pstmt != null) pstmt.close(); + if (conn != null) conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/GetWscdDataImporter.java b/src/main/java/org/example/GetWscdDataImporter.java new file mode 100644 index 0000000..8868d84 --- /dev/null +++ b/src/main/java/org/example/GetWscdDataImporter.java @@ -0,0 +1,194 @@ +// MountainFloodDataImporter.java +package org.example; + +import java.io.File; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; + +public class GetWscdDataImporter { + + public static void main(String[] args) { + // 先测试数据库连接 + if (!testDatabaseConnection()) { + System.err.println("数据库连接测试失败,程序退出"); + return; + } + + // 测试用的固定路径 + args = new String[]{"I:\\6666-华科26个流域1023-已统一表头-待入库"}; + + 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 boolean testDatabaseConnection() { + try { + Connection conn = DatabaseUtil.getConnection(); + if (conn != null && !conn.isClosed()) { + System.out.println("✓ 数据库连接测试成功"); + conn.close(); + return true; + } + } catch (Exception e) { + System.err.println("✗ 数据库连接测试失败: " + e.getMessage()); + } + return false; + } + + 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; + + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + List res = new ArrayList<>(); + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + // 获取该县市下所有小流域编码 + List watershedCodes = getWatershedCodesForCounty(countyDir); + System.out.println("在 " + countyName + " 下找到 " + watershedCodes.size() + " 个小流域编码:"); + for (String code : watershedCodes) { + System.out.println(" - " + code); + } + res.addAll(watershedCodes); + totalSuccess++; + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + e.printStackTrace(); + } + } + + System.out.println("\n=== 处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总找到小流域编码: " + totalProcessed + " 个"); + String s = ""; + for (String code : res) { + s += "'"+code+"',\n"; + } + System.out.println(s); + } + + /** + * 获取指定县市文件夹下的所有小流域编码 + */ + private static List getWatershedCodesForCounty(File countyDir) { + List watershedCodes = new ArrayList<>(); + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyDir.getName() + " 下未找到小流域目录"); + return watershedCodes; + } + + System.out.println("找到小流域目录: " + watershedDir.getName()); + + // 查找所有水系目录 + File[] sxDirs = findSxDirectories(watershedDir); + if (sxDirs == null || sxDirs.length == 0) { + System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录"); + return watershedCodes; + } + + System.out.println("找到 " + sxDirs.length + " 个水系文件夹:"); + + // 遍历处理每个水系文件夹,提取小流域编码 + for (File sxDir : sxDirs) { + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + if (watershedCode != null && !watershedCode.isEmpty()) { + watershedCodes.add(watershedCode); + System.out.println(" - " + sxDir.getName() + " -> 编码: " + watershedCode); + } + } + + return watershedCodes; + } + + + /** + * 查找小流域目录 + */ + 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + String dirName = subDir.getName(); + // 包含"水系"或者以HBWFF开头的文件夹都认为是水系文件夹 + if (dirName.contains("水系") || dirName.startsWith("HBWF")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + /** + * 提取县市名称 + */ + private static String extractCountyName(String dirName) { + if (dirName.contains("、")) { + String[] parts = dirName.split("、"); + return parts.length > 1 ? parts[1].trim() : parts[0].trim(); + } + return dirName; + } + + // 处理结果类 + private static class ProcessResult { + int processed; + int duplicates; + + ProcessResult(int processed, int duplicates) { + this.processed = processed; + this.duplicates = duplicates; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaEftsTownImporter.java b/src/main/java/org/example/IaEftsTownImporter.java new file mode 100644 index 0000000..b269939 --- /dev/null +++ b/src/main/java/org/example/IaEftsTownImporter.java @@ -0,0 +1,646 @@ +// MountainFloodEftsImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 表4 + */ +public class IaEftsTownImporter { + + // 外洪顶托集镇及村落调查分析成果表插入SQL + private static final String INSERT_EFTS_TOWN_SQL = + "INSERT INTO SHZH_JCSJ.IA_EFTS_TOWN (" + + "PCD, PNM, TM50, CRP50, NCRP50, TM100, CRP100, NCRP100, REMARK, ISENABLE, " + + "IMPORTYEAR, ADCD, INPUTTYPE, AUDID, STATUS, SIGNER, CADCD, GUID, AUDBATCH, WSCD" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + // 检查重复的SQL + private static final String CHECK_EFTS_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_EFTS_TOWN " + + "WHERE PCD = ? AND TM50 = ? AND TM100 = ?"; + + public static void main(String[] args) { + // 先测试数据库连接 + if (!testDatabaseConnection()) { + System.err.println("数据库连接测试失败,程序退出"); + return; + } + + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; +// args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"}; +// args = new String[]{"F:\\2222-华科-黄石局-14条小流域(10.20)-已通过初检-已统一表头-待入库"}; + args = new String[]{"F:\\小流域\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库"}; + + + 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 { + processAllEftsTables(baseDirectory); + } catch (Exception e) { + System.err.println("处理过程中发生错误: " + e.getMessage()); + e.printStackTrace(); + } + } + + private static boolean testDatabaseConnection() { + try { + Connection conn = DatabaseUtil.getConnection(); + if (conn != null && !conn.isClosed()) { + System.out.println("✓ 数据库连接测试成功"); + conn.close(); + return true; + } + } catch (Exception e) { + System.err.println("✗ 数据库连接测试失败: " + e.getMessage()); + } + return false; + } + + private static void processAllEftsTables(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 totalSkipped = 0; + + System.out.println("开始处理外洪顶托集镇及村落调查分析成果表..."); + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + ProcessResult result = processCountyEftsData(countyDir, countyName); + totalProcessed += result.processed; + totalDuplicates += result.duplicates; + totalSkipped += result.skipped; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + + ",导入 " + result.processed + " 条记录,跳过 " + result.duplicates + + " 条重复记录," + result.skipped + " 条因E列为空跳过"); + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + e.printStackTrace(); + } + } + + System.out.println("\n=== 外洪顶托集镇及村落调查分析成果表处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总导入记录: " + totalProcessed + " 条"); + System.out.println("总跳过重复记录: " + totalDuplicates + " 条"); + System.out.println("总因E列为空跳过记录: " + totalSkipped + " 条"); + } + + private static ProcessResult processCountyEftsData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + int totalDuplicates = 0; + int totalSkipped = 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 = processSxEftsData(sxDir, countyName); + totalProcessed += result.processed; + totalDuplicates += result.duplicates; + totalSkipped += result.skipped; + System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " + + result.duplicates + " 条重复记录," + result.skipped + " 条因E列为空跳过"); + } + + return new ProcessResult(totalProcessed, totalDuplicates, totalSkipped); + } + + private static ProcessResult processSxEftsData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + int duplicateCount = 0; + int skippedCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return new ProcessResult(0, 0, 0); + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findEftsExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表4外洪顶托集镇及村落调查分析成果表.xlsx"); + return new ProcessResult(0, 0, 0); + } + System.out.println("找到外洪顶托集镇及村落调查分析成果表: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + ProcessResult result = readEftsExcelAndImport(excelFile, countyName, watershedCode); + + return result; + } + + private static ProcessResult readEftsExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + int duplicateCount = 0; + int skippedCount = 0; + + // 读取所有数据到内存 + List eftsDataList = readEftsExcelData(excelFile, countyName, watershedCode); + if (eftsDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0, 0); + } + + System.out.println("成功读取 " + eftsDataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertEftsData(eftsDataList); + + return result; + } + + private static List readEftsExcelData(File excelFile, String countyName, String watershedCode) throws Exception { + List dataList = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + String sheetName = sheet.getSheetName(); + + System.out.println("处理工作表: " + sheetName); + + // 提取县代码和乡镇代码 + String countyCode = extractCountyCode(sheet); + String townCode = extractTownCode(sheet); + String townName = extractTownName(sheet); + + System.out.println("县代码: " + countyCode + ", 乡镇代码: " + townCode + ", 乡镇名称: " + townName); + + int startRow = findEftsDataStartRow(sheet); + if (startRow == -1) { + System.out.println("在工作表 " + sheetName + " 中未找到数据开始行"); + continue; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - 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; + } + + // 检查E列是否为空,如果为空则跳过 + Cell eColumnCell = row.getCell(4); // E列是索引4 + if (eColumnCell == null || isCellEmpty(eColumnCell)) { + System.out.println("跳过第 " + (i + 1) + " 行,E列为空"); + continue; + } + + Object[] eftsData = parseEftsRowData(row, countyName, watershedCode, countyCode, townCode, townName); + if (eftsData != null) { + dataList.add(eftsData); + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } catch (Exception e) { + System.err.println("读取Excel文件失败: " + e.getMessage()); + throw e; + } + + return dataList; + } + + private static String extractCountyCode(Sheet sheet) { + // 从第二行提取县代码 (F列) + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(5); // F列是索引5 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; + } + + private static String extractTownCode(Sheet sheet) { + // 从第二行提取乡镇代码 (I列) + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(9); // I列是索引9 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; + } + + private static String extractTownName(Sheet sheet) { + // 从第二行提取乡镇名称 (G列) + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell nameCell = headerRow.getCell(7); // G列是索引7 + if (nameCell != null) { + return getCellStringValue(nameCell); + } + } + return ""; + } + + private static int findEftsDataStartRow(Sheet sheet) { + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); + if (cell != null && !isCellEmpty(cell)) { + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) return i; + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) return i; + } + } + } + } + return -1; + } + + private static Object[] parseEftsRowData(Row row, String countyName, String watershedCode, + String countyCode, String townCode, String townName) { + try { + Object[] data = new Object[20]; // 对应20个参数 + + int index = 0; + + // PCD - 防治对象代码 (C列) + String pcd = getCellStringValue(row.getCell(2)); + if (pcd == null || pcd.trim().isEmpty()) { + return null; // 防治对象编码为空,跳过 + } + data[index++] = pcd; + + // PNM - 防治对象名称 (B列) + data[index++] = getCellStringValue(row.getCell(1)); + + // TM50 - 50年一遇时段 (D列) + data[index++] = getCellStringValue(row.getCell(3)); + + // CRP50 - 50年一遇原临界雨量 (E列) + String crp50Str = getCellStringValue(row.getCell(4)); + if (crp50Str != null && !crp50Str.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(crp50Str.trim()); + } catch (NumberFormatException e) { + System.err.println("50年一遇原临界雨量格式错误: " + crp50Str); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // NCRP50 - 50年一遇修正后临界雨量 (F列) + String ncrp50Str = getCellStringValue(row.getCell(5)); + if (ncrp50Str != null && !ncrp50Str.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(ncrp50Str.trim()); + } catch (NumberFormatException e) { + System.err.println("50年一遇修正后临界雨量格式错误: " + ncrp50Str); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // TM100 - 100年一遇时段 (G列) + data[index++] = getCellStringValue(row.getCell(6)); + + // CRP100 - 100年一遇原临界雨量 (H列) + String crp100Str = getCellStringValue(row.getCell(7)); + if (crp100Str != null && !crp100Str.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(crp100Str.trim()); + } catch (NumberFormatException e) { + System.err.println("100年一遇原临界雨量格式错误: " + crp100Str); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // NCRP100 - 100年一遇修正后临界雨量 (I列) + String ncrp100Str = getCellStringValue(row.getCell(8)); + if (ncrp100Str != null && !ncrp100Str.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(ncrp100Str.trim()); + } catch (NumberFormatException e) { + System.err.println("100年一遇修正后临界雨量格式错误: " + ncrp100Str); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // REMARK - 备注 (J列) + data[index++] = getCellStringValue(row.getCell(9)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = townCode; // ADCD - 乡镇代码 + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER + data[index++] = countyCode; // CADCD - 县级编码 + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_EFTS_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + return data; + + } catch (Exception e) { + System.err.println("解析外洪顶托数据失败: " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + private static ProcessResult batchInsertEftsData(List eftsDataList) { + int importedCount = 0; + int duplicateCount = 0; + int skippedCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement eftsPstmt = conn.prepareStatement(INSERT_EFTS_TOWN_SQL); + PreparedStatement checkEftsDupPstmt = conn.prepareStatement(CHECK_EFTS_DUPLICATE_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + // 使用Set来跟踪已处理的数据,避免内存中重复 + Set processedEftsKeys = new HashSet<>(); + + for (Object[] rowData : eftsDataList) { + try { + // 检查是否重复 + String pcd = (String) rowData[0]; // PCD在索引0 + String tm50 = (String) rowData[2]; // TM50在索引2 + String tm100 = (String) rowData[5]; // TM100在索引5 + + // 检查必要字段是否为空 + if (pcd == null || tm50 == null || tm100 == null) { + System.out.println("跳过数据不完整的记录: PCD=" + pcd); + skippedCount++; + continue; + } + + // 生成唯一键,先检查内存中是否已处理 + String eftsKey = pcd + "|" + tm50 + "|" + tm100; + if (processedEftsKeys.contains(eftsKey)) { + duplicateCount++; + System.out.println("跳过内存中重复记录: " + pcd + " - " + tm50 + "/" + tm100); + continue; + } + + // 检查数据库中是否已存在 + checkEftsDupPstmt.setString(1, pcd); + checkEftsDupPstmt.setString(2, tm50); + checkEftsDupPstmt.setString(3, tm100); + + try (ResultSet rs = checkEftsDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过数据库中重复记录: " + pcd + " - " + tm50 + "/" + tm100); + continue; + } + } + + // 插入数据 + for (int i = 0; i < rowData.length; i++) { + eftsPstmt.setObject(i + 1, rowData[i]); + } + eftsPstmt.addBatch(); + importedCount++; + processedEftsKeys.add(eftsKey); + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + eftsPstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录到外洪顶托表"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 执行剩余的批量插入 + if (importedCount > 0) { + eftsPstmt.executeBatch(); + System.out.println("最终批量插入完成,共 " + importedCount + " 条记录到外洪顶托表"); + } + + conn.commit(); // 提交事务 + System.out.println("外洪顶托表事务提交成功"); + + } catch (Exception e) { + System.err.println("批量插入外洪顶托表数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return new ProcessResult(importedCount, duplicateCount, skippedCount); + } + + // 辅助方法 + 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 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 findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findEftsExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表4外洪顶托集镇及村落调查分析成果表.xlsx") || + name.contains("外洪顶托") || + name.toLowerCase().endsWith(".xlsx")); + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表4外洪顶托集镇及村落调查分析成果表.xlsx")) { + return file; + } + } + for (File file : files) { + if (file.getName().contains("外洪顶托")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static String getCellStringValue(Cell cell) { + if (cell == null) return null; + try { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double num = cell.getNumericCellValue(); + return (num == (long) num) ? String.valueOf((long) num) : String.valueOf(num); + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return cell.getStringCellValue(); + } catch (Exception e) { + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e2) { + return null; + } + } + 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; + } + } + + // 处理结果类 + private static class ProcessResult { + int processed; + int duplicates; + int skipped; + + ProcessResult(int processed, int duplicates, int skipped) { + this.processed = processed; + this.duplicates = duplicates; + this.skipped = skipped; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaGlaInfoDataImporter.java b/src/main/java/org/example/IaGlaInfoDataImporter.java new file mode 100644 index 0000000..c2aef7d --- /dev/null +++ b/src/main/java/org/example/IaGlaInfoDataImporter.java @@ -0,0 +1,548 @@ +// MountainFloodDataImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 表3 + */ +public class IaGlaInfoDataImporter { + + // IA_GLA_INFO表的插入SQL + private static final String INSERT_SQL = + "INSERT INTO SHZH_JCSJ.IA_GLA_INFO (" + + "ADCD, ADNM, NAME, CD, LGTD, LTTD, TYPE, WIDTH, LENGTH, STYPE, " + + "R2, RVNM, RVCD, REMARK, ISENABLE, IMPORTYEAR, INPUTTYPE, AUDID, STATUS, " + + "SIGNER, CADCD, GUID, AUDBATCH, WSCD" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + public static void main(String[] args) { + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; +// args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"}; +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; +// args = new String[]{"F:\\小流域\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\7777-华科-咸宁市8条1027-已通过初检-已统一表头-已入库"}; + + 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; + + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + int processed = processCountyData(countyDir, countyName); + totalProcessed += processed; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + ",导入 " + processed + " 条记录"); + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + } + } + + System.out.println("\n=== 处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总导入记录: " + totalProcessed + " 条"); + } + + private static int processCountyData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyName + " 下未找到小流域目录"); + return 0; + } + System.out.println("找到小流域目录: " + watershedDir.getName()); + + // 查找所有水系目录 + File[] sxDirs = findSxDirectories(watershedDir); + if (sxDirs == null || sxDirs.length == 0) { + System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录"); + return 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()); + int processed = processSxData(sxDir, countyName); + totalProcessed += processed; + System.out.println("水系 " + sxDir.getName() + " 导入 " + processed + " 条记录"); + } + + return totalProcessed; + } + + private static File[] findSxDirectories(File watershedDir) { + File[] subDirs = watershedDir.listFiles(File::isDirectory); + if (subDirs != null) { + List sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static int processSxData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return 0; + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表3沟滩占地情况调查成果表.xlsx"); + return 0; + } + System.out.println("找到Excel文件: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + processedCount = readExcelAndImport(excelFile, countyName, watershedCode); + + return processedCount; + } + + 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 findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表3沟滩占地情况调查成果表.xlsx") || name.toLowerCase().endsWith(".xlsx")); + + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表3沟滩占地情况调查成果表.xlsx")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static String extractWatershedCode(String dirName) { + Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+"); + Matcher matcher = pattern.matcher(dirName); + if(matcher.find()){ + return matcher.group(); + }else{ + System.out.println("小流域编码文件夹有问题: " + dirName); + } + return dirName; + } + + private static int readExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + + // 先读取所有数据到内存 + List dataList = readExcelData(excelFile, countyName, watershedCode); + if (dataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return 0; + } + + System.out.println("成功读取 " + dataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + importedCount = batchInsertData(dataList); + + return importedCount; + } + + private static List readExcelData(File excelFile, String countyName, String watershedCode) throws Exception { + List dataList = new ArrayList<>(); + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + 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); + // 提取县代码(从第二行) + String countyCode = extractCountyCode(sheet); + String adcd = extractAdcd(sheet); + String adnm = extractAdnm(sheet); + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("在工作表 " + sheetName + " 中未找到数据开始行"); + return dataList; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - 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[] rowData = parseRowData(row, countyName, watershedCode, countyCode,adcd,adnm); + if (rowData != null) { + dataList.add(rowData); + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } + return dataList; + } + + private static String extractCountyCode(Sheet sheet) { + // 从第二行提取县代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(7); // H列 - 县代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdcd(Sheet sheet) { + // 从第二行提取乡镇代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(12); // H列 - 乡镇代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdnm(Sheet sheet) { + // 从第二行提取乡镇代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(10); // H列 - 乡镇代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static int findDataStartRow(Sheet sheet) { + // 查找数据开始的行(序号列开始有数据的行) + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); // A列 + if (cell != null && !isCellEmpty(cell)) { + // 检查是否是数字序号 + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) { + return i; + } + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) { + return i; + } + } + } + } + } + return -1; + } + + private static Object[] parseRowData(Row row, String countyName, String watershedCode, String countyCode,String adcd ,String adnm) { + try { + + // 检查编码(C列)是否为空 + String name = getCellStringValue(row.getCell(2)); + if (name == null || name.trim().isEmpty()) { + System.out.println("第 " + (row.getRowNum() + 1) + " 行编码为空,跳过该行"); + return null; + } + + Object[] data = new Object[24]; // 对应24个参数 + + int index = 0; + + // ADCD - 行政区划代码 + data[index++] = adcd; + + // ADNM - 行政区划名称 + data[index++] = adnm; + + // NAME - 名称 (B列) + data[index++] = name; + + // CD - 编号 (C列) + data[index++] = getCellStringValue(row.getCell(2)); + + // LGTD - 经度 (D列) + String lngStr = getCellStringValue(row.getCell(3)); + data[index++] = parseDecimal(lngStr); + + // LTTD - 纬度 (E列) + String latStr = getCellStringValue(row.getCell(4)); + data[index++] = parseDecimal(latStr); + + // TYPE - 类型 (F列) + data[index++] = getCellStringValue(row.getCell(5)); + + // WIDTH - 沟宽/m (G列) + String widthStr = getCellStringValue(row.getCell(6)); + data[index++] = parseDecimal(widthStr); + + // LENGTH - 沟深/m (H列) + String depthStr = getCellStringValue(row.getCell(7)); + data[index++] = parseDecimal(depthStr); + + // STYPE - 断面形态 (I列) + data[index++] = getCellStringValue(row.getCell(8)); + + // R2 - 阻水面积比/% (J列) + String r2Str = getCellStringValue(row.getCell(9)); + data[index++] = parseDecimal(r2Str); + + // RVNM - 河流名称 (K列) + data[index++] = getCellStringValue(row.getCell(10)); + + // RVCD - 河流代码 (L列) + data[index++] = getCellStringValue(row.getCell(11)); + + // REMARK - 备注 (M列) + data[index++] = getCellStringValue(row.getCell(12)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER + data[index++] = countyCode; // CADCD + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + + private static int batchInsertData(List dataList) { + int importedCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + for (Object[] rowData : dataList) { + try { + for (int i = 0; i < rowData.length; i++) { + pstmt.setObject(i + 1, rowData[i]); + } + pstmt.addBatch(); + importedCount++; + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + pstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + // 继续处理下一条数据 + } + } + + // 执行剩余的批量插入 + if (importedCount % 10 != 0) { + pstmt.executeBatch(); + } + + conn.commit(); // 提交事务 + System.out.println("成功导入 " + importedCount + " 条记录到数据库"); + + } catch (Exception e) { + System.err.println("批量插入数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return importedCount; + } + + private static String getCellStringValue(Cell cell) { + if (cell == null) { + return null; + } + + try { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double num = cell.getNumericCellValue(); + if (num == (long) num) { + return String.valueOf((long) num); + } else { + return String.valueOf(num); + } + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return cell.getStringCellValue(); + } catch (Exception e) { + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e2) { + return cell.getCellFormula(); + } + } + default: + return null; + } + } catch (Exception e) { + System.err.println("读取单元格值时出错: " + e.getMessage()); + return null; + } + } + + private static Double parseDecimal(String value) { + if (value == null || value.trim().isEmpty()) { + return null; + } + try { + return Double.parseDouble(value.trim()); + } catch (NumberFormatException 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; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaHdpPointDataImporter.java b/src/main/java/org/example/IaHdpPointDataImporter.java new file mode 100644 index 0000000..7057688 --- /dev/null +++ b/src/main/java/org/example/IaHdpPointDataImporter.java @@ -0,0 +1,613 @@ +// MountainFloodDataImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * 表5,6,7 + */ +public class IaHdpPointDataImporter { + + public final static String five = "表5 重点防治对象危险地建房详查成果表.xlsx"; + public final static String three = "3"; + + public final static String six = "表6 重点防治对象房屋结构问题详查成果表.xlsx"; + public final static String two = "2"; + + public final static String seven = "表7 重点防治对象弱势人群详查成果表.xlsx"; + + // IA_SHZH_HDP_POINT表的插入SQL + private static final String INSERT_SQL = + "INSERT INTO SHZH_JCSJ.IA_SHZH_HDP_POINT (" + + "ADCD, PCD, LGTD, LTTD, GC, PCOUNT, NAME, PHONE, BBZRRNM, BBZRRPHONE, " + + "PPOINT, REMARK, ISENABLE, IMPORTYEAR, INPUTTYPE, AUDID, STATUS, SIGNER, " + + "CADCD, GUID, AUDBATCH, WSCD, TYPE, PNM" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + public static void main(String[] args) { + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-已入库"}; +// args = new String[]{"F:\\2222-华科-黄石局-14条小流域(10.20)-已通过初检-已统一表头-已入库"}; +// args = new String[]{"F:\\3333-华科-地大9条-20251021-已通过初检-已统一表头-已入库"}; +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\8888-长科院-孝昌县8条1028-已通过初检-已统一表头-待入库"}; + + 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; + + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + int processed = processCountyData(countyDir, countyName); + totalProcessed += processed; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + ",导入 " + processed + " 条记录"); + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + } + } + + System.out.println("\n=== 处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总导入记录: " + totalProcessed + " 条"); + } + + private static int processCountyData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyName + " 下未找到小流域目录"); + return 0; + } + System.out.println("找到小流域目录: " + watershedDir.getName()); + + // 查找所有水系目录 + File[] sxDirs = findSxDirectories(watershedDir); + if (sxDirs == null || sxDirs.length == 0) { + System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录"); + return 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()); + int processed = processSxData(sxDir, countyName); + totalProcessed += processed; + System.out.println("水系 " + sxDir.getName() + " 导入 " + processed + " 条记录"); + } + + return totalProcessed; + } + + private static File[] findSxDirectories(File watershedDir) { + File[] subDirs = watershedDir.listFiles(File::isDirectory); + if (subDirs != null) { + List sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static int processSxData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return 0; + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到" + six); + return 0; + } + System.out.println("找到Excel文件: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + processedCount = readExcelAndImport(excelFile, countyName, watershedCode); + + return processedCount; + } + + 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 findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals(six) || name.toLowerCase().endsWith(".xlsx")); + + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals(six)) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static int readExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + + // 先读取所有数据到内存 + List dataList = readExcelData(excelFile, countyName, watershedCode); + if (dataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return 0; + } + + System.out.println("成功读取 " + dataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + importedCount = batchInsertData(dataList); + + return importedCount; + } + + private static List readExcelData(File excelFile, String countyName, String watershedCode) throws Exception { + List dataList = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + String sheetName = sheet.getSheetName(); + + if ("填表说明".equals(sheetName)) { + System.out.println("跳过填表说明工作表"); + continue; + } + + System.out.println("处理工作表: " + sheetName); + + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("在工作表 " + sheetName + " 中未找到数据开始行"); + continue; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - startRow + 1) + " 行"); + + for (int i = startRow; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row == null) continue; + + Cell serialCell = row.getCell(8); + if (serialCell == null || isCellEmpty(serialCell)) { + continue; + } + + Object[] rowData = parseRowData(row,countyName, watershedCode); + if (rowData != null) { + dataList.add(rowData); + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } + + return dataList; + } + + private static int findDataStartRow(Sheet sheet) { + // 查找数据开始的行 + for (int i = 2; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(8); + if (cell != null && !isCellEmpty(cell)) { + return i; +// // 检查是否是数字序号 +// if (cell.getCellType() == CellType.NUMERIC) { +// double value = cell.getNumericCellValue(); +// if (value >= 1 && value <= 1000) { +// return i; +// } +// } else if (cell.getCellType() == CellType.STRING) { +// String value = cell.getStringCellValue().trim(); +// if (value.matches("\\d+")) { +// return i; +// } +// } + } + } + } + return -1; + } + + private static Object[] parseRowData1(Row row, String countyName, String watershedCode) { + try { + // 检查姓名(B列)是否为空 + String name = getCellStringValue(row.getCell(1)); + if (name == null || name.trim().isEmpty()) { + System.out.println("第 " + (row.getRowNum() + 1) + " 行姓名为空,跳过该行"); + return null; + } + + Object[] data = new Object[24]; // 对应24个参数 + + int index = 0; + + // ADCD - 行政区划代码 (使用防治对象代码的前6位作为县级代码) + String preventionCode = getCellStringValue(row.getCell(5)); // I列 - 防治对象代码 + String countyCode = (preventionCode != null && preventionCode.length() >= 6) ? + preventionCode.substring(0, 9) + "000000" : ""; + data[index++] = countyCode; + + // PCD - 防治对象代码 (I列) + data[index++] = preventionCode; + + // LGTD - 住房经度(°) (E列) + String lngStr = getCellStringValue(row.getCell(6)); + data[index++] = parseDecimal(lngStr); + + // LTTD - 住房纬度(°) (F列) + String latStr = getCellStringValue(row.getCell(7)); + data[index++] = parseDecimal(latStr); + + // GC - 宅基地高程(m) (G列) + String elevationStr = getCellStringValue(row.getCell(8)); + data[index++] = parseDecimal(elevationStr); + + // PCOUNT - 常住人口 (D列) + String populationStr = getCellStringValue(row.getCell(3)); + if (populationStr != null && !populationStr.trim().isEmpty()) { + try { + data[index++] = Integer.parseInt(populationStr.trim()); + } catch (NumberFormatException e) { + data[index++] = null; + } + } else { + data[index++] = null; + } + + // NAME - 姓名 (B列) + data[index++] = name; + + // PHONE - 联系方式 (C列) + data[index++] = getCellStringValue(row.getCell(2)); + + // BBZRRNM - 包保责任人姓名 (暂无数据,设为null) + data[index++] = getCellStringValue(row.getCell(9)); + + // BBZRRPHONE - 包保责任人电话 (暂无数据,设为null) + data[index++] = getCellStringValue(row.getCell(10)); + + // PPOINT - 安置点 (暂无数据,设为null) + data[index++] = null; + + // REMARK - 备注 (J列) + data[index++] = getCellStringValue(row.getCell(11)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER +// data[index++] = countyCode; // CADCD - 县级编码(前6位) + data[index++] = null; + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + // TYPE - 重点关注对象类型 (3:危险地建房) + data[index++] = "1"; + + // PNM - 防治对象名称 (H列) + data[index++] = getCellStringValue(row.getCell(4)); + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + + private static Object[] parseRowData(Row row,String countyName, String watershedCode) { + try { + // 检查姓名(B列)是否为空 + String name = getCellStringValue(row.getCell(1)); + if (name == null || name.trim().isEmpty() || "无".equals(name)) { + System.out.println("第 " + (row.getRowNum() + 1) + " 行姓名为空,跳过该行"); + return null; + } + + Object[] data = new Object[24]; // 对应24个参数 + + int index = 0; + + // ADCD - 行政区划代码 (使用防治对象代码的前6位作为县级代码) + String preventionCode = getCellStringValue(row.getCell(8)); // I列 - 防治对象代码 + String countyCode = (preventionCode != null && preventionCode.length() >= 6) ? + preventionCode.substring(0, 9) + "000000" : ""; + data[index++] = countyCode; + + // PCD - 防治对象代码 (I列) + data[index++] = preventionCode; + + // LGTD - 住房经度(°) (E列) + String lngStr = getCellStringValue(row.getCell(4)); + data[index++] = parseDecimal(lngStr); + + // LTTD - 住房纬度(°) (F列) + String latStr = getCellStringValue(row.getCell(5)); + data[index++] = parseDecimal(latStr); + + // GC - 宅基地高程(m) (G列) + String elevationStr = getCellStringValue(row.getCell(6)); + data[index++] = parseDecimal(elevationStr); + + // PCOUNT - 常住人口 (D列) + String populationStr = getCellStringValue(row.getCell(3)); + if (populationStr != null && !populationStr.trim().isEmpty()) { + try { + data[index++] = Integer.parseInt(populationStr.trim()); + } catch (NumberFormatException e) { + data[index++] = null; + } + } else { + data[index++] = null; + } + + // NAME - 姓名 (B列) + data[index++] = name; + + // PHONE - 联系方式 (C列) + data[index++] = getCellStringValue(row.getCell(2)); + + // BBZRRNM - 包保责任人姓名 (暂无数据,设为null) + data[index++] = null; + + // BBZRRPHONE - 包保责任人电话 (暂无数据,设为null) + data[index++] = null; + + // PPOINT - 安置点 (暂无数据,设为null) + data[index++] = null; + + // REMARK - 备注 (J列) + data[index++] = getCellStringValue(row.getCell(9)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER + data[index++] = null; + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + // TYPE - 重点关注对象类型 (3:危险地建房) + data[index++] = two; + + // PNM - 防治对象名称 (H列) + data[index++] = getCellStringValue(row.getCell(7)); + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + + private static int batchInsertData(List dataList) { + int importedCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + for (Object[] rowData : dataList) { + try { + for (int i = 0; i < rowData.length; i++) { + pstmt.setObject(i + 1, rowData[i]); + } + pstmt.addBatch(); + importedCount++; + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + pstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + // 继续处理下一条数据 + } + } + + // 执行剩余的批量插入 + if (importedCount % 10 != 0) { + pstmt.executeBatch(); + } + + conn.commit(); // 提交事务 + System.out.println("成功导入 " + importedCount + " 条记录到数据库"); + + } catch (Exception e) { + System.err.println("批量插入数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return importedCount; + } + + private static String getCellStringValue(Cell cell) { + if (cell == null) { + return null; + } + + try { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double num = cell.getNumericCellValue(); + if (num == (long) num) { + return String.valueOf((long) num); + } else { + return String.valueOf(num); + } + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return cell.getStringCellValue(); + } catch (Exception e) { + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e2) { + return cell.getCellFormula(); + } + } + default: + return null; + } + } catch (Exception e) { + System.err.println("读取单元格值时出错: " + e.getMessage()); + return null; + } + } + + private static Double parseDecimal(String value) { + if (value == null || value.trim().isEmpty()) { + return null; + } + try { + return Double.parseDouble(value.trim()); + } catch (NumberFormatException 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; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaRbadInfoDataImporter.java b/src/main/java/org/example/IaRbadInfoDataImporter.java new file mode 100644 index 0000000..f3d4798 --- /dev/null +++ b/src/main/java/org/example/IaRbadInfoDataImporter.java @@ -0,0 +1,546 @@ +// MountainFloodDataImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 表2 + */ +public class IaRbadInfoDataImporter { + + // IA_RBAD_INFO表的插入SQL + private static final String INSERT_SQL = + "INSERT INTO SHZH_JCSJ.IA_RBAD_INFO (" + + "ADCD, NAME, LGTD, LTTD, TYPE, WIDTH, LENGTH, STYPE, R1, V, " + + "RVCD, YSNM, YSCD, KJNM, KJCD, REMARK, ISENABLE, IMPORTYEAR, CD, INPUTTYPE, " + + "AUDID, STATUS, SIGNER, CADCD, GUID, AUDBATCH, WSCD" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + public static void main(String[] args) { + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; +// args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"}; +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; +// args = new String[]{"F:\\3333-华科-地大9条-20251021-已通过初检-已统一表头-待入库"}; +// args = new String[]{"F:\\小流域\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\8888-长科院-孝昌县8条1028-已通过初检-已统一表头-待入库"}; + + 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; + + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + int processed = processCountyData(countyDir, countyName); + totalProcessed += processed; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + ",导入 " + processed + " 条记录"); + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + } + } + + System.out.println("\n=== 处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总导入记录: " + totalProcessed + " 条"); + } + + private static int processCountyData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyName + " 下未找到小流域目录"); + return 0; + } + System.out.println("找到小流域目录: " + watershedDir.getName()); + + // 查找所有水系目录 + File[] sxDirs = findSxDirectories(watershedDir); + if (sxDirs == null || sxDirs.length == 0) { + System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录"); + return 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()); + int processed = processSxData(sxDir, countyName); + totalProcessed += processed; + System.out.println("水系 " + sxDir.getName() + " 导入 " + processed + " 条记录"); + } + + return totalProcessed; + } + + private static File[] findSxDirectories(File watershedDir) { + File[] subDirs = watershedDir.listFiles(File::isDirectory); + if (subDirs != null) { + List sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static int processSxData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return 0; + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表2跨沟道路、桥涵、塘(堰)坝调查成果表.xlsx"); + return 0; + } + System.out.println("找到Excel文件: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + processedCount = readExcelAndImport(excelFile, countyName, watershedCode); + + return processedCount; + } + + 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 findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表2跨沟道路、桥涵、塘(堰)坝调查成果表.xlsx") || name.toLowerCase().endsWith(".xlsx")); + + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表2跨沟道路、桥涵、塘(堰)坝调查成果表.xlsx")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static int readExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + + // 先读取所有数据到内存 + List dataList = readExcelData(excelFile, countyName, watershedCode); + if (dataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return 0; + } + + System.out.println("成功读取 " + dataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + importedCount = batchInsertData(dataList); + + return importedCount; + } + + private static List readExcelData(File excelFile, String countyName, String watershedCode) throws Exception { + List dataList = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + 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); + + // 提取县代码(从第二行) + String countyCode = extractCountyCode(sheet); + String adcd = extractAdcd(sheet); + String adnm = extractAdnm(sheet); + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("在工作表 " + sheetName + " 中未找到数据开始行"); + continue; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - 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[] rowData = parseRowData(row, countyName, watershedCode, countyCode,adcd,adnm); + if (rowData != null) { + dataList.add(rowData); + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } + + return dataList; + } + + private static String extractCountyCode(Sheet sheet) { + // 从第二行提取县代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(7); // H列 - 县代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdcd(Sheet sheet) { + // 从第二行提取乡镇代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(15); // H列 - 乡镇代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdnm(Sheet sheet) { + // 从第二行提取乡镇名称 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(10); // H列 - 乡镇名称 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static int findDataStartRow(Sheet sheet) { + // 查找数据开始的行(序号列开始有数据的行) + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); // A列 + if (cell != null && !isCellEmpty(cell)) { + // 检查是否是数字序号 + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) { + return i; + } + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) { + return i; + } + } + } + } + } + return -1; + } + + private static Object[] parseRowData(Row row, String countyName, String watershedCode, String countyCode,String adcd ,String adnm) { + try { + // 检查名称(B列)是否为空 + String name = getCellStringValue(row.getCell(1)); + if (name == null || name.trim().isEmpty()) { + System.out.println("第 " + (row.getRowNum() + 1) + " 行名称为空,跳过该行"); + return null; + } + + Object[] data = new Object[27]; // 对应27个参数 + + int index = 0; + + // ADCD - 行政区划代码 + data[index++] = adcd; + + // NAME - 名称 (B列) + data[index++] = name; + + // LGTD - 经度 (D列) + String lngStr = getCellStringValue(row.getCell(3)); + data[index++] = parseDecimal(lngStr); + + // LTTD - 纬度 (E列) + String latStr = getCellStringValue(row.getCell(4)); + data[index++] = parseDecimal(latStr); + + // TYPE - 类型 (F列) + data[index++] = getCellStringValue(row.getCell(5)); + + // WIDTH - 沟宽/m (G列) + String widthStr = getCellStringValue(row.getCell(6)); + data[index++] = parseDecimal(widthStr); + + // LENGTH - 沟深/m (H列) + String depthStr = getCellStringValue(row.getCell(7)); + data[index++] = parseDecimal(depthStr); + + // STYPE - 断面形态 (I列) + data[index++] = getCellStringValue(row.getCell(8)); + + // R1 - 阻水面积比R1/% (J列) + data[index++] = getCellStringValue(row.getCell(9)); + + // V - 阻水库容V/万m3 (K列) + data[index++] = getCellStringValue(row.getCell(10)); + + // RVCD - 河流代码 (L列) + data[index++] = getCellStringValue(row.getCell(11)); + + // YSNM - 壅水影响对象名称 (M列) + data[index++] = getCellStringValue(row.getCell(12)); + + // YSCD - 壅水影响对象编码 (N列) + data[index++] = getCellStringValue(row.getCell(13)); + + // KJNM - 溃决影响对象名称 (O列) + data[index++] = getCellStringValue(row.getCell(14)); + + // KJCD - 溃决影响对象编码 (P列) + data[index++] = getCellStringValue(row.getCell(15)); + + // REMARK - 备注 (Q列) + data[index++] = getCellStringValue(row.getCell(16)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = getCellStringValue(row.getCell(2)); // CD - 编码 (C列) + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER + data[index++] = countyCode; // CADCD + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + + private static int batchInsertData(List dataList) { + int importedCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + for (Object[] rowData : dataList) { + try { + for (int i = 0; i < rowData.length; i++) { + pstmt.setObject(i + 1, rowData[i]); + } + pstmt.addBatch(); + importedCount++; + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + pstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + // 继续处理下一条数据 + } + } + + // 执行剩余的批量插入 + if (importedCount % 10 != 0) { + pstmt.executeBatch(); + } + + conn.commit(); // 提交事务 + System.out.println("成功导入 " + importedCount + " 条记录到数据库"); + + } catch (Exception e) { + System.err.println("批量插入数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return importedCount; + } + + private static String getCellStringValue(Cell cell) { + if (cell == null) { + return null; + } + + try { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double num = cell.getNumericCellValue(); + if (num == (long) num) { + return String.valueOf((long) num); + } else { + return String.valueOf(num); + } + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return cell.getStringCellValue(); + } catch (Exception e) { + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e2) { + return cell.getCellFormula(); + } + } + default: + return null; + } + } catch (Exception e) { + System.err.println("读取单元格值时出错: " + e.getMessage()); + return null; + } + } + + private static Double parseDecimal(String value) { + if (value == null || value.trim().isEmpty()) { + return null; + } + try { + return Double.parseDouble(value.trim()); + } catch (NumberFormatException 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; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaShzhHdpDataImporter.java b/src/main/java/org/example/IaShzhHdpDataImporter.java new file mode 100644 index 0000000..33ecb00 --- /dev/null +++ b/src/main/java/org/example/IaShzhHdpDataImporter.java @@ -0,0 +1,726 @@ +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 表1 + */ +public class IaShzhHdpDataImporter { + + // 防灾对象表插入SQL + private static final String INSERT_HDP_SQL = + "INSERT INTO SHZH_JCSJ.IA_SHZH_HDP(ADCD, ADNM, TYPE, PCOUNT, RVNM, RVCD, BRNAME, BRCD, " + + "DAMNAME, DAMCD, DZRVNM, DZRVCD, ISSZ, ISJW, ISDW, ISGT, ISYS, ISDT, ISGD, ISML, " + + "REMARK, ISENABLE, IMPORTYEAR, ISKJ, PRENAME, PRECODE, ISLHHP, ISNSL, SIGNER, CADCD, " + + "GUID, AUDBATCH, INPUTTYPE, AUDID, STATUS, WSCD) \n" + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)"; + + // 防灾对象河流信息表插入SQL + private static final String INSERT_RV_INFO_SQL = + "INSERT INTO SHZH_JCSJ.IA_RV_INFO (" + + "PRECODE, PRENAME, RVCD, RVNM, WSCD" + + ") VALUES (?, ?, ?, ?, ?)"; + + // 检查防灾对象重复的SQL(基于县编码、名称、编码、类型、人口) + private static final String CHECK_HDP_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_SHZH_HDP " + + "WHERE ADCD = ? AND PRENAME = ? AND PRECODE = ? AND TYPE = ? AND " + + "(PCOUNT = ? OR (PCOUNT IS NULL AND ? IS NULL))"; + + // 检查河流信息重复的SQL(基于precode, prename, rvcd, rvnm, wscd) + private static final String CHECK_RV_INFO_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_RV_INFO " + + "WHERE PRECODE = ? AND PRENAME = ? AND RVCD = ? AND RVNM = ? AND WSCD = ?"; + + public static void main(String[] args) { + // 先测试数据库连接 + if (!testDatabaseConnection()) { + System.err.println("数据库连接测试失败,程序退出"); + return; + } + + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; +// args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"}; +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; +// args = new String[]{"F:\\3333-华科-地大9条-20251021-已通过初检-已统一表头-待入库"}; +// args = new String[]{"F:\\小流域\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库\\5555-长江科学院20条10.23-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\8888-长科院-孝昌县8条1028-已通过初检-已统一表头-待入库"}; + + 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 boolean testDatabaseConnection() { + try { + Connection conn = DatabaseUtil.getConnection(); + if (conn != null && !conn.isClosed()) { + System.out.println("✓ 数据库连接测试成功"); + conn.close(); + return true; + } + } catch (Exception e) { + System.err.println("✗ 数据库连接测试失败: " + e.getMessage()); + } + return false; + } + + 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 totalRvDuplicates = 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; + totalRvDuplicates += result.rvDuplicates; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + + ",导入 " + result.processed + " 条记录,跳过 " + result.duplicates + + " 条重复记录,河流信息表跳过 " + result.rvDuplicates + " 条重复记录"); + } 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("河流信息表跳过重复记录: " + totalRvDuplicates + " 条"); + } + + private static ProcessResult processCountyData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + int totalDuplicates = 0; + int totalRvDuplicates = 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; + totalRvDuplicates += result.rvDuplicates; + System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " + + result.duplicates + " 条重复记录,河流信息表跳过 " + result.rvDuplicates + " 条重复记录"); + } + + return new ProcessResult(totalProcessed, totalDuplicates, totalRvDuplicates); + } + + private static ProcessResult processSxData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + int duplicateCount = 0; + int rvDuplicateCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return new ProcessResult(0, 0, 0); + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表1山洪灾害防治对象名录.xlsx"); + return new ProcessResult(0, 0, 0); + } + System.out.println("找到Excel文件: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + ProcessResult result = readExcelAndImport(excelFile, countyName, watershedCode); + + return result; + } + + private static ProcessResult readExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + int duplicateCount = 0; + int rvDuplicateCount = 0; + + // 先读取所有数据到内存 + List hdpDataList = new ArrayList<>(); + List rvInfoDataList = new ArrayList<>(); + + readExcelData(excelFile, countyName, watershedCode, hdpDataList, rvInfoDataList); + + if (hdpDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0, 0); + } + + System.out.println("成功读取 " + hdpDataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertData(hdpDataList, rvInfoDataList); + + return result; + } + + private static String extractCountyCode(Sheet sheet) { + // 从第二行提取县代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(9); // H列 - 县代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdcd(Sheet sheet) { + // 从第二行提取乡镇代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(22); // H列 - 乡镇代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdnm(Sheet sheet) { + // 从第二行提取乡镇名称 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(14); // H列 - 乡镇名称 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static void readExcelData(File excelFile, String countyName, String watershedCode, + List hdpDataList, List rvInfoDataList) throws Exception { + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + + String sheetName = sheet.getSheetName().replaceAll("[\\u4e00-\\u9fa5]+$", ""); + + // 跳过填表说明等非数据工作表 + if (sheetName.contains("填表说明") || sheetName.contains("说明")) { + continue; + } + + System.out.println("处理工作表: " + sheetName); + + String countyCode = extractCountyCode(sheet); + String adcd = extractAdcd(sheet); + String adnm = extractAdnm(sheet); + + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("未找到数据开始行"); + return; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - 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[] hdpData = parseRowData(row, countyName, watershedCode, countyCode, adcd, adnm); + if (hdpData != null) { + hdpDataList.add(hdpData); + + // 同时生成河流信息表数据 + Object[] rvInfoData = parseRvInfoData(hdpData); + if (rvInfoData != null) { + rvInfoDataList.add(rvInfoData); + } + + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } + } + + private static ProcessResult batchInsertData(List hdpDataList, List rvInfoDataList) { + int importedCount = 0; + int duplicateCount = 0; + int rvDuplicateCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement hdpPstmt = conn.prepareStatement(INSERT_HDP_SQL); + PreparedStatement rvInfoPstmt = conn.prepareStatement(INSERT_RV_INFO_SQL); + PreparedStatement checkHdpDupPstmt = conn.prepareStatement(CHECK_HDP_DUPLICATE_SQL); + PreparedStatement checkRvInfoDupPstmt = conn.prepareStatement(CHECK_RV_INFO_DUPLICATE_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + // 使用Set来跟踪已处理的数据,避免内存中重复 + Set processedHdpKeys = new HashSet<>(); + Set processedRvInfoKeys = new HashSet<>(); + + // 处理防灾对象表数据 + for (Object[] rowData : hdpDataList) { + try { + // 检查是否重复 + String adcd = (String) rowData[0]; + String prename = (String) rowData[24]; // PRENAME在索引24 + String precode = (String) rowData[25]; // PRECODE在索引25 + String type = (String) rowData[2]; // TYPE在索引2 + Integer pcount = (Integer) rowData[3]; // PCOUNT在索引3 + + // 检查必要字段是否为空 + if (adcd == null || prename == null || precode == null || type == null) { + System.out.println("跳过数据不完整的记录: " + prename + " (" + precode + ")"); + continue; + } + + // 生成唯一键,先检查内存中是否已处理 + String hdpKey = adcd + "|" + prename + "|" + precode + "|" + type + "|" + pcount; + if (processedHdpKeys.contains(hdpKey)) { + duplicateCount++; + System.out.println("跳过内存中重复记录: " + prename + " (" + precode + ")"); + continue; + } + + // 检查数据库中是否已存在 + checkHdpDupPstmt.setString(1, adcd); + checkHdpDupPstmt.setString(2, prename); + checkHdpDupPstmt.setString(3, precode); + checkHdpDupPstmt.setString(4, type); + if (pcount != null) { + checkHdpDupPstmt.setInt(5, pcount); + checkHdpDupPstmt.setInt(6, pcount); + } else { + checkHdpDupPstmt.setNull(5, java.sql.Types.INTEGER); + checkHdpDupPstmt.setNull(6, java.sql.Types.INTEGER); + } + + try (ResultSet rs = checkHdpDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过数据库中重复记录: " + prename + " (" + precode + ")"); + continue; + } + } + + // 插入数据 + for (int i = 0; i < rowData.length; i++) { + hdpPstmt.setObject(i + 1, rowData[i]); + } + hdpPstmt.addBatch(); + importedCount++; + processedHdpKeys.add(hdpKey); // 记录已处理的键 + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + hdpPstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录到防灾对象表"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + e.printStackTrace(); + // 继续处理下一条数据 + } + } + + // 执行剩余的批量插入 + if (importedCount > 0 && importedCount % 10 != 0) { + hdpPstmt.executeBatch(); + System.out.println("最终批量插入完成,共 " + importedCount + " 条记录到防灾对象表"); + } + + // 处理河流信息表数据 + int rvImportedCount = 0; + for (Object[] rvData : rvInfoDataList) { + try { + // 检查河流信息是否重复 + String precode = (String) rvData[0]; + String prename = (String) rvData[1]; + String rvcd = (String) rvData[2]; + String rvnm = (String) rvData[3]; + String wscd = (String) rvData[4]; + + // 检查必要字段是否为空 + if (precode == null || prename == null || rvcd == null || rvnm == null || wscd == null) { + System.out.println("跳过河流信息数据不完整的记录: " + prename + " (" + precode + ")"); + continue; + } + + // 生成唯一键,先检查内存中是否已处理 + String rvInfoKey = precode + "|" + prename + "|" + rvcd + "|" + rvnm + "|" + wscd; + if (processedRvInfoKeys.contains(rvInfoKey)) { + rvDuplicateCount++; + System.out.println("跳过内存中河流信息重复记录: " + prename + " (" + precode + ") - " + rvnm); + continue; + } + + // 检查数据库中是否已存在 + checkRvInfoDupPstmt.setString(1, precode); + checkRvInfoDupPstmt.setString(2, prename); + checkRvInfoDupPstmt.setString(3, rvcd); + checkRvInfoDupPstmt.setString(4, rvnm); + checkRvInfoDupPstmt.setString(5, wscd); + + try (ResultSet rs = checkRvInfoDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + rvDuplicateCount++; + System.out.println("跳过数据库中河流信息重复记录: " + prename + " (" + precode + ") - " + rvnm); + continue; + } + } + + for (int i = 0; i < rvData.length; i++) { + rvInfoPstmt.setObject(i + 1, rvData[i]); + } + rvInfoPstmt.addBatch(); + rvImportedCount++; + processedRvInfoKeys.add(rvInfoKey); // 记录已处理的键 + + if (rvImportedCount % 10 == 0) { + rvInfoPstmt.executeBatch(); + System.out.println("已批量插入 " + rvImportedCount + " 条记录到河流信息表"); + } + } catch (Exception e) { + System.err.println("河流信息表数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 执行剩余的河流信息批量插入 + if (rvImportedCount > 0 && rvImportedCount % 10 != 0) { + rvInfoPstmt.executeBatch(); + System.out.println("最终批量插入完成,共 " + rvImportedCount + " 条记录到河流信息表"); + } + + conn.commit(); // 提交事务 + System.out.println("事务提交成功"); + + } catch (Exception e) { + System.err.println("批量插入数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return new ProcessResult(importedCount, duplicateCount, rvDuplicateCount); + } + + // 修改ProcessResult类,添加河流信息重复统计 + private static class ProcessResult { + int processed; + int duplicates; + int rvDuplicates; + + ProcessResult(int processed, int duplicates, int rvDuplicates) { + this.processed = processed; + this.duplicates = duplicates; + this.rvDuplicates = rvDuplicates; + } + } + + // 解析河流信息表数据 + private static Object[] parseRvInfoData(Object[] hdpData) { + try { + Object[] rvData = new Object[5]; + + // PRECODE + rvData[0] = hdpData[25]; // PRECODE在索引25 + // PRENAME + rvData[1] = hdpData[24]; // PRENAME在索引24 + // RVCD - 河流代码 + rvData[2] = hdpData[5]; // RVCD在索引5 + // RVNM - 河流名称 + rvData[3] = hdpData[4]; // RVNM在索引4 + // WSCD - 流域编码 + rvData[4] = hdpData[35]; // WSCD在索引35 + + return rvData; + } catch (Exception e) { + System.err.println("解析河流信息数据失败: " + e.getMessage()); + return null; + } + } + + // 其他辅助方法保持不变... + 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + // 包含"水系"或者是类似HBWF开头的文件夹都认为是水系文件夹 + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static File findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表1山洪灾害防治对象名录.xlsx") || name.toLowerCase().endsWith(".xlsx")); + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表1山洪灾害防治对象名录.xlsx")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + + private static int findDataStartRow(Sheet sheet) { + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); + if (cell != null && !isCellEmpty(cell)) { + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) return i; + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) return i; + } + } + } + } + return -1; + } + + 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; + } + } + + // parseRowData方法保持不变... + private static Object[] parseRowData(Row row, String countyName, String watershedCode, String countyCode,String adcd ,String adnm) { + try { + Object[] data = new Object[36]; // 对应36个参数 + + int index = 0; + + // ADCD - 行政区划代码 (C列) + String objectCode = getCellStringValue(row.getCell(2)); + data[index++] = adcd; + + // ADNM - 行政区划名称 (B列 + 县市名称) + String objectName = getCellStringValue(row.getCell(1)); + data[index++] = adnm; + + // TYPE - 类型 (D列) + data[index++] = getCellStringValue(row.getCell(3)); + + // PCOUNT - 人口 (E列) + String populationStr = getCellStringValue(row.getCell(4)); + if (populationStr != null && !populationStr.trim().isEmpty()) { + try { + data[index++] = Integer.parseInt(populationStr.trim()); + } catch (NumberFormatException e) { + data[index++] = null; + } + } else { + data[index++] = null; + } + + // RVNM - 河流名称 (F列) + data[index++] = getCellStringValue(row.getCell(5)); + + // RVCD - 河流代码 (G列) + data[index++] = getCellStringValue(row.getCell(6)); + + // BRNAME - 桥梁名称 (H列) + data[index++] = getCellStringValue(row.getCell(7)); + + // BRCD - 桥梁编码 (I列) + data[index++] = getCellStringValue(row.getCell(8)); + + // DAMNAME - 塘坝名称 (J列) + data[index++] = getCellStringValue(row.getCell(9)); + + // DAMCD - 塘坝编码 (K列) + data[index++] = getCellStringValue(row.getCell(10)); + + // DZRVNM - 多支河流名称 (L列) + data[index++] = getCellStringValue(row.getCell(11)); + + // DZRVCD - 多支河流代码 (M列) + data[index++] = getCellStringValue(row.getCell(12)); + + // 风险隐患要素 (N~S列) + data[index++] = getCellStringValue(row.getCell(13)); // ISSZ束窄 + data[index++] = getCellStringValue(row.getCell(14)); // ISJW急弯 + data[index++] = getCellStringValue(row.getCell(15)); // ISDW低洼地 + data[index++] = getCellStringValue(row.getCell(18)); // ISGT沟滩占地 + data[index++] = getCellStringValue(row.getCell(20)); // ISYS壅水 + data[index++] = getCellStringValue(row.getCell(21)); // ISDT顶托 + + // 风险隐患影响类型 (T~Y列) + data[index++] = getCellStringValue(row.getCell(22)); // ISGD改道 + data[index++] = getCellStringValue(row.getCell(23)); // ISML漫流 + + // REMARK - 备注 (Z列) + data[index++] = getCellStringValue(row.getCell(24)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = getCellStringValue(row.getCell(19)); // ISKJ溃决 + data[index++] = objectName; // PRENAME + data[index++] = objectCode; // PRECODE + data[index++] = getCellStringValue(row.getCell(16)); // ISLHHP临河滑坡 + data[index++] = getCellStringValue(row.getCell(17)); // ISNSL泥石流 + data[index++] = null; // SIGNER + data[index++] = countyCode; // CADCD + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // 其他固定字段 + data[index++] = "BATCH_" + System.currentTimeMillis(); // AUDBATCH + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + // WSCD - 流域编码 + data[index++] = watershedCode; + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } +} diff --git a/src/main/java/org/example/IaShzhHsurfaceDataImporter.java b/src/main/java/org/example/IaShzhHsurfaceDataImporter.java new file mode 100644 index 0000000..22f270f --- /dev/null +++ b/src/main/java/org/example/IaShzhHsurfaceDataImporter.java @@ -0,0 +1,915 @@ +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 横断面数据导入器(完整修复版) + */ +public class IaShzhHsurfaceDataImporter { + + public static final String dirName1 = "防治对象断面成果"; + public static final String type1 = "1"; + + public static final String dirName2 = "跨沟道路河桥涵"; + public static final String type2 = "2"; + + // 横断面主表插入SQL - 所有字段都通过参数设置 + private static final String INSERT_HSURFACE_SQL = + "INSERT INTO SHZH_JCSJ.IA_M_HSURFACE(" + + "HECD, ADCD, CHANNEL, ADDRESS, ISCTOWN, DMIDENTIT, " + + "DMFORM, TEXTURE, COORDINATE, ELETYPE, BASEELE, BASELGTD, " + + "BASELTTD, AZIMUTH, HMZ, CZZ, METHOD, VECD, SIGNER, " + + "AUDID, STATUS, REMARK, MODITIME, ISENABLE, IMPORTYEAR, " + + "AUDBATCH, CADCD, GUID, INPUTTYPE, WSCD, SURFACE_CLASSIFY, " + + "OBJECT_NAME, SURFACE_TYPE) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?,?)"; + + // 横断面点表插入SQL - 所有字段都通过参数设置 + private static final String INSERT_HSPOINT_SQL = + "INSERT INTO SHZH_JCSJ.IA_M_HSPOINT(" + + "HSURFACEID, TRANSECTNAME, FID, HELGTD, HELTTD, CDISTANCE, " + + "HEELE, POINTSIGN, TRANSECTTYPE, RVCOEFF, RIGHTCOEFF, " + + "LEFTCOEFF, GRADIENT, MODITIME, GUID, REMARK) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + // 检查横断面主表重复的SQL + private static final String CHECK_HSURFACE_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_HSURFACE WHERE HECD = ? and SURFACE_CLASSIFY = ?"; + + // 检查横断面点表重复的SQL + private static final String CHECK_HSPOINT_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_HSPOINT WHERE HSURFACEID = ? AND FID = ?"; + + public static void main(String[] args) { + // 测试用的固定路径 +// args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\222"}; +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"};--湖工大 +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\7777-华科-咸宁市8条1027-已通过初检-已统一表头-已入库"}; + + 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 hsurfaceDataList = new ArrayList<>(); + List hspointDataList = new ArrayList<>(); + + readExcelData(wscd,excelFile, hsurfaceDataList, hspointDataList); + + if (hsurfaceDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0, 0); + } + + System.out.println("成功读取 " + hsurfaceDataList.size() + " 条横断面数据,包含 " + + hspointDataList.size() + " 个断面点,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertData(hsurfaceDataList, hspointDataList); + return result; + } + + private static void readExcelData(String wscd,File excelFile, + List hsurfaceDataList, + List hspointDataList) throws Exception { + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + String name = excelFile.getName(); + Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+"); + Matcher matcher = pattern.matcher(name); + if(matcher.find()){ + name=matcher.group(); + }else{ + System.out.println("工作表表名有问题: " + name); + } + // 遍历所有工作表 + 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); + + // 解析横断面主表数据 + Object[] hsurfaceData = parseHsurfaceData(sheet, sheetName,wscd,name); + if (hsurfaceData != null) { + hsurfaceDataList.add(hsurfaceData); + System.out.println("✓ 解析横断面主表数据成功: " + sheetName); + + // 解析断面点数据 + List points = parseHspointData(sheet, (String) hsurfaceData[27]); // guid作为HSURFACEID + hspointDataList.addAll(points); + System.out.println("✓ 解析 " + points.size() + " 个断面点数据"); + } else { + System.out.println("✗ 解析横断面主表数据失败: " + sheetName); + } + } + } + } + + private static Object[] parseHsurfaceData(Sheet sheet, String sheetName,String wscd,String excelName) { + try { + Object[] data = new Object[33]; // 对应33个参数 + + int index = 0; + + // 按照新的读取规则获取基本信息 + // 第1行:C列-所在位置,F列-行政区划代码 + String location = getCellValue(sheet, 0, 2); // C1单元格 + String adminCode = getCellValue(sheet, 0, 5); // F1单元格 + + // 第3行:C列-所在沟道,F列-断面标识 + String channel = getCellValue(sheet, 1, 2); // C3单元格 + String dmIdentit = getCellValue(sheet, 1, 5); // F3单元格 + + // 第5行:C列-断面形态,F列-是否跨县 + String dmForm = getCellValue(sheet, 2, 2); // C5单元格 + String isCrossCounty = getCellValue(sheet, 2, 5); // F5单元格 + + // 第7行:C列-河床底质,F列-测量方法 + String texture = getCellValue(sheet, 3, 2); // C7单元格 + String method = getCellValue(sheet, 3, 5); // F7单元格 + + // 第1行:H列-坐标系备注 + String coordinate = ""; // H1单元格 + + // 提取基点信息(如果存在) + // 第9行:C列-基点经度,F列-基点纬度 + String baseLongitude = getCellValue(sheet, 4, 2); // C9单元格 - 基点经度 + String baseLatitude = getCellValue(sheet, 4, 5); // F9单元格 - 基点纬度 + + // 第11行:C列-基点高程,F列-断面方位角 + String baseElevation = getCellValue(sheet, 5, 2); // C11单元格 - 基点高程 + String azimuth = getCellValue(sheet, 5, 5); // F11单元格 - 断面方位角 + + // 第13行:C列-历史最高水位,F列-成灾水位 + String historyWaterLevel = getCellValue(sheet, 6, 2); // C13单元格 - 历史最高水位 + String disasterWaterLevel = getCellValue(sheet, 6, 5); // F13单元格 - 成灾水位 + + // HECD - 横断面编码 (工作表名) + data[index++] = sheetName; + + // ADCD - 行政区划代码 + data[index++] = getSafeString(adminCode); + + // CHANNEL - 所在沟道 + data[index++] = getSafeString(channel); + + // ADDRESS - 所在位置 + data[index++] = getSafeString(location); + + // ISCTOWN - 是否跨县 + data[index++] = getSafeString(isCrossCounty); + + // DMIDENTIT - 断面标识 + data[index++] = getSafeString(dmIdentit); + + // DMFORM - 断面形态 + data[index++] = getSafeString(dmForm); + + // TEXTURE - 河床底质 + data[index++] = getSafeString(texture); + + // COORDINATE - 坐标系 + data[index++] = getSafeString(coordinate); + + // ELETYPE - 高程系(默认为空) + data[index++] = null; + + // BASEELE - 基点高程 + data[index++] = getSafeString(baseElevation); + + // BASELGTD - 基点经度 + data[index++] = getSafeString(baseLongitude); + + // BASELTTD - 基点纬度 + data[index++] = getSafeString(baseLatitude); + + // AZIMUTH - 断面方位角 + data[index++] = getSafeString(azimuth); + + // HMZ - 历史最高水位 + data[index++] = getSafeString(historyWaterLevel); + + // CZZ - 成灾水位 + data[index++] = getSafeString(disasterWaterLevel); + + // METHOD - 测量方法 + data[index++] = getSafeString(method); + + // VECD - 纵断面编码(默认为空) + data[index++] = null; + + // SIGNER - 填写人姓名(默认为空) + data[index++] = null; + + // AUDID - 审核批次号(默认为空) + data[index++] = null; + + // STATUS - 状态(默认1-待审核) + data[index++] = "1"; + + // REMARK - 备注 + data[index++] = getSafeString(coordinate); + + // MODITIME - 时间戳 + data[index++] = new Timestamp(System.currentTimeMillis()); + + // ISENABLE - 启用状态 + data[index++] = "1"; + + // IMPORTYEAR - 导入年份 + data[index++] = "2025"; + + // AUDBATCH - 审核批次 + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // CADCD - 县级编码(从行政区划代码提取) + data[index++] = adminCode != null && adminCode.length() >= 6 ? + adminCode.substring(0, 6) +"000000000" : ""; + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // INPUTTYPE - 录入方式 + data[index++] = "1"; + + // WSCD - 流域编码 + data[index++] = wscd; + + // SURFACE_CLASSIFY - 断面分类 + data[index++] = excelName; + + // OBJECT_NAME - 对象名称 + data[index++] = null; + + // SURFACE_TYPE - 断面类型 + data[index++] = type1; + + return data; + + } catch (Exception e) { + System.err.println("解析横断面主表数据失败: " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + private static List parseHspointData(Sheet sheet, String hsurfaceId) { + List points = new ArrayList<>(); + + try { + // 找到数据开始行(序号列开始) + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("未找到断面点数据开始行"); + return points; + } + + 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 = parsePointRowData(row, hsurfaceId, i - startRow + 1); + if (pointData != null) { + points.add(pointData); + } + } + + } catch (Exception e) { + System.err.println("解析断面点数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return points; + } + + private static Object[] parsePointRowData(Row row, String hsurfaceId, int fid) { + try { + Object[] data = new Object[16]; // 对应16个参数 + + int index = 0; + + // HSURFACEID - 横断面主表ID + data[index++] = hsurfaceId; + + // TRANSECTNAME - 断面特征点描述 + data[index++] = getSafeString(getCellStringValue(row.getCell(1))); + + // FID - 断面序号 + data[index++] = fid; + + // HELGTD - 经度 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(4))); + + // HELTTD - 纬度 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(5))); + + // CDISTANCE - 起点距 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(2))); + + // HEELE - 高程 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3))); + + // POINTSIGN - 点类型标记 + data[index++] = "0"; + + // TRANSECTTYPE - 断面类型 + data[index++] = "普通断面"; + + // RVCOEFF - 糙率 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(6))); + + // RIGHTCOEFF - 右岸糙率 + data[index++] = null; + + // LEFTCOEFF - 左岸糙率 + data[index++] = null; + + // GRADIENT - 坡降 + data[index++] = null; + + // MODITIME - 时间戳 + data[index++] = new Timestamp(System.currentTimeMillis()); + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // REMARK - 备注 + data[index++] = null; + + return data; + + } catch (Exception e) { + System.err.println("解析断面点行数据失败: " + e.getMessage()); + return null; + } + } + + private static ProcessResult batchInsertData(List hsurfaceDataList, List hspointDataList) { + int importedCount = 0; + int duplicateCount = 0; + int pointDuplicateCount = 0; + + Connection conn = null; + PreparedStatement hsurfacePstmt = null; + PreparedStatement hspointPstmt = null; + PreparedStatement checkHsurfaceDupPstmt = null; + PreparedStatement checkHspointDupPstmt = null; + + try { + conn = DatabaseUtil.getConnection(); + if (conn == null) { + System.err.println("无法获取数据库连接"); + return new ProcessResult(0, 0, 0); + } + + hsurfacePstmt = conn.prepareStatement(INSERT_HSURFACE_SQL); + hspointPstmt = conn.prepareStatement(INSERT_HSPOINT_SQL); + checkHsurfaceDupPstmt = conn.prepareStatement(CHECK_HSURFACE_DUPLICATE_SQL); + checkHspointDupPstmt = conn.prepareStatement(CHECK_HSPOINT_DUPLICATE_SQL); + + conn.setAutoCommit(false); // 开启事务 + + // 处理横断面主表数据 + for (Object[] rowData : hsurfaceDataList) { + try { + String hecd = (String) rowData[0]; + String surface_classify = (String) rowData[30]; + // 检查横断面是否重复 + checkHsurfaceDupPstmt.setString(1, hecd); + checkHsurfaceDupPstmt.setString(2, surface_classify); + try (ResultSet rs = checkHsurfaceDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过重复横断面: " + hecd); + continue; + } + } + + // 插入数据 - 设置所有参数 + setHsurfaceParameters(hsurfacePstmt, rowData); + hsurfacePstmt.executeUpdate(); + importedCount++; + System.out.println("✓ 插入横断面记录: " + hecd); + + } catch (Exception e) { + System.err.println("横断面数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 处理横断面点表数据 + int pointImportedCount = 0; + for (Object[] pointData : hspointDataList) { + try { + String hsurfaceId = (String) pointData[0]; + Integer fid = (Integer) pointData[2]; + + // 检查断面点是否重复 + checkHspointDupPstmt.setString(1, hsurfaceId); + checkHspointDupPstmt.setInt(2, fid); + try (ResultSet rs = checkHspointDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + pointDuplicateCount++; + continue; + } + } + + // 插入数据 - 设置所有参数 + setHspointParameters(hspointPstmt, pointData); + hspointPstmt.addBatch(); + pointImportedCount++; + + // 每10条执行一次批量插入 + if (pointImportedCount % 10 == 0) { + hspointPstmt.executeBatch(); + hspointPstmt.clearBatch(); // 清空批量 + System.out.println("已批量插入 " + pointImportedCount + " 条断面点记录"); + } + + } catch (Exception e) { + System.err.println("断面点数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 执行剩余的断面点批量插入 + if (pointImportedCount > 0) { + hspointPstmt.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(checkHspointDupPstmt); + closeResource(checkHsurfaceDupPstmt); + closeResource(hspointPstmt); + closeResource(hsurfacePstmt); + closeResource(conn); + } + + return new ProcessResult(importedCount, duplicateCount, pointDuplicateCount); + } + + // 设置横断面主表参数 + private static void setHsurfaceParameters(PreparedStatement pstmt, Object[] rowData) throws Exception { + int index = 1; + + for (int i = 0; i < rowData.length; i++) { + Object value = rowData[i]; + if (value == null) { + pstmt.setNull(index++, java.sql.Types.NULL); + } else if (value instanceof String) { + pstmt.setString(index++, (String) value); + } else if (value instanceof Double) { + pstmt.setDouble(index++, (Double) value); + } else if (value instanceof Integer) { + pstmt.setInt(index++, (Integer) value); + } else if (value instanceof Timestamp) { + pstmt.setTimestamp(index++, (Timestamp) value); + } else { + pstmt.setObject(index++, value); + } + } + } + + // 设置横断面点表参数 + private static void setHspointParameters(PreparedStatement pstmt, Object[] pointData) throws Exception { + int index = 1; + + for (int i = 0; i < pointData.length; i++) { + Object value = pointData[i]; + if (value == null) { + pstmt.setNull(index++, java.sql.Types.NULL); + } else if (value instanceof String) { + pstmt.setString(index++, (String) value); + } else if (value instanceof Double) { + pstmt.setDouble(index++, (Double) value); + } else if (value instanceof Integer) { + pstmt.setInt(index++, (Integer) value); + } else if (value instanceof Timestamp) { + pstmt.setTimestamp(index++, (Timestamp) value); + } else { + pstmt.setObject(index++, 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + 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, dirName1); + if (sectionResultDir == null) { + System.out.println("在 " + measureDataDir.getPath() + " 下未找到"+dirName1+"目录"); + 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; + } + } + + private static int findDataStartRow(Sheet sheet) { + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); // 序号列 + if (cell != null && !isCellEmpty(cell)) { + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) return i; + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) return i; + } + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaShzhHsurfaceDataImporter2.java b/src/main/java/org/example/IaShzhHsurfaceDataImporter2.java new file mode 100644 index 0000000..c8fad2a --- /dev/null +++ b/src/main/java/org/example/IaShzhHsurfaceDataImporter2.java @@ -0,0 +1,934 @@ +package org.example; + +import org.apache.poi.openxml4j.util.ZipSecureFile; +import org.apache.poi.ss.usermodel.*; +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; + +/** + * 横断面数据导入器(完整修复版) + */ +public class IaShzhHsurfaceDataImporter2 { + + public static final String dirName1 = "防治对象断面成果"; + public static final String type1 = "1"; + + public static final String dirName2 = "跨沟道路河桥涵"; + public static final String type2 = "2"; + + // 横断面主表插入SQL - 所有字段都通过参数设置 + private static final String INSERT_HSURFACE_SQL = + "INSERT INTO SHZH_JCSJ.IA_M_HSURFACE(" + + "HECD, ADCD, CHANNEL, ADDRESS, ISCTOWN, DMIDENTIT, " + + "DMFORM, TEXTURE, COORDINATE, ELETYPE, BASEELE, BASELGTD, " + + "BASELTTD, AZIMUTH, HMZ, CZZ, METHOD, VECD, SIGNER, " + + "AUDID, STATUS, REMARK, MODITIME, ISENABLE, IMPORTYEAR, " + + "AUDBATCH, CADCD, GUID, INPUTTYPE, WSCD, SURFACE_CLASSIFY, " + + "OBJECT_NAME, SURFACE_TYPE) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?,?)"; + + // 横断面点表插入SQL - 所有字段都通过参数设置 + private static final String INSERT_HSPOINT_SQL = + "INSERT INTO SHZH_JCSJ.IA_M_HSPOINT(" + + "HSURFACEID, TRANSECTNAME, FID, HELGTD, HELTTD, CDISTANCE, " + + "HEELE, POINTSIGN, TRANSECTTYPE, RVCOEFF, RIGHTCOEFF, " + + "LEFTCOEFF, GRADIENT, MODITIME, GUID, REMARK) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + // 检查横断面主表重复的SQL + private static final String CHECK_HSURFACE_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_HSURFACE WHERE HECD = ? and SURFACE_CLASSIFY = ?"; + + // 检查横断面点表重复的SQL + private static final String CHECK_HSPOINT_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_HSPOINT WHERE HSURFACEID = ? AND FID = ?"; + + public static void main(String[] args) { + // 测试用的固定路径 +// args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\222"}; +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"};--湖工大 +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\7777-华科-咸宁市8条1027-已通过初检-已统一表头-已入库"}; + + 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 hsurfaceDataList = new ArrayList<>(); + List hspointDataList = new ArrayList<>(); + + readExcelData(wscd, excelFile, hsurfaceDataList, hspointDataList); + + if (hsurfaceDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0, 0); + } + + System.out.println("成功读取 " + hsurfaceDataList.size() + " 条横断面数据,包含 " + + hspointDataList.size() + " 个断面点,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertData(hsurfaceDataList, hspointDataList); + return result; + } + + private static void readExcelData(String wscd, File excelFile, + List hsurfaceDataList, + List hspointDataList) throws Exception { + // 保存原始设置 + double originalRatio = ZipSecureFile.getMinInflateRatio(); + + try { + // 临时调整安全阈值 + ZipSecureFile.setMinInflateRatio(0.001); + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + String name = excelFile.getName(); + Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+"); + Matcher matcher = pattern.matcher(name); + if (matcher.find()) { + name = matcher.group(); + } else { + System.out.println("工作表表名有问题: " + name); + } + // 遍历所有工作表 + 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); + + // 解析横断面主表数据 + Object[] hsurfaceData = parseHsurfaceData(sheet, sheetName, wscd, name); + if (hsurfaceData != null) { + hsurfaceDataList.add(hsurfaceData); + System.out.println("✓ 解析横断面主表数据成功: " + sheetName); + + // 解析断面点数据 + List points = parseHspointData(sheet, (String) hsurfaceData[27]); // guid作为HSURFACEID + hspointDataList.addAll(points); + System.out.println("✓ 解析 " + points.size() + " 个断面点数据"); + } else { + System.out.println("✗ 解析横断面主表数据失败: " + sheetName); + } + } + } + } finally { + // 恢复原始设置 + ZipSecureFile.setMinInflateRatio(originalRatio); + } + } + + private static Object[] parseHsurfaceData(Sheet sheet, String sheetName, String wscd, String excelName) { + try { + Object[] data = new Object[33]; // 对应33个参数 + + int index = 0; + + // 按照新的读取规则获取基本信息 + // 第1行:C列-所在位置,F列-行政区划代码 + String location = getCellValue(sheet, 0, 2); // C1单元格 + String adminCode = getCellValue(sheet, 0, 5); // F1单元格 + + // 第3行:C列-所在沟道,F列-断面标识 + String channel = getCellValue(sheet, 1, 2); // C3单元格 + String dmIdentit = getCellValue(sheet, 1, 5); // F3单元格 + + // 第5行:C列-断面形态,F列-是否跨县 + String dmForm = getCellValue(sheet, 2, 2); // C5单元格 + String isCrossCounty = getCellValue(sheet, 2, 5); // F5单元格 + + // 第7行:C列-河床底质,F列-测量方法 + String texture = getCellValue(sheet, 3, 2); // C7单元格 + String method = getCellValue(sheet, 3, 5); // F7单元格 + + // 第1行:H列-坐标系备注 + String coordinate = ""; // H1单元格 + + // 提取基点信息(如果存在) + // 第9行:C列-基点经度,F列-基点纬度 + String baseLongitude = getCellValue(sheet, 4, 2); // C9单元格 - 基点经度 + String baseLatitude = getCellValue(sheet, 4, 5); // F9单元格 - 基点纬度 + + // 第11行:C列-基点高程,F列-断面方位角 + String baseElevation = getCellValue(sheet, 5, 2); // C11单元格 - 基点高程 + String azimuth = getCellValue(sheet, 5, 5); // F11单元格 - 断面方位角 + + // 第13行:C列-历史最高水位,F列-成灾水位 + String historyWaterLevel = getCellValue(sheet, 6, 2); // C13单元格 - 历史最高水位 + String disasterWaterLevel = getCellValue(sheet, 6, 5); // F13单元格 - 成灾水位 + + // HECD - 横断面编码 (工作表名) + data[index++] = sheetName; + + // ADCD - 行政区划代码 + data[index++] = getSafeString(adminCode); + + // CHANNEL - 所在沟道 + data[index++] = getSafeString(channel); + + // ADDRESS - 所在位置 + data[index++] = getSafeString(location); + + // ISCTOWN - 是否跨县 + data[index++] = getSafeString(isCrossCounty); + + // DMIDENTIT - 断面标识 + data[index++] = getSafeString(dmIdentit); + + // DMFORM - 断面形态 + data[index++] = getSafeString(dmForm); + + // TEXTURE - 河床底质 + data[index++] = getSafeString(texture); + + // COORDINATE - 坐标系 + data[index++] = getSafeString(coordinate); + + // ELETYPE - 高程系(默认为空) + data[index++] = null; + + // BASEELE - 基点高程 + data[index++] = getSafeString(baseElevation); + + // BASELGTD - 基点经度 + data[index++] = getSafeString(baseLongitude); + + // BASELTTD - 基点纬度 + data[index++] = getSafeString(baseLatitude); + + // AZIMUTH - 断面方位角 + data[index++] = getSafeString(azimuth); + + // HMZ - 历史最高水位 + data[index++] = getSafeString(historyWaterLevel); + + // CZZ - 成灾水位 + data[index++] = getSafeString(disasterWaterLevel); + + // METHOD - 测量方法 + data[index++] = getSafeString(method); + + // VECD - 纵断面编码(默认为空) + data[index++] = null; + + // SIGNER - 填写人姓名(默认为空) + data[index++] = null; + + // AUDID - 审核批次号(默认为空) + data[index++] = null; + + // STATUS - 状态(默认1-待审核) + data[index++] = "1"; + + // REMARK - 备注 + data[index++] = getSafeString(coordinate); + + // MODITIME - 时间戳 + data[index++] = new Timestamp(System.currentTimeMillis()); + + // ISENABLE - 启用状态 + data[index++] = "1"; + + // IMPORTYEAR - 导入年份 + data[index++] = "2025"; + + // AUDBATCH - 审核批次 + data[index++] = "BATCH_" + System.currentTimeMillis(); + + // CADCD - 县级编码(从行政区划代码提取) + data[index++] = adminCode != null && adminCode.length() >= 6 ? + adminCode.substring(0, 6) + "000000000" : ""; + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // INPUTTYPE - 录入方式 + data[index++] = "1"; + + // WSCD - 流域编码 + data[index++] = wscd; + + // SURFACE_CLASSIFY - 断面分类 + data[index++] = excelName; + + // OBJECT_NAME - 对象名称 + data[index++] = null; + + // SURFACE_TYPE - 断面类型 + data[index++] = type1; + + return data; + + } catch (Exception e) { + System.err.println("解析横断面主表数据失败: " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + private static List parseHspointData(Sheet sheet, String hsurfaceId) { + List points = new ArrayList<>(); + + try { + // 找到数据开始行(序号列开始) + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("未找到断面点数据开始行"); + return points; + } + + 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 = parsePointRowData(row, hsurfaceId, i - startRow + 1); + if (pointData != null) { + points.add(pointData); + } + } + + } catch (Exception e) { + System.err.println("解析断面点数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return points; + } + + private static Object[] parsePointRowData(Row row, String hsurfaceId, int fid) { + try { + Object[] data = new Object[16]; // 对应16个参数 + + int index = 0; + + // HSURFACEID - 横断面主表ID + data[index++] = hsurfaceId; + + // TRANSECTNAME - 断面特征点描述 + data[index++] = getSafeString(getCellStringValue(row.getCell(1))); + + // FID - 断面序号 + data[index++] = fid; + + // HELGTD - 经度 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(4))); + + // HELTTD - 纬度 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(5))); + + // CDISTANCE - 起点距 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(2))); + + // HEELE - 高程 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3))); + + // POINTSIGN - 点类型标记 + data[index++] = "0"; + + // TRANSECTTYPE - 断面类型 + data[index++] = "普通断面"; + + // RVCOEFF - 糙率 + data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(6))); + + // RIGHTCOEFF - 右岸糙率 + data[index++] = null; + + // LEFTCOEFF - 左岸糙率 + data[index++] = null; + + // GRADIENT - 坡降 + data[index++] = null; + + // MODITIME - 时间戳 + data[index++] = new Timestamp(System.currentTimeMillis()); + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // REMARK - 备注 + data[index++] = null; + + return data; + + } catch (Exception e) { + System.err.println("解析断面点行数据失败: " + e.getMessage()); + return null; + } + } + + private static ProcessResult batchInsertData(List hsurfaceDataList, List hspointDataList) { + int importedCount = 0; + int duplicateCount = 0; + int pointDuplicateCount = 0; + + Connection conn = null; + PreparedStatement hsurfacePstmt = null; + PreparedStatement hspointPstmt = null; + PreparedStatement checkHsurfaceDupPstmt = null; + PreparedStatement checkHspointDupPstmt = null; + + try { + conn = DatabaseUtil.getConnection(); + if (conn == null) { + System.err.println("无法获取数据库连接"); + return new ProcessResult(0, 0, 0); + } + + hsurfacePstmt = conn.prepareStatement(INSERT_HSURFACE_SQL); + hspointPstmt = conn.prepareStatement(INSERT_HSPOINT_SQL); + checkHsurfaceDupPstmt = conn.prepareStatement(CHECK_HSURFACE_DUPLICATE_SQL); + checkHspointDupPstmt = conn.prepareStatement(CHECK_HSPOINT_DUPLICATE_SQL); + + conn.setAutoCommit(false); // 开启事务 + + // 处理横断面主表数据 + for (Object[] rowData : hsurfaceDataList) { + try { + String hecd = (String) rowData[0]; + String surface_classify = (String) rowData[30]; + // 检查横断面是否重复 + checkHsurfaceDupPstmt.setString(1, hecd); + checkHsurfaceDupPstmt.setString(2, surface_classify); + try (ResultSet rs = checkHsurfaceDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过重复横断面: " + hecd); + continue; + } + } + + // 插入数据 - 设置所有参数 + setHsurfaceParameters(hsurfacePstmt, rowData); + hsurfacePstmt.executeUpdate(); + importedCount++; + System.out.println("✓ 插入横断面记录: " + hecd); + + } catch (Exception e) { + System.err.println("横断面数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 处理横断面点表数据 + int pointImportedCount = 0; + for (Object[] pointData : hspointDataList) { + try { + String hsurfaceId = (String) pointData[0]; + Integer fid = (Integer) pointData[2]; + + // 检查断面点是否重复 + checkHspointDupPstmt.setString(1, hsurfaceId); + checkHspointDupPstmt.setInt(2, fid); + try (ResultSet rs = checkHspointDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + pointDuplicateCount++; + continue; + } + } + + // 插入数据 - 设置所有参数 + setHspointParameters(hspointPstmt, pointData); + hspointPstmt.addBatch(); + pointImportedCount++; + + // 每10条执行一次批量插入 + if (pointImportedCount % 10 == 0) { + hspointPstmt.executeBatch(); + hspointPstmt.clearBatch(); // 清空批量 + System.out.println("已批量插入 " + pointImportedCount + " 条断面点记录"); + } + + } catch (Exception e) { + System.err.println("断面点数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 执行剩余的断面点批量插入 + if (pointImportedCount > 0) { + hspointPstmt.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(checkHspointDupPstmt); + closeResource(checkHsurfaceDupPstmt); + closeResource(hspointPstmt); + closeResource(hsurfacePstmt); + closeResource(conn); + } + + return new ProcessResult(importedCount, duplicateCount, pointDuplicateCount); + } + + // 设置横断面主表参数 + private static void setHsurfaceParameters(PreparedStatement pstmt, Object[] rowData) throws Exception { + int index = 1; + + for (int i = 0; i < rowData.length; i++) { + Object value = rowData[i]; + if (value == null) { + pstmt.setNull(index++, java.sql.Types.NULL); + } else if (value instanceof String) { + pstmt.setString(index++, (String) value); + } else if (value instanceof Double) { + pstmt.setDouble(index++, (Double) value); + } else if (value instanceof Integer) { + pstmt.setInt(index++, (Integer) value); + } else if (value instanceof Timestamp) { + pstmt.setTimestamp(index++, (Timestamp) value); + } else { + pstmt.setObject(index++, value); + } + } + } + + // 设置横断面点表参数 + private static void setHspointParameters(PreparedStatement pstmt, Object[] pointData) throws Exception { + int index = 1; + + for (int i = 0; i < pointData.length; i++) { + Object value = pointData[i]; + if (value == null) { + pstmt.setNull(index++, java.sql.Types.NULL); + } else if (value instanceof String) { + pstmt.setString(index++, (String) value); + } else if (value instanceof Double) { + pstmt.setDouble(index++, (Double) value); + } else if (value instanceof Integer) { + pstmt.setInt(index++, (Integer) value); + } else if (value instanceof Timestamp) { + pstmt.setTimestamp(index++, (Timestamp) value); + } else { + pstmt.setObject(index++, 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 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, dirName1); + if (sectionResultDir == null) { + System.out.println("在 " + measureDataDir.getPath() + " 下未找到" + dirName1 + "目录"); + 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; + } + } + + private static int findDataStartRow(Sheet sheet) { + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); // 序号列 + if (cell != null && !isCellEmpty(cell)) { + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) return i; + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) return i; + } + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaShzhVsurfaceDataImporter.java b/src/main/java/org/example/IaShzhVsurfaceDataImporter.java new file mode 100644 index 0000000..771280c --- /dev/null +++ b/src/main/java/org/example/IaShzhVsurfaceDataImporter.java @@ -0,0 +1,846 @@ +package org.example; + +import org.apache.poi.ss.usermodel.*; +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 IaShzhVsurfaceDataImporter { + + // 纵断面主表插入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[]{"I:\\7777-华科-咸宁市8条1027-已通过初检-已统一表头-已入库"}; + 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 vsurfaceDataList = new ArrayList<>(); + List 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 vsurfaceDataList, + List vspointDataList) throws Exception { + 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); + + // 解析纵断面主表数据 + Object[] vsurfaceData = parseVsurfaceData(sheet, sheetName, wscd, surfaceClassify); + if (vsurfaceData != null) { + vsurfaceDataList.add(vsurfaceData); + System.out.println("✓ 解析纵断面主表数据成功: " + sheetName); + + // 解析断面点数据 + List points = parseVspointData(sheet, (String) vsurfaceData[19]); // guid作为vsurfaceID + vspointDataList.addAll(points); + System.out.println("✓ 解析 " + points.size() + " 个断面点数据"); + } else { + System.out.println("✗ 解析纵断面主表数据失败: " + sheetName); + } + } + } + } + + 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 parseVspointData(Sheet sheet, String vsurfaceId) { + List 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 vsurfaceDataList, List 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + 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; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaShzhVsurfaceDataImporter2.java b/src/main/java/org/example/IaShzhVsurfaceDataImporter2.java new file mode 100644 index 0000000..077ce37 --- /dev/null +++ b/src/main/java/org/example/IaShzhVsurfaceDataImporter2.java @@ -0,0 +1,864 @@ +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 vsurfaceDataList = new ArrayList<>(); + List 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 vsurfaceDataList, + List 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 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 parseVspointData(Sheet sheet, String vsurfaceId) { + List 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 vsurfaceDataList, List 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 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; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/IaStHdpDataImporter.java b/src/main/java/org/example/IaStHdpDataImporter.java new file mode 100644 index 0000000..05b572e --- /dev/null +++ b/src/main/java/org/example/IaStHdpDataImporter.java @@ -0,0 +1,588 @@ +// MountainFloodStHdpImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +/** + * 表8====代码还需优化,目前是处理了都有两个站点的 + */ +public class IaStHdpDataImporter { + + // 防治对象-监测站点关系表插入SQL + private static final String INSERT_ST_HDP_SQL = + "INSERT INTO SHZH_JCSJ.IA_ST_HDP (" + + "ADCD, PCD, FSOURCE, STCD, TYPE, LGTD, LTTD, REMARK, ISENABLE, IMPORTYEAR, " + + "INPUTTYPE, AUDID, STATUS, SIGNER, CADCD, GUID, AUDBATCH, WSCD, PRENAME, STNM" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + // 检查防治对象-监测站点重复的SQL + private static final String CHECK_ST_HDP_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_ST_HDP " + + "WHERE PCD = ? AND STCD = ? AND STNM = ?"; + + public static void main(String[] args) { + // 先测试数据库连接 + if (!testDatabaseConnection()) { + System.err.println("数据库连接测试失败,程序退出"); + return; + } + + // 测试用的固定路径 +// args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; +// args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; + args = new String[]{"I:\\8888-长科院-孝昌县8条1028-已通过初检-已统一表头-待入库"}; + + 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 { + processAllStHdpTables(baseDirectory); + } catch (Exception e) { + System.err.println("处理过程中发生错误: " + e.getMessage()); + e.printStackTrace(); + } + } + + private static boolean testDatabaseConnection() { + try { + Connection conn = DatabaseUtil.getConnection(); + if (conn != null && !conn.isClosed()) { + System.out.println("✓ 数据库连接测试成功"); + conn.close(); + return true; + } + } catch (Exception e) { + System.err.println("✗ 数据库连接测试失败: " + e.getMessage()); + } + return false; + } + + private static void processAllStHdpTables(File baseDir) { + File[] countyDirs = baseDir.listFiles(File::isDirectory); + if (countyDirs == null) { + System.out.println("在基础目录下未找到任何县市文件夹"); + return; + } + + int totalProcessed = 0; + int totalSuccess = 0; + int totalDuplicates = 0; + + System.out.println("开始处理防治对象-监测站点关系表..."); + System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); + + for (File countyDir : countyDirs) { + String countyName = extractCountyName(countyDir.getName()); + System.out.println("\n=== 处理县市: " + countyName + " ==="); + + try { + ProcessResult result = processCountyStHdpData(countyDir, countyName); + totalProcessed += result.processed; + totalDuplicates += result.duplicates; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + + ",导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录"); + } catch (Exception e) { + System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); + e.printStackTrace(); + } + } + + System.out.println("\n=== 防治对象-监测站点关系表处理完成 ==="); + System.out.println("成功处理县市: " + totalSuccess + " 个"); + System.out.println("总导入记录: " + totalProcessed + " 条"); + System.out.println("总跳过重复记录: " + totalDuplicates + " 条"); + } + + private static ProcessResult processCountyStHdpData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + int totalDuplicates = 0; + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyName + " 下未找到小流域目录"); + return new ProcessResult(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); + } + + 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 = processSxStHdpData(sxDir, countyName); + totalProcessed += result.processed; + totalDuplicates += result.duplicates; + System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录"); + } + + return new ProcessResult(totalProcessed, totalDuplicates); + } + + private static ProcessResult processSxStHdpData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + int duplicateCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return new ProcessResult(0, 0); + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findStHdpExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表8 防治对象-监测站点关系表.xlsx"); + return new ProcessResult(0, 0); + } + System.out.println("找到防治对象-监测站点关系表: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + ProcessResult result = readStHdpExcelAndImport(excelFile, countyName, watershedCode); + + return result; + } + + private static ProcessResult readStHdpExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + int duplicateCount = 0; + + // 读取所有数据到内存 + List stHdpDataList = readStHdpExcelData(excelFile, countyName, watershedCode); + if (stHdpDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0); + } + + System.out.println("成功读取 " + stHdpDataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertStHdpData(stHdpDataList); + + return result; + } + + private static List readStHdpExcelData(File excelFile, String countyName, String watershedCode) throws Exception { + List dataList = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表,跳过"填表说明"工作表 + for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + String sheetName = sheet.getSheetName(); + + if ("填表说明".equals(sheetName)) { + System.out.println("跳过填表说明工作表"); + continue; + } + + System.out.println("处理工作表: " + sheetName); + + int startRow = findStHdpDataStartRow(sheet); + if (startRow == -1) { + System.out.println("在工作表 " + sheetName + " 中未找到数据开始行"); + continue; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - startRow + 1) + " 行"); + + for (int i = startRow; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row == null) continue; + + Cell serialCell = row.getCell(2); + if (serialCell == null || isCellEmpty(serialCell)) { + continue; + } + + // 解析监测站点1数据 + Object[] station1Data = parseStHdpRowData(row, countyName, watershedCode, 1); + if (station1Data != null) { + dataList.add(station1Data); + } + + // 解析监测站点2数据 + Object[] station2Data = parseStHdpRowData(row, countyName, watershedCode, 2); + if (station2Data != null) { + dataList.add(station2Data); + } + + if (station1Data != null || station2Data != null) { + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功,生成 " + + (station1Data != null ? 1 : 0) + "+" + (station2Data != null ? 1 : 0) + " 条记录"); + } + } + } + } catch (Exception e) { + System.err.println("读取Excel文件失败: " + e.getMessage()); + throw e; + } + + return dataList; + } + + private static int findStHdpDataStartRow(Sheet sheet) { + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(2); + if (cell != null && !isCellEmpty(cell)) { + + return i; +// if (cell.getCellType() == CellType.NUMERIC) { +// double value = cell.getNumericCellValue(); +// if (value >= 1 && value <= 1000) return i; +// } else if (cell.getCellType() == CellType.STRING) { +// String value = cell.getStringCellValue().trim(); +// if (value.matches("\\d+")) return i; +// } + } + } + } + return -1; + } + + private static Object[] parseStHdpRowData(Row row, String countyName, String watershedCode, int stationIndex) { + try { + Object[] data = new Object[20]; // 对应20个参数 + + int index = 0; + + // 防治对象编码 (C列) + String pcd = getCellStringValue(row.getCell(2)); + if (pcd == null || pcd.trim().isEmpty()) { + return null; // 防治对象编码为空,跳过 + } + + // ADCD - 行政区划编码 (从防治对象编码提取前6位 + 000000) + String adcd = pcd.length() >= 9 ? pcd.substring(0, 9) + "000000" : pcd + "000000"; + data[index++] = adcd; + + // PCD - 防治对象代码 + data[index++] = pcd; + + // FSOURCE - 洪水来源 (D列) + data[index++] = getCellStringValue(row.getCell(3)); + + // 根据站点索引确定列位置 + // 站点1: 列4-8 (编码,名称,类型,经度,纬度) + // 站点2: 列9-13 (编码,名称,类型,经度,纬度) + int baseCol = (stationIndex == 1) ? 4 : 9; + + // STCD - 监测站点编码 + String stcd = getCellStringValue(row.getCell(baseCol)); + if (stcd == null || stcd.trim().isEmpty()) { + return null; // 监测站点编码为空,跳过 + } + data[index++] = stcd; + + // TYPE - 监测站点类型 + data[index++] = getCellStringValue(row.getCell(baseCol + 2)); + + // LGTD - 经度 + String lngStr = getCellStringValue(row.getCell(baseCol + 3)); + if (lngStr != null && !lngStr.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(lngStr.trim()); + } catch (NumberFormatException e) { + System.err.println("经度格式错误: " + lngStr); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // LTTD - 纬度 + String latStr = getCellStringValue(row.getCell(baseCol + 4)); + if (latStr != null && !latStr.trim().isEmpty()) { + try { + data[index++] = Double.parseDouble(latStr.trim()); + } catch (NumberFormatException e) { + System.err.println("纬度格式错误: " + latStr); + data[index++] = null; + } + } else { + data[index++] = null; + } + + // REMARK - 备注 (O列) + data[index++] = getCellStringValue(row.getCell(14)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + data[index++] = null; // SIGNER + data[index++] = pcd.length() >= 6 ? pcd.substring(0, 6) + "000000000" : pcd; // CADCD - 县级编码 + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // AUDBATCH + data[index++] = "BATCH_ST_" + System.currentTimeMillis(); + + // WSCD - 流域编码 + data[index++] = watershedCode; + + // PRENAME - 防灾对象名称 (B列) + data[index++] = getCellStringValue(row.getCell(1)); + + // STNM - 监测站点名称 + data[index++] = getCellStringValue(row.getCell(baseCol + 1)); + + return data; + + } catch (Exception e) { + System.err.println("解析监测站点" + stationIndex + "数据失败: " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + private static ProcessResult batchInsertStHdpData(List stHdpDataList) { + int importedCount = 0; + int duplicateCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stHdpPstmt = conn.prepareStatement(INSERT_ST_HDP_SQL); + PreparedStatement checkStHdpDupPstmt = conn.prepareStatement(CHECK_ST_HDP_DUPLICATE_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + // 使用Set来跟踪已处理的数据,避免内存中重复 + Set processedStHdpKeys = new HashSet<>(); + + for (Object[] rowData : stHdpDataList) { + try { + // 检查是否重复 + String pcd = (String) rowData[1]; // PCD在索引1 + String stcd = (String) rowData[3]; // STCD在索引3 + String stnm = (String) rowData[19]; // STNM在索引19 + + // 检查必要字段是否为空 + if (pcd == null || stcd == null || stnm == null) { + System.out.println("跳过数据不完整的记录: PCD=" + pcd + ", STCD=" + stcd); + continue; + } + + // 生成唯一键,先检查内存中是否已处理 + String stHdpKey = pcd + "|" + stcd + "|" + stnm; + if (processedStHdpKeys.contains(stHdpKey)) { + duplicateCount++; + System.out.println("跳过内存中重复记录: " + pcd + " - " + stnm); + continue; + } + + // 检查数据库中是否已存在 + checkStHdpDupPstmt.setString(1, pcd); + checkStHdpDupPstmt.setString(2, stcd); + checkStHdpDupPstmt.setString(3, stnm); + + try (ResultSet rs = checkStHdpDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过数据库中重复记录: " + pcd + " - " + stnm); + continue; + } + } + + // 插入数据 + for (int i = 0; i < rowData.length; i++) { + stHdpPstmt.setObject(i + 1, rowData[i]); + } + stHdpPstmt.addBatch(); + importedCount++; + processedStHdpKeys.add(stHdpKey); + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + stHdpPstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录到防治对象-监测站点关系表"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 执行剩余的批量插入 + if (importedCount > 0) { + stHdpPstmt.executeBatch(); + System.out.println("最终批量插入完成,共 " + importedCount + " 条记录到防治对象-监测站点关系表"); + } + + conn.commit(); // 提交事务 + System.out.println("防治对象-监测站点关系表事务提交成功"); + + } catch (Exception e) { + System.err.println("批量插入防治对象-监测站点关系表数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return new ProcessResult(importedCount, duplicateCount); + } + + // 辅助方法 + 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static File findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findStHdpExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表8 防治对象-监测站点关系表.xlsx") || + name.contains("防治对象-监测站点关系表") || + name.toLowerCase().endsWith(".xlsx")); + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表8 防治对象-监测站点关系表.xlsx")) { + return file; + } + } + for (File file : files) { + if (file.getName().contains("防治对象-监测站点关系表")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static String getCellStringValue(Cell cell) { + if (cell == null) return null; + try { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double num = cell.getNumericCellValue(); + return (num == (long) num) ? String.valueOf((long) num) : String.valueOf(num); + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return cell.getStringCellValue(); + } catch (Exception e) { + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e2) { + return null; + } + } + 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; + } + } + + // 处理结果类 + private static class ProcessResult { + int processed; + int duplicates; + + ProcessResult(int processed, int duplicates) { + this.processed = processed; + this.duplicates = duplicates; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/example/MountainFloodDataImporter.java b/src/main/java/org/example/MountainFloodDataImporter.java new file mode 100644 index 0000000..ef533db --- /dev/null +++ b/src/main/java/org/example/MountainFloodDataImporter.java @@ -0,0 +1,639 @@ +// MountainFloodDataImporter.java +package org.example; + +import org.apache.poi.ss.usermodel.*; +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.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class MountainFloodDataImporter { + + // 防灾对象表插入SQL + private static final String INSERT_HDP_SQL = + "INSERT INTO SHZH_JCSJ.IA_SHZH_HDP(ADCD, ADNM, TYPE, PCOUNT, RVNM, RVCD, BRNAME, BRCD, " + + "DAMNAME, DAMCD, DZRVNM, DZRVCD, ISSZ, ISJW, ISDW, ISGT, ISYS, ISDT, ISGD, ISML, " + + "REMARK, ISENABLE, IMPORTYEAR, ISKJ, PRENAME, PRECODE, ISLHHP, ISNSL, SIGNER, CADCD, " + + "GUID, AUDBATCH, INPUTTYPE, AUDID, STATUS, WSCD) \n" + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)"; + + // 防灾对象河流信息表插入SQL + private static final String INSERT_RV_INFO_SQL = + "INSERT INTO SHZH_JCSJ.IA_RV_INFO (" + + "PRECODE, PRENAME, RVCD, RVNM, WSCD" + + ") VALUES (?, ?, ?, ?, ?)"; + + // 检查重复的SQL(基于县编码、名称、编码、类型、人口) + private static final String CHECK_DUPLICATE_SQL = + "SELECT COUNT(*) FROM SHZH_JCSJ.IA_SHZH_HDP " + + "WHERE ADCD = ? AND PRENAME = ? AND PRECODE = ? AND TYPE = ? AND PCOUNT = ?"; + + public static void main(String[] args) { + // 先测试数据库连接 + if (!testDatabaseConnection()) { + System.err.println("数据库连接测试失败,程序退出"); + return; + } + + // 测试用的固定路径 + args = new String[]{"F:\\9月29日湖工大提交小流域数据全\\湖工大9.29"}; + + 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 boolean testDatabaseConnection() { + try { + Connection conn = DatabaseUtil.getConnection(); + if (conn != null && !conn.isClosed()) { + System.out.println("✓ 数据库连接测试成功"); + conn.close(); + return true; + } + } catch (Exception e) { + System.err.println("✗ 数据库连接测试失败: " + e.getMessage()); + } + return false; + } + + 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; + + 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; + totalSuccess++; + System.out.println("✓ 成功处理 " + countyName + + ",导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录"); + } 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 + " 条"); + } + + private static ProcessResult processCountyData(File countyDir, String countyName) throws Exception { + int totalProcessed = 0; + int totalDuplicates = 0; + + // 查找小流域目录 + File watershedDir = findWatershedDirectory(countyDir); + if (watershedDir == null) { + System.out.println("在 " + countyName + " 下未找到小流域目录"); + return new ProcessResult(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); + } + + 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; + System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录"); + } + + return new ProcessResult(totalProcessed, totalDuplicates); + } + + private static ProcessResult processSxData(File sxDir, String countyName) throws Exception { + int processedCount = 0; + int duplicateCount = 0; + + // 查找成果报表目录 + File reportDir = findReportDirectory(sxDir); + if (reportDir == null) { + System.out.println("在 " + sxDir.getPath() + " 下未找到成果报表目录"); + return new ProcessResult(0, 0); + } + System.out.println("找到成果报表目录: " + reportDir.getPath()); + + // 查找Excel文件 + File excelFile = findExcelFile(reportDir); + if (excelFile == null) { + System.out.println("在 " + reportDir.getPath() + " 下未找到表1山洪灾害防治对象名录.xlsx"); + return new ProcessResult(0, 0); + } + System.out.println("找到Excel文件: " + excelFile.getPath()); + + // 提取流域编码 + String watershedCode = extractWatershedCode(sxDir.getName()); + System.out.println("流域编码: " + watershedCode); + + // 读取Excel文件并导入数据库 + ProcessResult result = readExcelAndImport(excelFile, countyName, watershedCode); + + return result; + } + + private static ProcessResult readExcelAndImport(File excelFile, String countyName, String watershedCode) throws Exception { + int importedCount = 0; + int duplicateCount = 0; + + // 先读取所有数据到内存 + List hdpDataList = new ArrayList<>(); + List rvInfoDataList = new ArrayList<>(); + + readExcelData(excelFile, countyName, watershedCode, hdpDataList, rvInfoDataList); + + if (hdpDataList.isEmpty()) { + System.out.println("未读取到有效数据"); + return new ProcessResult(0, 0); + } + + System.out.println("成功读取 " + hdpDataList.size() + " 条数据,开始导入数据库..."); + + // 批量导入数据库 + ProcessResult result = batchInsertData(hdpDataList, rvInfoDataList); + + return result; + } + + private static String extractCountyCode(Sheet sheet) { + // 从第二行提取县代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(9); // H列 - 县代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdcd(Sheet sheet) { + // 从第二行提取乡镇代码 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(22); // H列 - 乡镇代码 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static String extractAdnm(Sheet sheet) { + // 从第二行提取乡镇名称 + Row headerRow = sheet.getRow(1); + if (headerRow != null) { + Cell codeCell = headerRow.getCell(14); // H列 - 乡镇名称 + if (codeCell != null) { + return getCellStringValue(codeCell); + } + } + return ""; // 默认值 + } + + private static void readExcelData(File excelFile, String countyName, String watershedCode, + List hdpDataList, List rvInfoDataList) throws Exception { + try (FileInputStream fis = new FileInputStream(excelFile); + Workbook workbook = new XSSFWorkbook(fis)) { + + // 遍历所有工作表 + for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { + Sheet sheet = workbook.getSheetAt(sheetIndex); + + String countyCode = extractCountyCode(sheet); + String adcd = extractAdcd(sheet); + String adnm = extractAdnm(sheet); + + int startRow = findDataStartRow(sheet); + if (startRow == -1) { + System.out.println("未找到数据开始行"); + return; + } + + System.out.println("数据从第 " + (startRow + 1) + " 行开始,共 " + (sheet.getLastRowNum() - 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[] hdpData = parseRowData(row, countyName, watershedCode, countyCode,adcd,adnm); + if (hdpData != null) { + hdpDataList.add(hdpData); + + // 同时生成河流信息表数据 + Object[] rvInfoData = parseRvInfoData(hdpData); + if (rvInfoData != null) { + rvInfoDataList.add(rvInfoData); + } + + System.out.println("✓ 解析第 " + (i + 1) + " 行数据成功"); + } else { + System.out.println("✗ 解析第 " + (i + 1) + " 行数据失败"); + } + } + } + } + } + + private static ProcessResult batchInsertData(List hdpDataList, List rvInfoDataList) { + int importedCount = 0; + int duplicateCount = 0; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement hdpPstmt = conn.prepareStatement(INSERT_HDP_SQL); + PreparedStatement rvInfoPstmt = conn.prepareStatement(INSERT_RV_INFO_SQL); + PreparedStatement checkDupPstmt = conn.prepareStatement(CHECK_DUPLICATE_SQL)) { + + conn.setAutoCommit(false); // 开启事务 + + // 处理防灾对象表数据 + for (Object[] rowData : hdpDataList) { + try { + // 检查是否重复 + String adcd = (String) rowData[0]; + String prename = (String) rowData[24]; // PRENAME在索引24 + String precode = (String) rowData[25]; // PRECODE在索引25 + String type = (String) rowData[2]; // TYPE在索引2 + Integer pcount = (Integer) rowData[3]; // PCOUNT在索引3 + + checkDupPstmt.setString(1, adcd); + checkDupPstmt.setString(2, prename); + checkDupPstmt.setString(3, precode); + checkDupPstmt.setString(4, type); + checkDupPstmt.setObject(5, pcount); + + try (ResultSet rs = checkDupPstmt.executeQuery()) { + if (rs.next() && rs.getInt(1) > 0) { + duplicateCount++; + System.out.println("跳过重复记录: " + prename + " (" + precode + ")"); + continue; + } + } + + // 插入数据 + for (int i = 0; i < rowData.length; i++) { + hdpPstmt.setObject(i + 1, rowData[i]); + } + hdpPstmt.addBatch(); + importedCount++; + + // 每10条执行一次批量插入 + if (importedCount % 10 == 0) { + hdpPstmt.executeBatch(); + System.out.println("已批量插入 " + importedCount + " 条记录到防灾对象表"); + } + } catch (Exception e) { + System.err.println("单条数据插入失败: " + e.getMessage()); + // 继续处理下一条数据 + } + } + + // 执行剩余的批量插入 + if (importedCount % 10 != 0) { + hdpPstmt.executeBatch(); + } + + // 处理河流信息表数据 + int rvImportedCount = 0; + for (Object[] rvData : rvInfoDataList) { + try { + for (int i = 0; i < rvData.length; i++) { + rvInfoPstmt.setObject(i + 1, rvData[i]); + } + rvInfoPstmt.addBatch(); + rvImportedCount++; + + if (rvImportedCount % 10 == 0) { + rvInfoPstmt.executeBatch(); + } + } catch (Exception e) { + System.err.println("河流信息表数据插入失败: " + e.getMessage()); + } + } + + // 执行剩余的河流信息批量插入 + if (rvImportedCount % 10 != 0) { + rvInfoPstmt.executeBatch(); + } + + conn.commit(); // 提交事务 + System.out.println("成功导入 " + importedCount + " 条记录到防灾对象表"); + System.out.println("成功导入 " + rvImportedCount + " 条记录到河流信息表"); + + } catch (Exception e) { + System.err.println("批量插入数据失败: " + e.getMessage()); + e.printStackTrace(); + } + + return new ProcessResult(importedCount, duplicateCount); + } + + // 解析河流信息表数据 + private static Object[] parseRvInfoData(Object[] hdpData) { + try { + Object[] rvData = new Object[5]; + + // PRECODE + rvData[0] = hdpData[25]; // PRECODE在索引25 + // PRENAME + rvData[1] = hdpData[24]; // PRENAME在索引24 + // RVCD - 河流代码 + rvData[2] = hdpData[5]; // RVCD在索引5 + // RVNM - 河流名称 + rvData[3] = hdpData[4]; // RVNM在索引4 + // WSCD - 流域编码 + rvData[4] = hdpData[35]; // WSCD在索引35 + + return rvData; + } catch (Exception e) { + System.err.println("解析河流信息数据失败: " + e.getMessage()); + return null; + } + } + + // 其他辅助方法保持不变... + 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 sxDirs = new ArrayList<>(); + for (File subDir : subDirs) { + // 包含"水系"或者是类似HBWFF开头的文件夹都认为是水系文件夹 + if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWFF.*")) { + sxDirs.add(subDir); + } + } + return sxDirs.toArray(new File[0]); + } + return null; + } + + private static File findReportDirectory(File sxDir) { + File[] subDirs = sxDir.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 findExcelFile(File reportDir) { + File[] files = reportDir.listFiles((dir, name) -> + name.equals("表1山洪灾害防治对象名录.xlsx") || name.toLowerCase().endsWith(".xlsx")); + if (files != null && files.length > 0) { + for (File file : files) { + if (file.getName().equals("表1山洪灾害防治对象名录.xlsx")) { + return file; + } + } + return files[0]; + } + return null; + } + + private static String extractCountyName(String dirName) { + return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; + } + + private static String extractWatershedCode(String dirName) { + String[] parts = dirName.split("水系"); + String str = parts[0].trim(); + int start = str.length() -2; + return parts.length > 0 ? str.substring(0,start) : dirName; + } + + private static int findDataStartRow(Sheet sheet) { + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row != null) { + Cell cell = row.getCell(0); + if (cell != null && !isCellEmpty(cell)) { + if (cell.getCellType() == CellType.NUMERIC) { + double value = cell.getNumericCellValue(); + if (value >= 1 && value <= 1000) return i; + } else if (cell.getCellType() == CellType.STRING) { + String value = cell.getStringCellValue().trim(); + if (value.matches("\\d+")) return i; + } + } + } + } + return -1; + } + + 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; + } + } + + private static String getCountyCode(String objectCode) { + return (objectCode != null && objectCode.length() >= 6) ? + objectCode.substring(0, 6) + "000000" : null; + } + + // 处理结果类 + private static class ProcessResult { + int processed; + int duplicates; + + ProcessResult(int processed, int duplicates) { + this.processed = processed; + this.duplicates = duplicates; + } + } + + // parseRowData方法保持不变... + private static Object[] parseRowData(Row row, String countyName, String watershedCode, String countyCode,String adcd ,String adnm) { + try { + Object[] data = new Object[36]; // 对应36个参数 + + int index = 0; + + // ADCD - 行政区划代码 (C列) + String objectCode = getCellStringValue(row.getCell(2)); + data[index++] = adcd; + + // ADNM - 行政区划名称 (B列 + 县市名称) + String objectName = getCellStringValue(row.getCell(1)); + data[index++] = adnm; + + // TYPE - 类型 (D列) + data[index++] = getCellStringValue(row.getCell(3)); + + // PCOUNT - 人口 (E列) + String populationStr = getCellStringValue(row.getCell(4)); + if (populationStr != null && !populationStr.trim().isEmpty()) { + try { + data[index++] = Integer.parseInt(populationStr.trim()); + } catch (NumberFormatException e) { + data[index++] = null; + } + } else { + data[index++] = null; + } + + // RVNM - 河流名称 (F列) + data[index++] = getCellStringValue(row.getCell(5)); + + // RVCD - 河流代码 (G列) + data[index++] = getCellStringValue(row.getCell(6)); + + // BRNAME - 桥梁名称 (H列) + data[index++] = getCellStringValue(row.getCell(7)); + + // BRCD - 桥梁编码 (I列) + data[index++] = getCellStringValue(row.getCell(8)); + + // DAMNAME - 塘坝名称 (J列) + data[index++] = getCellStringValue(row.getCell(9)); + + // DAMCD - 塘坝编码 (K列) + data[index++] = getCellStringValue(row.getCell(10)); + + // DZRVNM - 多支河流名称 (L列) + data[index++] = getCellStringValue(row.getCell(11)); + + // DZRVCD - 多支河流代码 (M列) + data[index++] = getCellStringValue(row.getCell(12)); + + // 风险隐患要素 (N~S列) + data[index++] = getCellStringValue(row.getCell(13)); // ISSZ + data[index++] = getCellStringValue(row.getCell(14)); // ISJW + data[index++] = getCellStringValue(row.getCell(15)); // ISDW + data[index++] = getCellStringValue(row.getCell(16)); // ISGT + data[index++] = getCellStringValue(row.getCell(17)); // ISYS + data[index++] = getCellStringValue(row.getCell(18)); // ISDT + + // 风险隐患影响类型 (T~Y列) + data[index++] = getCellStringValue(row.getCell(19)); // ISGD + data[index++] = getCellStringValue(row.getCell(20)); // ISML + + // REMARK - 备注 (Z列) + data[index++] = getCellStringValue(row.getCell(25)); + + // 固定值字段 + data[index++] = "1"; // ISENABLE + data[index++] = "2025"; // IMPORTYEAR + data[index++] = null; // ISKJ + data[index++] = objectName; // PRENAME + data[index++] = objectCode; // PRECODE + data[index++] = null; // ISLHHP + data[index++] = null; // ISNSL + data[index++] = null; // SIGNER + data[index++] = countyCode; // CADCD + + // GUID - 唯一标识 + data[index++] = UUID.randomUUID().toString(); + + // 其他固定字段 + data[index++] = "BATCH_" + System.currentTimeMillis(); // AUDBATCH + data[index++] = "1"; // INPUTTYPE + data[index++] = null; // AUDID + data[index++] = "1"; // STATUS + // WSCD - 流域编码 + data[index++] = watershedCode; + + return data; + + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/example/Test.java b/src/main/java/org/example/Test.java new file mode 100644 index 0000000..e583086 --- /dev/null +++ b/src/main/java/org/example/Test.java @@ -0,0 +1,8 @@ +package org.example; + +public class Test { + public static void main(String[] args) { + String str = "WFG26305L0000000ZACS0011"; + System.out.println(str.length()); + } +} diff --git a/src/main/java/org/example/WatershedDataCleaner.java b/src/main/java/org/example/WatershedDataCleaner.java new file mode 100644 index 0000000..243d4f8 --- /dev/null +++ b/src/main/java/org/example/WatershedDataCleaner.java @@ -0,0 +1,296 @@ +// WatershedDataCleaner.java +package org.example; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +public class WatershedDataCleaner { + + /** + * 根据小流域编码集合删除相关表数据 + * @param watershedCodes 小流域编码列表 + * @return 删除结果信息 + */ + public static CleanResult deleteByWatershedCodes(List watershedCodes) { + if (watershedCodes == null || watershedCodes.isEmpty()) { + return new CleanResult(0, "小流域编码列表为空,无需删除"); + } + + Connection conn = null; + CleanResult result = new CleanResult(); + + try { + conn = DatabaseUtil.getConnection(); + conn.setAutoCommit(false); // 开启事务 + + System.out.println("开始删除 " + watershedCodes.size() + " 个小流域的相关数据..."); + System.out.println("小流域编码列表: " + watershedCodes); + + // 依次删除各个表的数据 + result.table1Count = deleteFromTable1(conn, watershedCodes); + result.table2Count = deleteFromTable2(conn, watershedCodes); + result.table3Count = deleteFromTable3(conn, watershedCodes); + result.table4Count = deleteFromTable4(conn, watershedCodes); + result.table5_7Count = deleteFromTable5_7(conn, watershedCodes); + result.table8Count = deleteFromTable8(conn, watershedCodes); + result.hsPointCount = deleteFromHSPoint(conn, watershedCodes); + result.hSurfaceCount = deleteFromHSurface(conn, watershedCodes); + result.vsPointCount = deleteFromVSPoint(conn, watershedCodes); + result.vSurfaceCount = deleteFromVSurface(conn, watershedCodes); + + // 提交事务 + conn.commit(); + result.success = true; + result.message = "数据删除完成"; + + System.out.println("✓ " + result.getMessage()); + + } catch (Exception e) { + // 回滚事务 + if (conn != null) { + try { + conn.rollback(); + } catch (SQLException ex) { + System.err.println("回滚事务失败: " + ex.getMessage()); + } + } + result.success = false; + result.message = "删除过程中发生错误: " + e.getMessage(); + System.err.println("✗ " + result.getMessage()); + e.printStackTrace(); + } finally { + // 恢复自动提交并关闭连接 + if (conn != null) { + try { + conn.setAutoCommit(true); + conn.close(); + } catch (SQLException e) { + System.err.println("关闭连接失败: " + e.getMessage()); + } + } + } + + return result; + } + + /** + * 表1防治对象 - IA_SHZH_HDP + */ + private static int deleteFromTable1(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_SHZH_HDP\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_SHZH_HDP"); + } + + /** + * 表2跨沟 - IA_RBAD_INFO + */ + private static int deleteFromTable2(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_RBAD_INFO\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_RBAD_INFO"); + } + + /** + * 表3沟滩占地 - IA_GLA_INFO + */ + private static int deleteFromTable3(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_GLA_INFO\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_GLA_INFO"); + } + + /** + * 表4外洪顶托 - IA_EFTS_TOWN + */ + private static int deleteFromTable4(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_EFTS_TOWN\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_EFTS_TOWN"); + } + + /** + * 表5,6,7三合一 - IA_SHZH_HDP_POINT + */ + private static int deleteFromTable5_7(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_SHZH_HDP_POINT\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_SHZH_HDP_POINT"); + } + + /** + * 表8防治对象关联站点 - IA_ST_HDP + */ + private static int deleteFromTable8(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_ST_HDP\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_ST_HDP"); + } + + /** + * 横断面 - IA_M_HSURFACE + */ + private static int deleteFromHSurface(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_M_HSURFACE\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_M_HSURFACE"); + } + + /** + * 横断面点 - IA_M_HSPOINT + */ + private static int deleteFromHSPoint(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_M_HSPOINT\" WHERE \"HSURFACEID\" IN (SELECT GUID FROM \"SHZH_JCSJ\".\"IA_M_HSURFACE\" WHERE \"WSCD\" = ?)"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_M_HSPOINT"); + } + + /** + * 纵断面 - IA_M_VSURFACE + */ + private static int deleteFromVSurface(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_M_VSURFACE\" WHERE \"WSCD\" = ?"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_M_VSURFACE"); + } + + /** + * 纵断面点 - IA_M_VSPOINT + */ + private static int deleteFromVSPoint(Connection conn, List watershedCodes) throws SQLException { + String sql = "DELETE FROM \"SHZH_JCSJ\".\"IA_M_VSPOINT\" WHERE WHERE \"ZSURFACEID\" IN (SELECT GUID FROM \"SHZH_JCSJ\".\"IA_M_VSURFACE\" WHERE \"WSCD\" = ?)"; + return executeBatchDelete(conn, sql, watershedCodes, "IA_M_VSPOINT"); + } + + /** + * 执行批量删除操作 + */ + private static int executeBatchDelete(Connection conn, String sql, List watershedCodes, String tableName) throws SQLException { + int totalDeleted = 0; + + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + for (String code : watershedCodes) { + // 先查询要删除的记录数 + int countBefore = getRecordCount(conn, tableName, code); + + if (countBefore > 0) { + pstmt.setString(1, code); + int deleted = pstmt.executeUpdate(); + totalDeleted += deleted; + System.out.println(" 表 " + tableName + " - 流域 " + code + ": 删除 " + deleted + " 条记录"); + } else { + System.out.println(" 表 " + tableName + " - 流域 " + code + ": 无记录可删除"); + } + } + } + + return totalDeleted; + } + + /** + * 获取指定表和小流域编码的记录数 + */ + private static int getRecordCount(Connection conn, String tableName, String watershedCode) throws SQLException { + String sql = "SELECT COUNT(*) FROM \"SHZH_JCSJ\".\"" + tableName + "\" WHERE \"WSCD\" = ?"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, watershedCode); + try (ResultSet rs = pstmt.executeQuery()) { + if (rs.next()) { + return rs.getInt(1); + } + } + } + return 0; + } + + /** + * 删除结果类 + */ + public static class CleanResult { + private boolean success; + private String message; + private int table1Count; // IA_SHZH_HDP + private int table2Count; // IA_RBAD_INFO + private int table3Count; // IA_GLA_INFO + private int table4Count; // IA_EFTS_TOWN + private int table5_7Count; // IA_SHZH_HDP_POINT + private int table8Count; // IA_ST_HDP + private int hSurfaceCount; // IA_M_HSURFACE + private int hsPointCount; // IA_M_HSPOINT + private int vSurfaceCount; // IA_M_VSURFACE + private int vsPointCount; // IA_M_VSPOINT + + public CleanResult() {} + + public CleanResult(int totalCount, String message) { + this.success = true; + this.message = message; + } + + // Getter 方法 + public boolean isSuccess() { return success; } + public String getMessage() { return message; } + public int getTable1Count() { return table1Count; } + public int getTable2Count() { return table2Count; } + public int getTable3Count() { return table3Count; } + public int getTable4Count() { return table4Count; } + public int getTable5_7Count() { return table5_7Count; } + public int getTable8Count() { return table8Count; } + public int gethSurfaceCount() { return hSurfaceCount; } + public int getHsPointCount() { return hsPointCount; } + public int getvSurfaceCount() { return vSurfaceCount; } + public int getVsPointCount() { return vsPointCount; } + + /** + * 获取总删除记录数 + */ + public int getTotalDeleted() { + return table1Count + table2Count + table3Count + table4Count + + table5_7Count + table8Count + hSurfaceCount + hsPointCount + + vSurfaceCount + vsPointCount; + } + + /** + * 打印详细删除结果 + */ + public void printDetailedResult() { + System.out.println("\n=== 删除结果详情 ==="); + System.out.println("状态: " + (success ? "成功" : "失败")); + System.out.println("消息: " + message); + System.out.println("各表删除记录数:"); + System.out.println(" IA_SHZH_HDP (防治对象): " + table1Count); + System.out.println(" IA_RBAD_INFO (跨沟): " + table2Count); + System.out.println(" IA_GLA_INFO (沟滩占地): " + table3Count); + System.out.println(" IA_EFTS_TOWN (外洪顶托): " + table4Count); + System.out.println(" IA_SHZH_HDP_POINT (三合一): " + table5_7Count); + System.out.println(" IA_ST_HDP (防治对象关联站点): " + table8Count); + System.out.println(" IA_M_HSPOINT (横断面点): " + hsPointCount); + System.out.println(" IA_M_HSURFACE (横断面): " + hSurfaceCount); + System.out.println(" IA_M_VSPOINT (纵断面点): " + vsPointCount); + System.out.println(" IA_M_VSURFACE (纵断面): " + vSurfaceCount); + System.out.println("总删除记录数: " + getTotalDeleted()); + } + } + + /** + * 测试方法 + */ + public static void main(String[] args) { + // 测试数据 + List testWatershedCodes = Arrays.asList( + "HBWFA8900124H00000", + "HBWFA8900125M00000", + "HBWFA8900126F00000", + "HBWFA8900127000000", + "HBWFAA200123o00000", + "HBWFAA200125cE0000", + "HBWFAA200127c00000", + "HBWFAA200127m00000", + "HBWFAA200127t00000", + "HBWFAA20012g000000", + "HBWFAA2103N0000000", + "HBWFAA2106F0000000", + "HBWFAA210G00000000", + "HBWFADJ00125000000" + ); + + System.out.println("开始测试删除操作..."); + CleanResult result = deleteByWatershedCodes(testWatershedCodes); + result.printDetailedResult(); + } +} \ No newline at end of file