From 8629f2be4fca45fcc83edd5e80e6b945a1d32301 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Mon, 1 Dec 2025 14:18:25 +0800 Subject: [PATCH] =?UTF-8?q?Excel=E5=AF=BC=E5=85=A5=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E5=AE=9A=E4=BD=8D=E5=88=B0=E5=85=B7=E4=BD=93sheet=E5=92=8C?= =?UTF-8?q?=E8=A1=8C=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ecss/service/impl/CoDelServiceImpl.java | 120 ++++++++++++------ 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java index 6dd20fcf..9030ddab 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java @@ -345,7 +345,7 @@ public class CoDelServiceImpl implements CoDelService { } /** - * 判断单元格值是否有效 + * 判断单元格值是否有效(通用版本) * 无效值包括:空值、"0"、Excel错误(#REF!、#N/A、#VALUE!等) * * @param cellValue 单元格字符串值 @@ -357,27 +357,48 @@ public class CoDelServiceImpl implements CoDelService { return false; } + String trimmedValue = cellValue.trim(); + // 2. 值为"0" - if ("0".equals(cellValue.trim())) { + if ("0".equals(trimmedValue)) { return false; } // 3. Excel错误值(以#开头,如#REF!、#N/A、#VALUE!、#DIV/0!、#NAME?、#NUM!、#NULL!等) - return !cellValue.trim().startsWith("#"); + return !trimmedValue.startsWith("#"); // 其他情况视为有效值 } + /** + * 判断CMC Invoice是否有效 + * 无效值包括:空值、"0"、Excel错误、长度超过20位 + * + * @param cellValue 单元格字符串值 + * @return true=有效值,false=无效值 + */ + private boolean isValidCmcInvoice(String cellValue) { + // 先进行通用验证 + if (!isValidCellValue(cellValue)) { + return false; + } + + // CMC Invoice特殊验证:长度不能超过20位 + String trimmedValue = cellValue.trim(); + return trimmedValue.length() <= 20; + } + /** * 解析Excel第一行,建立列名到列索引的映射关系 * * @param headerRow 第一行(表头行) + * @param sheetName Sheet名称(用于错误提示) * @return 列名到列索引的映射Map */ - private Map parseExcelHeader(XSSFRow headerRow) { + private Map parseExcelHeader(XSSFRow headerRow, String sheetName) { Map columnIndexMap = new HashMap<>(); if (headerRow == null) { - throw new RuntimeException("Excel表头行不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 表头行不能为空!"); } // 遍历第一行的所有单元格,建立列名到索引的映射 @@ -411,7 +432,7 @@ public class CoDelServiceImpl implements CoDelService { } if (!missingColumns.isEmpty()) { - throw new RuntimeException("Excel表头缺少必填列: " + String.join(", ", missingColumns)); + throw new RuntimeException("Sheet [" + sheetName + "] 表头缺少必填列: " + String.join(", ", missingColumns)); } return columnIndexMap; @@ -422,31 +443,34 @@ public class CoDelServiceImpl implements CoDelService { for (int s = 0; s < workbook.getNumberOfSheets(); s++) { // 读取工作表 XSSFSheet sheet = workbook.getSheetAt(s); - // 剔除空行 - deleteEmptyRow(sheet); - // 获取行数 - int rows = sheet.getPhysicalNumberOfRows(); + String sheetName = sheet.getSheetName(); - if (rows < 4) { - continue; // 至少需要前2行、表头行(第3行)和一行数据(第4行) - } + try { + // 剔除空行 + deleteEmptyRow(sheet); + // 获取行数 + int rows = sheet.getPhysicalNumberOfRows(); - // 获取第三行(表头行) - XSSFRow headerRow = sheet.getRow(2); - if (headerRow == null) { - log.warn("Sheet {} 的第3行为空,跳过该Sheet", sheet.getSheetName()); - continue; - } + if (rows < 4) { + continue; // 至少需要前2行、表头行(第3行)和一行数据(第4行) + } + + // 获取第三行(表头行) + XSSFRow headerRow = sheet.getRow(2); + if (headerRow == null) { + log.warn("Sheet [{}] 的第3行为空,跳过该Sheet", sheetName); + continue; + } - // 解析表头行(第3行),获取列索引映射 - Map columnMap = parseExcelHeader(headerRow); + // 解析表头行(第3行),获取列索引映射 + Map columnMap = parseExcelHeader(headerRow, sheetName); - // 获取Cargo Ready Date列索引 - Integer cargoReadyDateIdx = columnMap.get("Cargo Ready Date"); - if (cargoReadyDateIdx == null) { - log.warn("Sheet {} 中未找到 'Cargo Ready Date' 列,跳过该Sheet", sheet.getSheetName()); - continue; - } + // 获取Cargo Ready Date列索引 + Integer cargoReadyDateIdx = columnMap.get("Cargo Ready Date"); + if (cargoReadyDateIdx == null) { + log.warn("Sheet [{}] 中未找到 'Cargo Ready Date' 列,跳过该Sheet", sheetName); + continue; + } // 遍历每一行(从第四行开始,即索引3) for (int j = 3; j < rows; j++) { @@ -475,37 +499,37 @@ public class CoDelServiceImpl implements CoDelService { Integer poIdx = columnMap.get("PO#"); if (row.getCell(poIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的PO#不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [PO#] 列不能为空!"); } Integer pnIdx = columnMap.get("PN"); if (row.getCell(pnIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的PN不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [PN] 列不能为空!"); } Integer qtyIdx = columnMap.get("Qty (pcs)"); if (row.getCell(qtyIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的Qty不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Qty (pcs)] 列不能为空!"); } Integer destinationIdx = columnMap.get("Destination"); if (row.getCell(destinationIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的Destination不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Destination] 列不能为空!"); } Integer shippingModeIdx = columnMap.get("Shipping Mode"); if (row.getCell(shippingModeIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的Shipping Mode不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Shipping Mode] 列不能为空!"); } Integer currencyIdx = columnMap.get("Currency"); if (row.getCell(currencyIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的Currency不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Currency] 列不能为空!"); } Integer tpIdx = columnMap.get("TP"); if (row.getCell(tpIdx) == null) { - throw new RuntimeException("第" + (j+1) + "行的TP不能为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [TP] 列不能为空!"); } // 创建对象并为对象赋值 @@ -520,7 +544,7 @@ public class CoDelServiceImpl implements CoDelService { String formatted = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); readDate = DateUtils.getDateByParten(formatted, "yyyy-MM-dd"); } catch (Exception e) { - throw new RuntimeException("第" + (j+1) + "行的ReadyDate格式有误!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Cargo Ready Date] 列格式有误! " + e.getMessage()); } task.setReadyDate(readDate); @@ -533,19 +557,20 @@ public class CoDelServiceImpl implements CoDelService { task.setCurrency(getStringCellValue(row, currencyIdx)); task.setTp(getNumericCellValueOrDefault(row, tpIdx)); - // 处理CMC Invoice:如果CMC Invoice为空/0/Excel错误则取Shipping Number,如果两者都为空则报错 + // 处理CMC Invoice:如果CMC Invoice为空/0/Excel错误/超过20位则取Shipping Number,如果两者都为空则报错 String cmcInvoiceValue = getStringCellValueSafe(row, columnMap, "CMC Invoice"); String shippingNumberValue = getStringCellValueSafe(row, columnMap, "Shipping Number"); - // 判断CMC Invoice是否为有效值(排除空值、"0"、Excel错误) - boolean isCmcInvoiceValid = isValidCellValue(cmcInvoiceValue); + // 判断CMC Invoice是否为有效值(排除空值、"0"、Excel错误、长度超过20位) + boolean isCmcInvoiceValid = isValidCmcInvoice(cmcInvoiceValue); + // 判断Shipping Number是否为有效值(排除空值、"0"、Excel错误,允许超过20位) boolean isShippingNumberValid = isValidCellValue(shippingNumberValue); if (!isCmcInvoiceValid && !isShippingNumberValid) { - throw new RuntimeException("第" + (j+1) + "行的CMC Invoice和Shipping Number不能同时为空!"); + throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [CMC Invoice] 和 [Shipping Number] 列不能同时为空!"); } - // 如果CMC Invoice无效(空/0/错误),则使用Shipping Number + // 如果CMC Invoice无效(空/0/错误/超过20位),则使用Shipping Number if (!isCmcInvoiceValid) { task.setCmcInvoice(shippingNumberValue); } else { @@ -601,6 +626,18 @@ public class CoDelServiceImpl implements CoDelService { // 物料存在性检查已移至批量处理阶段,此处不再单独检查 excelList.add(task); } + + } catch (Exception e) { + // 捕获并重新抛出异常,确保包含Sheet信息 + String errorMsg = e.getMessage(); + if (errorMsg != null && errorMsg.contains("Sheet [")) { + // 异常消息已包含Sheet信息,直接抛出 + throw e; + } else { + // 异常消息不包含Sheet信息,添加Sheet信息后抛出 + throw new RuntimeException("Sheet [" + sheetName + "] 处理失败: " + errorMsg, e); + } + } } } @@ -825,6 +862,9 @@ public class CoDelServiceImpl implements CoDelService { return value.setScale(6, RoundingMode.HALF_UP); // 四舍五入保留四位小数 case STRING: try { + if (cell.getStringCellValue() == null || cell.getStringCellValue().isEmpty()) { + return null; + } BigDecimal stringValue = new BigDecimal(cell.getStringCellValue()); return stringValue.setScale(6, RoundingMode.HALF_UP); // 四舍五入保留四位小数 } catch (NumberFormatException e) {