easyExcel 不规则模板导入数据

文章目录

  • 前言
  • 一、需求和效果
  • 二、难点和思路
  • 三、全部代码
  • 踩坑


前言

之前分享的 EasyExcel 批量导入并校验数据,仅支持规则excel,即首行表头,下面对应数据,无合并单元格情况。
本篇主要解决问题:

  1. 模板excel 表头不在首行
  2. 数据项有合并单元格情况

esayexcel版本2.2.7

一、需求和效果

在这里插入图片描述
在这里插入图片描述

二、难点和思路

  1. 跳过表头前的说明

    设置headRowNumber指定表头位置,第三行

EasyExcel.read(inputStream, EvalTemplateReq.class,listener).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(3).doRead();
  1. 合并单元格数据获取放入list
    合并单元格的数据默认是在合并表格的左上第一个格子,其他为null,获取到这个格子的数据,赋值给其他被合并单元格对应的字段中

3.1 开启合并单元格识别
extraRead(CellExtraTypeEnum.MERGE)开启合并单元格识别
3.2 获取合并的单元格数据
EvalExcelDataListener 重写extra方法,获取到被合并的数据,后续处理。extra方法在invoke方法执行,先不要在意要导入的list部分字段是null,后续重新赋值即可。
extra会从excel头读取,所以要把前2行的数据过滤掉,这里用extra.getFirstRowIndex()>2判断一下

    // 合并单元格private final List<CellExtra> extraMergeInfoList = new ArrayList<>();@Overridepublic void extra(CellExtra extra, AnalysisContext context) {if (extra.getType() == CellExtraTypeEnum.MERGE) {// 处理合并单元格的情况int firstRowIndex = extra.getFirstRowIndex();if(firstRowIndex>2) {extraMergeInfoList.add(extra);}}}

3.3 doAfterAllAnalysed中补全list字段值

    @Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//所有数据解析完毕执行该方法// 防止导入空的Excelif (context.readRowHolder().getRowIndex() <= 0) {throw new ExcelAnalysisException("当前excel无数据!");}//处理合并单元格list = EasyExcelMergeUtil.explainMergeData(list, extraMergeInfoList, 3);saveData();}

3.4 explainMergeData 补全字段值
根据单元格左上角标通过反射获取字段并赋值给其他被合并的单元格,角标对应实体类index属性

三、全部代码

  1. 接收数据实体
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.validation.constraints.NotBlank;
import java.util.List;/*** 评估标准*/
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EvalTemplateReq {@ExcelIgnoreprivate String id;/*** 评估项*/@ExcelProperty(value = "评估名称",index = 1)@NotBlank(message = "评估名称不能为空")private String item;/*** 指标简称*/@ExcelProperty(value = "指标简称",index =2)@NotBlank(message = "指标简称不能为空")private String itemShortName;/*** 指标编码*/@ExcelProperty(value = "指标编码",index = 3)@NotBlank(message = "指标编码不能为空")private String itemCode;/*** 指标释义*/@ExcelProperty(value = "指标释义",index = 4)@NotBlank(message = "指标释义不能为空")private String itemExplain;/*** 评价要求/分数 json*/@ExcelIgnoreprivate List<Requirements> requirementList;/*** 系统监测类/参演部门上报类*/@ExcelProperty(value = "分类",index = 0)@NotBlank(message = "分类不能为空")private String type;@ExcelProperty(value = "评价要求",index = 5)@JsonIgnoreprivate String require;@ExcelProperty(value = "分数",index = 6)@JsonIgnoreprivate Integer score;@Builder@Data@AllArgsConstructor@NoArgsConstructorpublic static class Requirements {@ExcelIgnoreprivate String id;/*** 评价内容*/@NotBlank(message = "评价要求不能为空")private String require;/*** 分数*/@NotBlank(message = "分数不能为空")private Integer score;}
}
  1. service调用
    /*** 导入评估标准*/@Overridepublic String importEval(MultipartFile file) {EvalExcelDataListener listener = new EvalExcelDataListener(evalTemplateDao);InputStream inputStream;try {inputStream = file.getInputStream();EasyExcel.read(inputStream, EvalTemplateReq.class,listener).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(3).doRead();return "全部导入成功!";} catch (IOException e) {throw new BusinessCheckException("Excel 文件流读取失败");} catch (ExcelAnalysisException e) {return e.getMessage();} catch (Exception e) {throw new BusinessException("数据导入失败", e);}}
  1. 合并单元格数据处理util
package com.gsafety.bg.pd.service.excel;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.CellExtra;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;
import java.util.List;@Slf4j
public class EasyExcelMergeUtil {/*** 处理合并单元格* @param data               解析数据* @param extraMergeInfoList 合并单元格信息* @param headRowNumber      起始行* @return 填充好的解析数据*/public static <T> List<T> explainMergeData(List<T> data, List<CellExtra> extraMergeInfoList, Integer headRowNumber) {// 循环所有合并单元格信息extraMergeInfoList.forEach(cellExtra -> {int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNumber;int lastRowIndex = cellExtra.getLastRowIndex() - headRowNumber;int firstColumnIndex = cellExtra.getFirstColumnIndex();int lastColumnIndex = cellExtra.getLastColumnIndex();// 获取初始值Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, data);// 设置值for (int i = firstRowIndex; i <= lastRowIndex; i++) {for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {setInitValueToList(initValue, i, j, data);}}});return data;}/*** 设置合并单元格的值** @param filedValue  值* @param rowIndex    行* @param columnIndex 列* @param data        解析数据*/private static <T> void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<T> data) {if (rowIndex >= data.size()) return;T object = data.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());}}}}}/*** 获取合并单元格的初始值* rowIndex对应list的索引* columnIndex对应实体内的字段** @param firstRowIndex    起始行* @param firstColumnIndex 起始列* @param data             列数据* @return 初始值*/private static <T> Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<T> data) {Object filedValue = null;T object = data.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;}}
  1. easyexcel数据监听类
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellExtra;
import com.gsafety.bg.gsdss.common.utils.json.JsonUtil;
import com.gsafety.bg.pd.dao.EvalTemplateDao;
import com.gsafety.bg.pd.model.dto.req.EvalTemplateReq;
import com.gsafety.bg.pd.model.po.EvalTemplatePO;import java.util.*;
import java.util.stream.Collectors;public class EvalExcelDataListener extends AnalysisEventListener<EvalTemplateReq> {private final Integer LIST_COUNT = 19;List<EvalTemplateReq> list = new ArrayList<>(LIST_COUNT);// 合并单元格private final List<CellExtra> extraMergeInfoList = new ArrayList<>();// 由于监听器只能通过new的方式创建,所以可以通过构造器传入dao层对象private final EvalTemplateDao dao;public EvalExcelDataListener(EvalTemplateDao dao) {this.dao = dao;}@Overridepublic void invoke(EvalTemplateReq req, AnalysisContext context) {list.add(req);if (list.size() > LIST_COUNT) {throw new ExcelAnalysisException("当前excel数据量不得大于" + LIST_COUNT + "条!");}}@Overridepublic void extra(CellExtra extra, AnalysisContext context) {if (extra.getType() == CellExtraTypeEnum.MERGE) {// 处理合并单元格的情况int firstRowIndex = extra.getFirstRowIndex();if(firstRowIndex>2) {extraMergeInfoList.add(extra);}}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//所有数据解析完毕执行该方法// 防止导入空的Excelif (context.readRowHolder().getRowIndex() <= 0) {throw new ExcelAnalysisException("当前excel无数据!");}//处理合并单元格list = EasyExcelMergeUtil.explainMergeData(list, extraMergeInfoList, 3);saveData();}protected void saveData() {Map<String, List<EvalTemplateReq>> collect = list.stream().collect(Collectors.groupingBy(EvalTemplateReq::getItem));List<EvalTemplatePO> pos = new ArrayList<>();collect.forEach((k, v) -> {List<EvalTemplateReq.Requirements> requirements = v.stream().map(l -> EvalTemplateReq.Requirements.builder().id(v.indexOf(l) + "").require(l.getRequire()).score(l.getScore()).build()).collect(Collectors.toList());pos.add(EvalTemplatePO.builder().item(k).itemCode(collect.get(k).get(0).getItemCode()).itemExplain(collect.get(k).get(0).getItemExplain()).itemShortName(collect.get(k).get(0).getItemShortName()).type(collect.get(k).get(0).getType()).requirements(JsonUtil.of(requirements)).build());});dao.deleteAll();dao.saveAll(pos);}
}

踩坑

  1. extra方法不生效
    extraRead(CellExtraTypeEnum.MERGE)显式指定识别合并单元格数据
    invoke中原校验数据,因为为null导致拦截,不走extra方法。
    执行顺序:invoke->extra->doAfterAllAnalysed
  2. 指定表头位置后extra获取的第一个数据还是首行的合并单元格数据
    headRowNumber(3)只是指定了读取表头的位置,extra是获取整表的所有合并单元格数据,根据excel模板,要跳过2行,获取从第三行后的合并单元格数据。if(firstRowIndex>2)

参考:https://blog.csdn.net/xhmico/article/details/136905419


在这里插入图片描述

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

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

相关文章

基于PCIe总线架构的2路1GSPS AD、4路1GSPS DA信号处理平台(100%国产化)

板卡概述 PCIE723-165是基于PCIE总线架构的2通道1GSPS采样率14位分辨率、4通道1GSPS采样率16位分辨率信号处理平台&#xff0c;该板卡采用国产16nm FPGA作为实时处理器&#xff0c;支持2路高速采集以及4路高速数据回放&#xff0c;板载2组DDR4 SDRAM大容量数据缓存&#xff0c;…

ElasticSearch 深度分页详解

原文链接&#xff1a;https://zhuanlan.zhihu.com/p/667036768 1 前言 ElasticSearch 是一个实时的分布式搜索与分析引擎&#xff0c;常用于大量非结构化数据的存储和快速检索场景&#xff0c;具有很强的扩展性。纵使其有诸多优点&#xff0c;在搜索领域远超关系型数据库&…

IDEA 中的调试方式(以 java 为例)

文章目录 IDEA 中的调试方式(以 java 为例)1. 基本介绍2. 断点调试的快捷键2.1 设置断点并启动调试2.3 快捷键 IDEA 中的调试方式(以 java 为例) 在开发中查找错误的时候&#xff0c;我们可以用断点调试&#xff0c;一步一步的看源码执行的过程&#xff0c;从而发现错误所在。 …

Linux --- 高级IO

一、基本概念 五种IO模型 阻塞IO&#xff1a;在内核将数据准备好之前&#xff0c;系统调用会一直等待&#xff0c;所有的套接字&#xff0c;默认都是阻塞方式 非阻塞IO&#xff1a;如果内核还未将数据准备好&#xff0c;系统调用仍然会直接返回&#xff0c;并且返回EWOULDBLOCK…

java—Spring框架

Spring 简介 Spring框架由Rod Johnson开发&#xff0c;2004年发布了Spring框架的第一版。Spring是一个从实际开发中抽取出来的框架&#xff0c;因此它完成了大量开发中的通用步骤&#xff0c;留给开发者的仅仅是与特定应用相关的部分&#xff0c;从而大大提高了企业应用的开发…

MacOS 开发 — Packages 程序 macOS新版本 演示选项卡无法显示

MacOS 开发 — Packages 程序 macOS新版本 演示选项卡无法显示 问题描述 &#xff1a; 之前写过 Packages 的使用以及如何打包macOS程序。最近更新了新的macOS系统&#xff0c;发现Packages的演示选项卡无法显示&#xff0c;我尝试从新安转了Packages 也是没作用&#xff0c;…

2024年新一代WebOffice内嵌网页组件——猿大师办公助手

背景 WebOffice控件这个中间件软件产品已存在二十余年&#xff0c;在国内众多大中小型企业、各级政府机关、科研机构和学校等事业单位的OA、ERP、文档系统、云盘等信息化B/S系统中得到了大量使用&#xff0c;为我国的信息化事业也做出了不小贡献。随着操作系统、浏览器及Offic…

亚信安全新一代终端安全TrustOne2024年重磅升级

以极简新主义为核心&#xff0c;亚信安全新一代终端安全TrustOne自2023年发布以来&#xff0c;带动了数字化终端安全的革新。60%&#xff0c;安装部署及管理效率的提升&#xff1b;50%&#xff0c;安全管理资源的节省&#xff1b;100%&#xff0c;信创非信创场景的全覆盖。Trus…

sqlmap使用之-post注入、head注入(ua、cookie、referer)

1、post注入 1.1、方法一&#xff0c;通过保存数据包文件进行注入 bp抓包获取post数据 将数据保存到post.txt文件 加上-r指定数据文件 1.2、方法二、通过URL注入 D:\Python3.8.6\SQLmap>python sqlmap.py -u "http://localhost/login.php" --data "userna…

百度文心4.0 Turbo开放,领跑国内AI大模型赛道!

百度文心4.0 Turbo开放&#xff0c;领跑国内AI大模型赛道&#xff01; 前言 文心一言大模型 就在7月5日&#xff0c;在2024世界人工智能大会 (WAIC) 上&#xff0c;百度副总裁谢广军宣布文心大模型4.0 Turbo正式向企业客户全面开放&#xff01;这一举动直接引发了业界的关注。那…

SpringCloud教程 | 第八篇: 使用seata处理分布式事务

1、参考程序员江小北 2、打算降低nacos版本&#xff0c;先学通再看看升级到高版本nacos能不能正常使用。 3、nacos用1.4.1&#xff0c;正常启动单机版的了 4、seata用2.0.0 我看江小北说用的1.4.0的seata&#xff0c;但是图片中的目录文件都找不到&#xff0c;倒是在2.0.0的…

【git】:初识Git 和 Git 的安装

目录 学习 Git 的目标 Git 安装 Linux-centos Linux-ubuntu Windows 学习 Git 的目标 技术目标 掌握 Git 企业级应用&#xff0c;深刻理解Git操作过程与操作原理&#xff0c;理解工作区&#xff0c;暂存区&#xff0c;版本库的含义 掌握 Git 版本管理&#xff0c;自由进⾏…

DWG文件发布至IIS后无法下载和预览解决办法

问题描述 DWG文件发布至IIS后无法下载和预览 原因分析&#xff1a; iis里面需要添加扩展 解决方案&#xff1a; 在服务器端IS属性的HTTP头下的MIME内容中添加扩展名“.dwg” MIME类型填入application/acad

利用Python进行数据分析PDF下载经典数据分享推荐

本书由Python pandas项目创始人Wes McKinney亲笔撰写&#xff0c;详细介绍利用Python进行操作、处理、清洗和规整数据等方面的具体细节和基本要点。第2版针对Python 3.6进行全面修订和更新&#xff0c;涵盖新版的pandas、NumPy、IPython和Jupyter&#xff0c;并增加大量实际案例…

【想心静?】红尘中修炼的功夫,才是真正的功夫

刘君亮想要去山中静坐&#xff0c;先生说&#xff1a; 你若是以厌弃身外事物的心去静中寻求天理&#xff0c;反而只会养出骄傲怠惰的习气。你若能不厌弃身外事物&#xff0c;然后再到静处涵养天理&#xff0c;却是好的。 去一个安静的地方&#xff0c;去沉静一下自己的内心也…

Java之网络面试经典题(一)

目录 ​编辑 一.Session和cookie Cookie Session 二.HTTP和HTTPS的区别 三.浅谈HTTPS为什么是安全的&#xff1f; 四.TCP和UDP 五.GET和Post的区别 六.forward 和 redirect 的区别&#xff1f; 本专栏全是博主自己收集的面试题&#xff0c;仅可参考&#xff0c;不能相…

kind kubernetes(k8s虚拟环境)使用本地docker的镜像

kubernetes中&#xff0c;虽然下载镜像使用docker&#xff0c;但是存储在docker image里的镜像是不能被k8s直接使用的&#xff0c;但是kind不同&#xff0c;可以使用下面的方法&#xff0c;让kind kubernetes环境使用docker image里的镜像。 kind – Quick Start 例如&#x…

Java数据结构-链表与LinkedList

链表 链表的概念 链表是一种物理存储结构上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的。 通俗来说&#xff0c;相比较于顺序表&#xff08;物理上连续&#xff0c;逻辑上也连续&#xff09;&#xff0c;链表物理上不一定连续。 链表是…

VBA语言専攻T3学员领取资料通知

T3学员领取资料通知0713 各位学员∶本周MF系列VBA技术资料增加646-650讲&#xff0c;T3学员看到通知后请免费领取,领取时间7月12日晚上19:00-7月13日晚上18:00。本次增加内容&#xff1a; MF646:OnKey禁用ShiftCTRL向右键 MF647:每隔一行插入一空行 MF648:取消合并单元格 …

druid(德鲁伊)数据线程池连接MySQL数据库

文章目录 1、druid连接MySQL2、编写JDBCUtils 工具类 1、druid连接MySQL 初学JDBC时&#xff0c;连接数据库是先建立连接&#xff0c;用完直接关闭。这就需要不断的创建和销毁连接&#xff0c;会消耗系统的资源。 借鉴线程池的思想&#xff0c;数据连接池就这么被设计出来了。…