EasyExcel导入合并单元格数据

1.EasyExcel.read 方法

这里在read的时候要注意,增加这个extraRead(CellExtraTypeEnum.MERGE)来解析合并单元格的信息

 ImportListener listener = new ImportListener();try {EasyExcel.read(file.getInputStream(), ImportDto.class, listener).headRowNumber(1).extraRead(CellExtraTypeEnum.MERGE).ignoreEmptyRow(true).sheet().doRead();} catch (IOException e) {log.error("importAccountExcel-----EasyExcel.read-----error:", e);throw new Exception(ResponseEnum.FAILURE.getCode(), e.getMessage());}List<ImportDto> dataList = listener.getDataList();if (CollectionUtils.isEmpty(dataList)) {throw new Exception(ResponseEnum.FAILURE.getCode(), "导入文件失败,获取数据为空");}

2.Listener解析方法

在invok解析完所有数据以后,先将所有解析的数据存储在tempDataList中,此时合并单元格是没数据的。

然后经过convertDataMapToData方法处理完合并单元格数据后,最后才得到完整的单元格数据
 

@Getter
@Slf4j
public class ImportListener implements ReadListener<ImportDto> {private final static String[] excelTitle = {"日期", "姓名", "银行账号", "开户行", "证件号", "电话号码", "金额", "期数"};private final List<ImportDto> dataList = ListUtils.newArrayList();private final List<String> excelTitleList = Arrays.asList(excelTitle);/*** 正文起始行*/private Integer headRowNumber = 1;/*** 解析的临时数据*/private List<ImportDto> tempDataList = new ArrayList<>();/*** 合并单元格数据*/private List<CellExtra> mergeList = new ArrayList<>();@Overridepublic void invoke(ImportDto data, AnalysisContext context) {
//        log.info("解析到一条数据:{}", JSON.toJSONString(data));checkData(data, context);
//        dataList.add(data);tempDataList.add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {log.info("导入文件-所有数据记录:{}", JSON.toJSONString(dataList));// 在invok解析完数据以后,才去处理合并单元格数据,最后得到合并完以后的数据convertDataMapToData();log.info("导入文件-所有数据解析完成!");}@Overridepublic void onException(Exception exception, AnalysisContext context) {log.info("解析失败,但是继续解析下一行:{}", exception.getMessage());// 如果是某一个单元格的转换异常 能获取到具体行号if (exception instanceof ExcelDataConvertException) {ExcelDataConvertException dataException = (ExcelDataConvertException) exception;String errData = CellDataTypeEnum.STRING.equals(dataException.getCellData().getType()) ? dataException.getCellData().getStringValue() : dataException.getCellData().getNumberValue().toPlainString();log.warn("第{}行,第{}列解析异常,数据为:{}", dataException.getRowIndex(), dataException.getColumnIndex(),errData);String errorMsg = "第" +dataException.getRowIndex() +"行,第" +dataException.getColumnIndex() +"列解析异常,数据为:" +errData;throw new BaseException(ResponseEnum.FAILURE.getCode(), errorMsg);} else {log.error("文件校验失败:", exception);if (exception instanceof BaseException) {BaseException base = (BaseException) exception;if (StringUtils.isNotBlank(base.getErrorMsg())) {throw new BaseException(ResponseEnum.FAILURE.getCode(), base.getErrorMsg());}throw new BaseException(ResponseEnum.FAILURE.getCode(), "获取异常出错");} else {throw new BaseException(ResponseEnum.FAILURE.getCode(), "获取异常出错");}}}@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {if (CollectionUtils.isEmpty(headMap)) {throw new BaseException(ResponseEnum.FAILURE.getCode(), "excel表头不能为空");}headMap.forEach((i, readCellData) -> {readCellData.checkEmpty();if (CellDataTypeEnum.EMPTY.equals(readCellData.getType())) {return;}if (!excelTitleList.contains(readCellData.getStringValue())) {throw new BaseException(ResponseEnum.FAILURE.getCode(), "第" + (i + 1) + "列Excel文件表头有误");}});}//上面写入的CellExtraTypeEnum.MERGE就会来调用这个方法@Overridepublic void extra(CellExtra extra, AnalysisContext context) {switch (extra.getType()) {case MERGE: // 额外信息是合并单元格if (extra.getRowIndex() >= headRowNumber) {mergeList.add(extra); // 保存合并单元格信息}break;case COMMENT:case HYPERLINK:default:}}/*** 将具有多个sheet数据的dataMap转变成一个data*/private void convertDataMapToData() {if (!CollectionUtils.isEmpty(mergeList)) {tempDataList = explainMergeData(tempDataList, mergeList);}dataList.addAll(tempDataList);}/*** 处理有合并单元格的数据** @param list      解析的sheet数据* @param mergeList 合并单元格信息* @return 填充好的解析数据*/private List<ImportDto> explainMergeData(List<ImportDto> list, List<CellExtra> mergeList) {// 循环所有合并单元格信息for (CellExtra item : mergeList) {Integer firstRowIndex = item.getFirstRowIndex() - headRowNumber; // 起始行Integer lastRowIndex = item.getLastRowIndex() - headRowNumber; // 结束行Integer firstColumnIndex = item.getFirstColumnIndex(); // 起始列Integer lastColumnIndex = item.getLastColumnIndex(); // 结束列// 获取初始值,即合并单元的的值Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, list);// 设置值for (int i = firstRowIndex; i <= lastRowIndex; i++) {for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {setInitValueToList(initValue, i, j, list);}}}return list;}/*** 获取合并单元格的初始值* rowIndex对应list的索引* columnIndex对应实体内的字段** @param firstRowIndex    起始行* @param firstColumnIndex 起始列* @param list             列数据* @return 初始值*/private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<ImportDto> list) {Object filedValue = null;ImportDto object = list.get(firstRowIndex);for (Field field : object.getClass().getDeclaredFields()) {field.setAccessible(true);ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);if (annotation != null) {if (annotation.index() == firstColumnIndex) {try {filedValue = field.get(object);break;} catch (IllegalAccessException e) {log.error("获取合并单元格的初始值异常:" + e.getMessage());}}}}return filedValue;}/*** 设置合并单元格的值** @param filedValue  值* @param rowIndex    行* @param columnIndex 列* @param list        解析数据*/public void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<ImportDto> list) {ImportDto object = list.get(rowIndex);//for (Field field : object.getClass().getDeclaredFields()) {field.setAccessible(true); // 提升反射性能,关闭安全检查ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);if (annotation != null) {if (annotation.index() == columnIndex) {try {field.set(object, filedValue);break;} catch (IllegalAccessException e) {log.error("设置合并单元格的值异常:" + e.getMessage());}}}}}
}
3.导入的DTO,这里要注意index,要设置值
@Data
public class ImportDto implements Serializable {@ExcelProperty(value = "日期", converter = CustomDateConverter.class, index = 0)private Date putoutDate;@ExcelProperty(value ="姓名", index = 1)private String name;@ExcelProperty(value = "银行账号", index = 2)private String bankNo;@ExcelProperty(value = "开户行", index = 3)private String bankAddress;@ExcelProperty(value = "证件号", index = 4)private String idNum;@ExcelProperty(value = "电话号码", index = 5)private String cellPhone;@ExcelProperty(value = "金额", index = 6)private BigDecimal limit;
}

easyexcel导入合并单元格解析(纵向合并,横向合并都支持)_easyexcel解析合并单元格-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/37571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL进阶:视图

视图 1. 创建视图2. 更改或删除视图3. 更新视图4. WITH OPTION CHECK子句5. 视图特点 1. 创建视图 作用&#xff1a;就是创建虚拟表&#xff0c;自动化一些重复性的查询模块&#xff0c;简化各种复杂操作&#xff08;包括复杂的子查询和连接等&#xff09;。 注意视图虽然可以…

【算法专题--链表】两数相加 -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐双指针 -- 模拟进位 (使用哨兵位头节点) &#x1f95d; 什么是哨兵位头节点&#xff1f; &#x1f347;思路解析 &#x1f34d;案例图解 四、总结与提炼 五、共勉 一、前言 两数相加 这道题&#xff0c;可以说是--…

SpringCloud Alibaba Seata2.0分布式事务AT模式实践总结

这里我们划分订单、库存与支付三个module来实践Seata的分布式事务。 依赖版本(jdk17)&#xff1a; <spring.boot.version>3.1.7</spring.boot.version> <spring.cloud.version>2022.0.4</spring.cloud.version> <spring.cloud.alibaba.version>…

简单说下GPT-4

ChatGPT 4.0&#xff0c;是OpenAI开发的基于GPT-4架构的大型语言模型。它在多个方面相较于前代版本有了显著的改进。以下是从专业角度对ChatGPT 4.0的详解&#xff1a; 架构与训练 1. **架构**&#xff1a;GPT-4采用的是变压器&#xff08;Transformer&#xff09;架构&#x…

计算机监控软件有哪些?10款常年霸榜的计算机监控软件

计算机监控软件是企业管理和保护信息安全的重要工具&#xff0c;它们帮助企业管理者监督员工的计算机使用行为&#xff0c;确保工作效率、数据安全以及合规性。在众多监控软件中&#xff0c;有些产品因其卓越的功能、易用性、安全性以及持续获得的良好市场反馈而常年占据行业领…

C++——探索智能指针的设计原理

前言: RAII是资源获得即初始化&#xff0c; 是一种利用对象生命周期来控制程序资源地手段。 智能指针是在对象构造时获取资源&#xff0c; 并且在对象的声明周期内控制资源&#xff0c; 最后在对象析构的时候释放资源。注意&#xff0c; 本篇文章参考——C 智能指针 - 全部用法…

IBCS 虚拟专线——让企业用于独立IP

在当今竞争激烈的商业世界中&#xff0c;企业的数字化运营对网络和服务器的性能有着极高的要求。作为一家企业的 IT 主管&#xff0c;我深刻体会到了在网络和服务器配置方面所面临的种种挑战&#xff0c;以及 IBCS 虚拟专线带来的革命性改变。 我们企业在业务扩张的过程中&…

msvcr120.dll文件下载的高级教程,修复msvcr120.dll 详细步骤分享

当电脑系统或特定应用程序无法找到或访问到msvcr120.dll文件时&#xff0c;便会导致错误消息的出现&#xff0c;例如“找不到 msvcr120.dll”、“msvcr120.dll丢失”等。这篇文章将大家讨论关于msvcr120.dll文件的内容、msvcr120.dll丢失问题的解决方法&#xff0c;其中最常见的…

Postman接口测试工具的原理及应用详解(一)

本系列文章简介&#xff1a; 在当今软件开发的世界中&#xff0c;接口测试作为保证软件质量的重要一环&#xff0c;其重要性不言而喻。随着前后端分离开发模式的普及&#xff0c;接口测试已成为连接前后端开发的桥梁&#xff0c;确保前后端之间的数据交互准确无误。在这样的背景…

web使用cordova打包Andriod

一.安装Gradel 1.下载地址 Gradle Distributions 2.配置环境 3.测试是否安装成功 在cmd gradle -v 二.创建vite项目 npm init vitelatest npm install vite build 三.创建cordova项目 1.全局安装cordova npm install -g cordova 2. 创建项目 cordova create cordova-app c…

【扩散模型应用方向】

参考&#xff1a;CVPR 2024 | 绝了&#xff01;&#xff01;最新 diffusion 扩散模型梳理&#xff01;100篇论文、40研究方向&#xff01; 扩散模型应用方向目录 1、扩散模型改进 2、可控文生图 3、风格迁移 4、人像生成 5、图像超分 6、图像恢复 7、目标跟踪 8、目标检…

VuePress日常使用

本篇来讲解下更多关于 VuePress 的基本用法 ‍ 配置首页 现在的页面太简单了&#xff0c;我们可以对项目首页进行配置&#xff0c;修改 docs/README.md &#xff08;这些配置是什么后面会说&#xff09;&#xff1a; --- home: true heroImage: https://s3.bmp.ovh/imgs/20…

Mac可以读取NTFS吗 Mac NTFS软件哪个好 mac ntfs读写工具免费

在跨操作系统环境下使用外部存储设备时&#xff0c;特别是当Windows系统的U盘被连接到Mac电脑时&#xff0c;常常会遇到文件系统兼容性的问题。由于Mac OS原生并不完全支持对NTFS格式磁盘的读写操作&#xff0c;导致用户无法直接在Mac上向NTFS格式的U盘或硬盘写入数据。下面我们…

Scala入门学习

Scala是一种现代化的多范式编程语言&#xff0c;它结合了面向对象编程和函数式编程的特点&#xff0c;运行在Java平台上。Scala的语法简洁&#xff0c;同时提供了强大的类型系统和丰富的库支持。下面是一些Scala入门的基础知识点&#xff1a; ### 1. 安装Scala - 下载并安装Sc…

详细分析JVM的底层原理及语法分析,JVM如何进行精细化的调优?小白进阶必读精品

Java虚拟机&#xff08;Java Virtual Machine&#xff0c;简称JVM&#xff09;是Java程序运行的基础&#xff0c;它提供了一个运行Java字节码的环境。JVM的底层原理涉及多方面的内容&#xff0c;包括类加载、字节码执行、内存管理、垃圾回收、即时编译&#xff08;JIT&#xff…

句柄数详解

目录 一. 什么是句柄二. 句柄书🟰文件打开数?三. 常用查看命令1. 查看当前系统中打开的文件数量(即文件句柄数)1)全局查看2)当前会话2. /proc/sys/fs/file-nr查看系统句柄数配置3. /proc/sys/fs/file-max查看系统支持的最大句柄数4. 显示当前会话中允许的最大句柄数量四…

揭示隐藏的模式:秩和检验和单因素方差分析的实战指南【考题】

1.研究一种新方法对于某实验结果准确性提高的效果&#xff0c;并将其与原有方法进行比较&#xff0c;结果见下表&#xff0c;请评价两者是否有不同? (行无序&#xff0c;列有序)-->单方向有序-->两独立样本的秩和检验) 如下图所示&#xff0c;先将相关数据导入spss。 图…

C# Modbus设备信息加载的实现方式(1)

Modbus设备信息加载的实现方式有很多种&#xff0c;这里讨论一种实现&#xff0c;思路比代码重要&#xff0c;具体类大家可以按自己的要求构建。 Load窗体事件中&#xff1a; GlobalProperties.Device LoadDevice(GroupPath, DevicePath, VariablePath); 具体的实现为&…

什么是指令微调(LLM)

经过大规模数据预训练后的语言模型已经具备较强的模型能力&#xff0c;能够编码丰富的世界知识&#xff0c;但是由于预训练任务形式所限&#xff0c;这些模型更擅长于文本补全&#xff0c;并不适合直接解决具体的任务。 指令微调是相对“预训练”来讲的&#xff0c;预训练的时…

SpringBoot3基础用法

技术和工具「!喜新厌旧」 一、背景 最近在一个轻量级的服务中&#xff0c;尝试了最新的技术和工具选型&#xff1b; 即SpringBoot3&#xff0c;JDK17&#xff0c;IDEA2023&#xff0c;Navicat16&#xff0c;虽然新的技术和工具都更加强大和高效&#xff0c;但是适应采坑的过程…