Browse Source

错误不抛异常,前端显示

java8
han\hanst 3 months ago
parent
commit
682b9e2fb9
  1. 8
      src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java
  2. 93
      src/main/java/com/xujie/sys/modules/ecss/dto/SheetErrorInfo.java
  3. 2
      src/main/java/com/xujie/sys/modules/ecss/service/CoDelService.java
  4. 144
      src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java
  5. 7
      src/main/resources/mapper/ecss/EcssCommonMapper.xml
  6. BIN
      src/main/resources/templates/packing-template.xlsx

8
src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java

@ -62,8 +62,12 @@ public class CoDelController {
@PostMapping("/previewExcel")
public R previewExcel(@RequestParam(value = "file") MultipartFile file, @ModelAttribute EcssCoDelNotifyHeaderData data){
List<Map<String, Object>> previewData = coDelService.previewExcel(file, data);
return R.ok().put("data", previewData);
Map<String, Object> result = coDelService.previewExcel(file, data);
return R.ok()
.put("data", result.get("previewList"))
.put("sheetErrors", result.get("sheetErrors"))
.put("hasErrors", result.get("hasErrors"))
.put("errorCount", result.get("errorCount"));
}
@PostMapping("/saveEcssCoDelNotifyByExcel")

93
src/main/java/com/xujie/sys/modules/ecss/dto/SheetErrorInfo.java

@ -0,0 +1,93 @@
package com.xujie.sys.modules.ecss.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* Sheet错误信息DTO
*
* <p>用于收集Excel导入时各个Sheet的错误信息而不中断整个导入流程</p>
*
* @author System
* @since 2025-01-01
*/
@Data
public class SheetErrorInfo {
/**
* Sheet名称
*/
private String sheetName;
/**
* Sheet索引从0开始
*/
private Integer sheetIndex;
/**
* 错误类型
* SKIP_EMPTY: 跳过空Sheet
* SKIP_NO_CARGO_DATE: 跳过没有Cargo Ready Date列的Sheet
* SKIP_INTERNAL_SALE: 跳过包含内销的Sheet
* MISSING_COLUMNS: 缺少必填列
* INVALID_DATA: 数据验证失败
* PARSE_ERROR: 解析错误
*/
private String errorType;
/**
* 错误描述
*/
private String errorMessage;
/**
* 错误详情列表具体哪些行有错误
*/
private List<String> errorDetails;
/**
* 是否跳过该Sheettrue=跳过false=处理失败
*/
private Boolean skipped;
/**
* 构造方法创建跳过类型的错误信息
*/
public static SheetErrorInfo createSkipped(String sheetName, Integer sheetIndex, String reason) {
SheetErrorInfo error = new SheetErrorInfo();
error.setSheetName(sheetName);
error.setSheetIndex(sheetIndex);
error.setErrorType("SKIP");
error.setErrorMessage(reason);
error.setSkipped(true);
error.setErrorDetails(new ArrayList<>());
return error;
}
/**
* 构造方法创建错误类型的错误信息
*/
public static SheetErrorInfo createError(String sheetName, Integer sheetIndex, String errorType, String errorMessage) {
SheetErrorInfo error = new SheetErrorInfo();
error.setSheetName(sheetName);
error.setSheetIndex(sheetIndex);
error.setErrorType(errorType);
error.setErrorMessage(errorMessage);
error.setSkipped(false);
error.setErrorDetails(new ArrayList<>());
return error;
}
/**
* 添加错误详情
*/
public void addErrorDetail(String detail) {
if (this.errorDetails == null) {
this.errorDetails = new ArrayList<>();
}
this.errorDetails.add(detail);
}
}

2
src/main/java/com/xujie/sys/modules/ecss/service/CoDelService.java

@ -23,7 +23,7 @@ public interface CoDelService {
PageUtils searchEcssCoDelNotifyHeaderForCK(EcssCoDelNotifyHeaderData data);
PageUtils searchEcssCoDelNotifyHeaderForDanZheng(EcssCoDelNotifyHeaderData data);
List<EcssCoDelNotifyDetailData> searchEcssCoDelNotifyDetail(EcssCoDelNotifyHeaderData data);
List<Map<String, Object>> previewExcel(MultipartFile file, EcssCoDelNotifyHeaderData data);
Map<String, Object> previewExcel(MultipartFile file, EcssCoDelNotifyHeaderData data);
Map<String, List<String>> saveEcssCoDelNotifyByExcel(MultipartFile file, EcssCoDelNotifyHeaderData data, String deletedInvoices, HttpServletRequest request);
void updateEcssDelHeader(EcssCoDelNotifyHeaderData data);

144
src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java

@ -14,6 +14,7 @@ import com.aspose.cells.PageOrientationType;
import com.aspose.cells.PaperSizeType;
import com.xujie.sys.modules.attrbute.entity.PropertyModelHeader;
import com.xujie.sys.modules.ecss.data.*;
import com.xujie.sys.modules.ecss.dto.SheetErrorInfo;
import com.xujie.sys.modules.ecss.entity.*;
import com.xujie.sys.modules.ecss.mapper.CoDelMapper;
import com.xujie.sys.modules.ecss.service.CoDelService;
@ -100,14 +101,15 @@ public class CoDelServiceImpl implements CoDelService {
}
@Override
public List<Map<String, Object>> previewExcel(MultipartFile file, EcssCoDelNotifyHeaderData inData) {
public Map<String, Object> previewExcel(MultipartFile file, EcssCoDelNotifyHeaderData inData) {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
String site = coDelMapper.getSiteByBu(inData.getBuNo());
List<EcssCoDelNotifyData> excelList = new ArrayList<>();
List<SheetErrorInfo> sheetErrors = new ArrayList<>();
try (InputStream is = file.getInputStream()) {
XSSFWorkbook workbook = new XSSFWorkbook(is);
importNotifyExcel(inData, workbook, site, currentUser, excelList);
importNotifyExcel(inData, workbook, site, currentUser, excelList, sheetErrors);
} catch (Exception e) {
throw new RuntimeException("文件解析失败:" + e.getMessage());
}
@ -164,7 +166,14 @@ public class CoDelServiceImpl implements CoDelService {
previewList.add(summary);
});
return previewList;
// 构建返回结果包含预览数据和Sheet错误信息
Map<String, Object> result = new HashMap<>();
result.put("previewList", previewList);
result.put("sheetErrors", sheetErrors);
result.put("hasErrors", !sheetErrors.isEmpty());
result.put("errorCount", sheetErrors.size());
return result;
}
@Override
@ -173,10 +182,11 @@ public class CoDelServiceImpl implements CoDelService {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
String site = coDelMapper.getSiteByBu(inData.getBuNo());
List<EcssCoDelNotifyData> excelList = new ArrayList<>();
List<SheetErrorInfo> sheetErrors = new ArrayList<>();
try (InputStream is = file.getInputStream()) {
XSSFWorkbook workbook = new XSSFWorkbook(is);
importNotifyExcel(inData, workbook, site, currentUser, excelList);
importNotifyExcel(inData, workbook, site, currentUser, excelList, sheetErrors);
} catch (NullPointerException e) {
log.error("导入失败:{}", e.getMessage());
throw new RuntimeException("导入失败:网络错误,请重新上传文档");
@ -223,6 +233,27 @@ public class CoDelServiceImpl implements CoDelService {
List<String> successList = new ArrayList<>();
List<String> failList = new ArrayList<>();
// 添加Sheet错误信息到失败列表
for (SheetErrorInfo error : sheetErrors) {
if (error.getSkipped()) {
// 跳过类型的错误作为警告信息
failList.add("Sheet [" + error.getSheetName() + "] 已跳过:" + error.getErrorMessage());
} else {
// 验证失败类型的错误
failList.add("Sheet [" + error.getSheetName() + "] 错误:" + error.getErrorMessage());
if (error.getErrorDetails() != null && !error.getErrorDetails().isEmpty()) {
// 限制显示前5个错误详情
int limit = Math.min(5, error.getErrorDetails().size());
for (int i = 0; i < limit; i++) {
failList.add(" - " + error.getErrorDetails().get(i));
}
if (error.getErrorDetails().size() > 5) {
failList.add(" - ... 还有 " + (error.getErrorDetails().size() - 5) + " 个错误");
}
}
}
}
// 添加物料不存在的发票到失败列表
for (Map.Entry<String, List<String>> entry : invalidMaterialsByInvoice.entrySet()) {
String invoice = entry.getKey();
@ -418,12 +449,24 @@ public class CoDelServiceImpl implements CoDelService {
return columnIndexMap;
}
/**
* 导入通知单Excel
*
* @param inData 输入数据
* @param workbook Excel工作簿
* @param site 站点
* @param currentUser 当前用户
* @param excelList 解析后的数据列表
* @param sheetErrors Sheet错误信息列表收集所有错误
*/
private void importNotifyExcel(EcssCoDelNotifyHeaderData inData, XSSFWorkbook workbook, String site,
SysUserEntity currentUser, List<EcssCoDelNotifyData> excelList) {
SysUserEntity currentUser, List<EcssCoDelNotifyData> excelList,
List<SheetErrorInfo> sheetErrors) {
for (int s = 0; s < workbook.getNumberOfSheets(); s++) {
// 读取工作表
XSSFSheet sheet = workbook.getSheetAt(s);
String sheetName = sheet.getSheetName();
SheetErrorInfo currentSheetError = null; // 当前Sheet的错误信息
try {
// 剔除空行
@ -471,7 +514,11 @@ public class CoDelServiceImpl implements CoDelService {
}
if (!missingColumns.isEmpty()) {
throw new RuntimeException("Sheet [" + sheetName + "] 表头缺少必填列: " + String.join(", ", missingColumns));
currentSheetError = SheetErrorInfo.createError(sheetName, s, "MISSING_COLUMNS",
"表头缺少必填列: " + String.join(", ", missingColumns));
sheetErrors.add(currentSheetError);
log.error("Sheet [{}] 表头缺少必填列,跳过该Sheet", sheetName);
continue; // 不抛异常记录错误后跳过
}
// 扫描整个 sheet如果发现"内销"则跳过该 sheet
@ -511,6 +558,19 @@ public class CoDelServiceImpl implements CoDelService {
continue;
}
// 创建当前Sheet的错误收集器如果还没创建的话
if (currentSheetError == null) {
currentSheetError = new SheetErrorInfo();
currentSheetError.setSheetName(sheetName);
currentSheetError.setSheetIndex(s);
currentSheetError.setErrorType("INVALID_DATA");
currentSheetError.setErrorMessage("数据验证失败");
currentSheetError.setSkipped(false);
currentSheetError.setErrorDetails(new ArrayList<>());
}
boolean hasRowError = false; // 标记当前Sheet是否有行错误
// 遍历每一行从第四行开始即索引3
for (int j = 3; j < rows; j++) {
// 获得该行
@ -535,40 +595,53 @@ public class CoDelServiceImpl implements CoDelService {
}
// 必填字段验证 - Cargo Ready Date已经在上面检查过了
Integer poIdx = columnMap.get("PO#");
if (row.getCell(poIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [PO#] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [PO#] 列不能为空");
hasRowError = true;
continue; // 跳过这一行继续处理下一行
}
Integer pnIdx = columnMap.get("PN");
if (row.getCell(pnIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [PN] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [PN] 列不能为空");
hasRowError = true;
continue;
}
Integer qtyIdx = columnMap.get("Qty (pcs)");
if (row.getCell(qtyIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Qty (pcs)] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [Qty (pcs)] 列不能为空");
hasRowError = true;
continue;
}
Integer destinationIdx = columnMap.get("Destination");
if (row.getCell(destinationIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Destination] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [Destination] 列不能为空");
hasRowError = true;
continue;
}
Integer shippingModeIdx = columnMap.get("Shipping Mode");
if (row.getCell(shippingModeIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Shipping Mode] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [Shipping Mode] 列不能为空");
hasRowError = true;
continue;
}
Integer currencyIdx = columnMap.get("Currency");
if (row.getCell(currencyIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Currency] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [Currency] 列不能为空");
hasRowError = true;
continue;
}
Integer tpIdx = columnMap.get("TP");
if (row.getCell(tpIdx) == null) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [TP] 列不能为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [TP] 列不能为空");
hasRowError = true;
continue;
}
// 创建对象并为对象赋值
@ -583,7 +656,9 @@ 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("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [Cargo Ready Date] 列格式有误! " + e.getMessage());
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [Cargo Ready Date] 列格式有误: " + e.getMessage());
hasRowError = true;
continue;
}
task.setReadyDate(readDate);
@ -606,7 +681,9 @@ public class CoDelServiceImpl implements CoDelService {
boolean isShippingNumberValid = isValidCellValue(shippingNumberValue);
if (!isCmcInvoiceValid && !isShippingNumberValid) {
throw new RuntimeException("Sheet [" + sheetName + "] 第" + (j+1) + "行的 [CMC Invoice] 和 [Shipping Number] 列不能同时为空!");
currentSheetError.addErrorDetail("第" + (j+1) + "行的 [CMC Invoice] 和 [Shipping Number] 列不能同时为空");
hasRowError = true;
continue;
}
// 如果CMC Invoice无效/0/错误/超过20位则使用Shipping Number
@ -666,18 +743,25 @@ public class CoDelServiceImpl implements CoDelService {
excelList.add(task);
}
// 在Sheet处理结束时如果有行错误添加到错误列表
if (hasRowError && currentSheetError != null) {
sheetErrors.add(currentSheetError);
log.error("Sheet [{}] 处理完成,发现 {} 个数据错误", sheetName, currentSheetError.getErrorDetails().size());
}
} 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);
}
SheetErrorInfo errorInfo = SheetErrorInfo.createError(sheetName, s, "PARSE_ERROR",
"Sheet解析失败: " + (errorMsg != null ? errorMsg : e.getClass().getSimpleName()));
sheetErrors.add(errorInfo);
log.error("Sheet [{}] 处理异常: {}", sheetName, errorMsg, e);
// 继续处理下一个Sheet
}
}
// 汇总日志
log.info("=== Excel导入完成 === 成功处理 {} 条数据,发现 {} 个Sheet存在问题", excelList.size(), sheetErrors.size());
}
public static LocalDate parseDateCell(Cell cell) {
@ -1106,12 +1190,22 @@ public class CoDelServiceImpl implements CoDelService {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
String site = coDelMapper.getSiteByBu(inData.getBuNo());
List<EcssCoDelNotifyData> excelList = new ArrayList<>();
List<SheetErrorInfo> sheetErrors = new ArrayList<>();
try {
// 转流
InputStream is = file.getInputStream();
// 读取工作簿
XSSFWorkbook workbook = new XSSFWorkbook(is);
importNotifyExcel(inData, workbook, site, currentUser, excelList);
importNotifyExcel(inData, workbook, site, currentUser, excelList, sheetErrors);
// 如果有Sheet错误抛出异常提示用户
if (!sheetErrors.isEmpty()) {
StringBuilder errorMsg = new StringBuilder("以下Sheet存在问题:\n");
for (SheetErrorInfo error : sheetErrors) {
errorMsg.append("Sheet [").append(error.getSheetName()).append("]: ").append(error.getErrorMessage()).append("\n");
}
throw new RuntimeException(errorMsg.toString());
}
} catch (NullPointerException e) {
throw new RuntimeException("导入失败:网络错误,请重新上传文档");
} catch (Exception e) {

7
src/main/resources/mapper/ecss/EcssCommonMapper.xml

@ -33,7 +33,8 @@
<select id="searchEcssCoDelNotifyDetail" resultType="java.util.Map">
select a.*,#{cmcInvoice} as cmcInvoice,#{shippingMode} as shippingMode,#{destination} as destination,
CONVERT(varchar(10), #{readyDate}, 120) AS readyDate
CONVERT(varchar(10), #{readyDate}, 120) AS readyDate,a.salesOrder as salesOrder,
CASE WHEN a.modifyFlag = 1 THEN '是' ELSE '否' END AS modifyFlagString
from ecss_CoDelNotifydetail a
<where>
And a.site = #{site}
@ -43,11 +44,11 @@
</select>
<select id="searchCoDelPalletData" resultType="java.util.Map">
select b.po_no as customerPO,b.part_no,b.qty,
select c.salesOrder as salesOrder,b.po_no as customerPO,b.part_no,b.qty,
a.box_qty as boxQty,b.rolls,b.pn,a.gross_weight as grossWeight,a.net_weight as netWeight,
#{cmcInvoice} as cmcInvoice,#{shippingMode} as shippingMode,#{destination} as destination,
c.cmc_comment,CONVERT(varchar(10), #{readyDate}, 120) AS readyDate,
CASE WHEN c.modifyFlag = 1 THEN '是' ELSE '否' END AS modifyFlag
CASE WHEN c.modifyFlag = 1 THEN '是' ELSE '否' END AS modifyFlagString
from ecss_CoDelBoxList a
left join ecss_CoDelPalletDetail b on a.site=b.site and a.bu_no=b.bu_no and a.delNo=b.delNo and a.item_no=b.seq_no
left join ecss_CoDelNotifydetail c on b.site=c.site and b.bu_no=c.bu_no and b.delNo=c.delNo and b.notify_detail_item_no=c.item_no

BIN
src/main/resources/templates/packing-template.xlsx

Loading…
Cancel
Save