当前位置: 首页 > news >正文

Easy-excel监听器中对批量上传的工单做错误收集

Easy-excel监听器中对批量上传的工单做错误收集

为什么要做"错误收集"?

1.监听器中将错误信息收集到errorMessages集合

@Slf4j
public class WorkOrderInfoListener implements ReadListener<WorkOrderInfoVo> {// 错误信息收集private final List<String> errorMessages = new ArrayList<>();// 合同名称列表private final List<String> contractNames;private final Set<String> faultLocationList;// 服务依赖由外部传入private final IWorkOrderInfoService workOrderInfoService;private final IContractInfoService contractInfoService;/*** 构造函数传入 service,并初始化合同名称*/public WorkOrderInfoListener(IWorkOrderInfoService workOrderInfoService,IContractInfoService contractInfoService) {this.workOrderInfoService = workOrderInfoService;this.contractInfoService = contractInfoService;this.contractNames = loadContractNames();this.faultLocationList = workOrderInfoService.getFaultLocationList(null);}private List<String> loadContractNames() {List<ContractSelectVo> contractSelectVoList = contractInfoService.getNames();return contractSelectVoList.stream().map(ContractSelectVo::getContractName).toList();}@Overridepublic void invoke(WorkOrderInfoVo workOrderInfoVo, AnalysisContext analysisContext) {try {WorkOrderInfo info = new WorkOrderInfo();BeanUtils.copyProperties(workOrderInfoVo, info, "id");String contractName = info.getContractName();if (StringUtils.isBlank(contractName)) {int rowNum = analysisContext.readRowHolder().getRowIndex();String errorMsg = String.format("第 %d 行数据导入失败:合同名称为空 故障地点: %s",rowNum, workOrderInfoVo.getFaultLocation());errorMessages.add(errorMsg);return;}if (!contractNames.contains(contractName)) {int rowNum = analysisContext.readRowHolder().getRowIndex();String errorMsg = String.format("第 %d 行数据导入失败:合同名称不存在:%s 故障地点: %s",rowNum, contractName, workOrderInfoVo.getFaultLocation());errorMessages.add(errorMsg);return;}// 不允许重复点位上报if (faultLocationList.contains(info.getFaultLocation())) {int rowNum = analysisContext.readRowHolder().getRowIndex();String errorMsg = String.format("第 %d 行数据导入失败:该点位正在维修 故障地点: %s",rowNum, workOrderInfoVo.getFaultLocation());errorMessages.add(errorMsg);return;}String unit = contractInfoService.getIoCompany(contractName);if (unit != null) {info.setMaintenanceUnit(unit);}info.setRepairTime(new Date());WorkOrderInfoBo convert = BeanUtil.copyProperties(info, WorkOrderInfoBo.class);workOrderInfoService.insertByExcel(convert);} catch (Exception e) {int rowNum = analysisContext.readRowHolder().getRowIndex();String errorMsg = String.format("第 %d 行数据导入失败:系统异常 - %s 故障地点: %s",rowNum, e.getMessage(), workOrderInfoVo.getFaultLocation());errorMessages.add(errorMsg);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 所有数据处理完成,无需特殊操作}/*** 获取所有错误信息*/public List<String> getErrorMessages() {return Collections.unmodifiableList(errorMessages);}/*** 是否存在错误*/public boolean hasErrors() {return !errorMessages.isEmpty();}/*** 清空错误信息*/public void clearErrors() {errorMessages.clear();}
}

2.控制层设置返回逻辑

如果错误信息存在则返回错误信息给前端展示,比如总共20条数据如果 第2 第14条数据上报时出了问题不会影响其余的18条数据的导入,而是将错误的详细信息返回给用户看

    @PostMapping("/uploadWorkOrderInfo")public R<List<String>> uploadWorkOrderInfo(MultipartFile file, HttpServletResponse response) throws IOException {long t1 = System.currentTimeMillis();// TODO 文件校验WorkOrderInfoListener listener = new WorkOrderInfoListener(workOrderInfoService, contractInfoService);try {// 开始读取 Excel 文件EasyExcel.read(file.getInputStream(), WorkOrderInfoVo.class, listener).sheet().doRead();List<String> errorMessages = listener.getErrorMessages();// ✅ 提前检查错误信息,存在则汇总返回给前端if (CollectionUtil.isNotEmpty(errorMessages)) {// 返回错误信息列表return R.ok("部分数据导入失败", errorMessages);}// ⬇️只有在没有错误的情况下才执行以下内容long t2 = System.currentTimeMillis();String message = "导入全部数据成功! 共用时:"+(t2-t1)+"ms";List<String> successMessages = new ArrayList<>();successMessages.add(message);return R.ok(message,successMessages);} catch (Exception e) {log.error("文件导入失败: ", e);return R.fail("文件导入失败: " + e.getMessage());}}

3.前端效果展示

如果存在插入失败的情况

image-20250703093842216

http://www.lryc.cn/news/579468.html

相关文章:

  • Redisson使用示例
  • 请求未达服务端?iOS端HTTPS链路异常的多工具抓包排查记录
  • 【Bug Recod】更新中...
  • Day50
  • 一文详解Character AI:实用指南+ ChatGPT、Gemini对比分析
  • contenteditable网页富文本编辑无法选中图片
  • Swift 的基础设计哲学是 “通过模块化组合实现安全与效率的平衡“,就像用标准化工业零件建造摩天大楼
  • 一台香港原生ip站群服务器多少钱?
  • 如何在Ubuntu上检查MySQL是否启动并放开3306端口
  • C++笔记-位图和布隆过滤器
  • P1155 [NOIP 2008 提高组] 双栈排序
  • 李宏毅机器学习笔记——梯度下降法
  • 映射阿里云OSS(对象存储服务)
  • 百度文心智能体平台x小米应用商店:联手打造行业首个智能体与应用市场跨端分发模式
  • webrtc-streamer视频流播放(rstp协议h264笔记)
  • KDD 2025 | 地理定位中的群体智能:一个多智能体大型视觉语言模型协同框架
  • Go应用容器化完全指南:构建最小化安全镜像的终极实践
  • I/O 线程 7.3
  • VTK中自定义双组分输入最大值滤波
  • 基于spark的北京房价数据分析及价格预测
  • npm 命令入门指南(前端小白版)
  • 以太坊 Legacy 交易和 EIP-1559 交易
  • C++ 标准模板库算法之 transform 用法
  • RAG从入门到高阶(二):Retrieve-and-Rerank
  • 开源无广告面板mdserver-web:替代宝塔实现服务器轻松管理
  • NCCL的基本使用和常用通信算法源码分析
  • 洛谷-循环结构(1)
  • 前端框架中注释占位与Fragment内容替换的实现与优化
  • 网络基础(3)
  • Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南