Execl数据导入 EasyExcel实现

官网

1. 需求简介

读取下面表格数据
在这里插入图片描述
第一行和第二行是计划信息
第三行是计划详情的抬头信息,以下行是计划详情信息
总段包含多个分段,总段使用了单元格合并功能

2. 实现读取功能

2.1 引入easyexcel依赖

        <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.0</version></dependency>

2.2 创建计划详情行信息对象

package com.gkdz.server.modules.shipyard.domain;import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;import java.util.Date;@Getter
@Setter
@EqualsAndHashCode
public class Summary {@ExcelProperty(value = "序号", index = 0)private String number;@ExcelProperty(value = "总段", index = 1)private String totalSection;@ExcelProperty(value = "分段", index = 2)private String subSection;@ExcelProperty(value = "分段预估重量(T)", index = 3)private Double subExpectWeight;@ExcelProperty(value = "长", index = 4)private Double length;@ExcelProperty(value = "宽", index = 5)private Double width;@ExcelProperty(value = "高", index = 6)private Double height;@ExcelProperty(value = "分段类型", index = 7)private String type;@ExcelProperty(value = "总段预估重量(T)", index = 8)private Double totalExpectWeight;@ExcelProperty(value = "分段交付时间", index = 9)private String subSectionDeliveryTime;@ExcelProperty(value = "总组吊装日期", index = 10)private String hoistDate;@ExcelProperty(value = "总组焊前", index = 11)private String totalBeWeldDate;@ExcelProperty(value = "总组焊前周期", index = 12)private String totalBeWeldCycle;@ExcelProperty(value = "总组完工日期", index = 13)private String totalCompletionDate;@ExcelProperty(value = "总组完工周期", index = 14)private String totalCompletionCycle;@ExcelProperty(value = "搭载吊装日期", index = 15)private String carryLiftDate;@ExcelProperty(value = "搭载焊前日期", index = 16)private String carryBeWeldDate;@ExcelProperty(value = "搭载焊前周期", index = 17)private String carryBeWeldCycle;@ExcelProperty(value = "搭载完工日期", index = 18)private String carryCompletionDate;@ExcelProperty(value = "搭载完工周期", index = 19)private String carryCompletionCycle;@ExcelProperty(value = "吊装顺序", index = 20)private String hoistOrder;@ExcelProperty(value = "封舱设备", index = 21)private String sealingEquipment;@ExcelProperty(value = "备注", index = 22)private String remark;//标记,用于分组,ExcelIgnore为忽略注解@ExcelIgnoreprivate String elementStr;/**行号*/@ExcelIgnoreprivate int rowNo;
}

2.3 读取execl工具类

package com.gkdz.server.modules.shipyard.util;import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import com.gkdz.server.modules.shipyard.domain.Summary;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;@Slf4j
public class EasyExcelUtil {/*** 计划详情正文起始行*/private static final Integer headRowNumber = 3;/*** 分组切割符号*/public static final String splitFlag = "<zld>";public static Map<String, List> uploadByFile(MultipartFile file) throws IOException {Map<String, List> map = new HashMap<>();//正文行数据List<Summary> saveList = new ArrayList<>();//抬头行数据List<String> planInfoList = new ArrayList<>();//合并单元格数据List<CellExtra> extraMergeInfoList = new ArrayList<>();EasyExcel.read(file.getInputStream(), Summary.class, new ReadListener<Summary>() {/*** 读取表格抬头行数据,默认为读第一行;* 可设置headRowNumber(headRowNumber):抬头行为前headRowNumber行* @param headMap* @param context*/@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {planInfoList.add(headMap.get(0).getStringValue());}/*** 读取非抬头行数据* @param data 行数据格式,自定义,默认为Object* @param analysisContext*/@Overridepublic void invoke(Summary data, AnalysisContext analysisContext) {if (StrUtil.isEmptyIfStr(data.getTotalSection())) {data.setTotalSection(data.getSubSection());}saveList.add(data);}/**** @param extra* @param context*/@Overridepublic void extra(CellExtra extra, AnalysisContext context) {log.info("读取到了一条额外信息:{}", JSON.toJSONString(extra));switch (extra.getType()) {case COMMENT: {log.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),extra.getText());break;}case HYPERLINK: {if ("Sheet1!A1".equals(extra.getText())) {log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),extra.getColumnIndex(), extra.getText());} else if ("Sheet2!A1".equals(extra.getText())) {log.info("额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"+ "内容是:{}",extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),extra.getLastColumnIndex(), extra.getText());} else {log.error("Unknown hyperlink!");}break;}case MERGE: {if (extra.getRowIndex() >= headRowNumber) {extraMergeInfoList.add(extra);}break;}default: {}}}/*** 数据读取完毕后执行的方法,可做数据整体处理* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}}).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(headRowNumber).doRead();final List<Summary> summaries = ExcelSplitUtil.explainMergeData(saveList, extraMergeInfoList, headRowNumber);map.put("planInfo", planInfoList);map.put("summary", summaries);return map;}/*** 根据easyexcel注解给指定实体赋值** @param objects 读取的表格内容* @param clazz   需转化的实体* @param <T>     实体* @return 需转化的提示集合*/public static <T> List<T> convertList(List<LinkedHashMap> objects, Class<T> clazz) {List<T> results = new ArrayList<>(objects.size());try {Map<String, Field> objIndex = new HashMap<>();// 获取转化实体字段信息集合Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 根据实体上Easy Excel的ExcelProperty注解中的索引值对应excel读取数据的值int index = field.getAnnotation(ExcelProperty.class).index();// 设置字段可编辑field.setAccessible(true);objIndex.put(String.valueOf(index), field);}T obj = null;for (LinkedHashMap o : objects) {obj = clazz.newInstance();for (Object key : o.keySet()) {// 如果表格索引与字段注解指定索引一样则赋值if (objIndex.containsKey(key)) {Object object = o.get(key);Object value = null;Field field = objIndex.get(key);if (ObjectUtil.isEmpty(object)) {continue;}Class<?> type = field.getType();String replace = object.toString();// 有特殊需要处理的字段类型则在此进行处理if (type == BigDecimal.class) {value = "--".equals(replace) ? null : new BigDecimal(replace.replace(",", ""));} else if (type == Integer.class) {// String强转Integer会报错,所以需要单独进行转化value = "--".equals(replace) ? null : Integer.valueOf(replace.replace(",", ""));} else {value = object;}field.set(obj, value);}}results.add(obj);}} catch (Exception e) {log.error("字段解析失败", e);}return results;}
}

2.4 拆分单元格工具

package com.gkdz.server.modules.shipyard.util;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.CellExtra;
import com.gkdz.server.modules.shipyard.domain.Summary;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;
import java.util.List;/*** @description:拆分单元格数据*/
@Slf4j
public class ExcelSplitUtil {/*** 处理合并单元格** @param data               解析数据* @param extraMergeInfoList 合并单元格信息* @param headRowNumber      起始行* @return 填充好的解析数据*/public static List<Summary> explainMergeData(List<Summary> 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 void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<Summary> data) {Summary 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("解析数据时发生异常!");}}}}}/*** 获取合并单元格的初始值* rowIndex对应list的索引* columnIndex对应实体内的字段** @param firstRowIndex    起始行* @param firstColumnIndex 起始列* @param data             列数据* @return 初始值*/private static Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<Summary> data) {Object filedValue = null;Summary 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("解析数据时发生异常!");}}}}return filedValue;}
}

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

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

相关文章

分享几个好用的网站、软件

1、果核剥壳 https://www.ghxi.com 果核剥壳是一家综合科技站点&#xff0c;看新闻&#xff0c;分享破解软件、绿色软件&#xff0c;Windows系统。守住互联网最后的一片净土。 2、小众软件 https://www.appinn.com 小众软件是一个分享免费、小巧、有趣、实用软件的网站&…

Hugo搭建博客和部署全流程—Congo主题和优化

欢迎来到我的全新博客&#xff1a;探索科研、创业和日常——Hugo搭建博客、部署和优化全流程 &#x1f30f; Demo site: https://sylvanding.online/ ⭐️ Repo: https://github.com/sylvanding/sylvanding.github.io 我的博客使用Hugo搭建&#xff0c;选择Congo主题&#xff0…

为什么25+胶原蛋白会流失?

随着年龄的增长&#xff0c;特别是当我们步入25岁之后&#xff0c;胶原蛋白的流失问题逐渐凸显&#xff0c;成为影响皮肤健康和外观的重要因素。以下将从几个方面详细解释胶原蛋白流失的原因&#xff1a; 一、年龄增长 胶原蛋白是皮肤的主要支撑结构&#xff0c;但随着年龄的增…

数据挖掘与机器学习——分类算法

目录 机器学习算法最普通分类&#xff1a; 分类算法的定义&#xff1a; 分类算法的应用&#xff1a; 分类器实现分类&#xff1a; 分类器的构建标准&#xff1a; 概率模型&#xff1a; 贝叶斯公式&#xff1a; 朴素贝叶斯算法&#xff08;朴素贝叶斯分类器&#xff09;…

【每日刷题】Day55

【每日刷题】Day55 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 441. 排列硬币 - 力扣&#xff08;LeetCode&#xff09; 2. 455. 分发饼干 - 力扣&#xff08;Leet…

centos系统清理docker日志文件

centos系统清理docker日志文件 1.查看docker根目录位置2.清理日志 1.查看docker根目录位置 命令&#xff1a;docker info ,将Docker Root Dir 的值复制下来。如果目录中包含 等特殊符号的目录&#xff0c;需要转义 2.清理日志 创建文件&#xff1a;vim docker_logs_clean.…

2024-6-4 石群电路-23

2024-6-4&#xff0c;星期二&#xff0c;13:16&#xff0c;天气&#xff1a;晴&#xff0c;心情&#xff1a;晴。今天又是阳光明媚的一天&#xff0c;没有什么特别的事情发生&#xff0c;加油学习喽~ 今日观看了石群老师电路课程的第39和第40个视频&#xff0c;继续第九章的学…

vulnhub靶机xptosystem

下载地址&#xff1a;https://download.vulnhub.com/xpto/xptosystem.ova 主机发现 端口扫描 服务扫描 漏洞扫描 看一下web 目录爆破 那不用说肯定看看robots.txt 要检查readme去看看 看不懂 这个是靶场吧很像 在最后看着挺像url路径的 还真是&#xff0c;我直接base64 坏了还…

TS 小技巧: 使用元组生成联合类型

前言 在我们使用 TypeScript 开发业务的时候&#xff0c;也许你会遇到一个这样的问题&#xff1a;我们如何根据一个数组的值得到一个联合类型&#xff1f; 这里向大家介绍一个开发小技巧&#xff1a;使用元组生成联合类型 开发场景 我们看下面一段 ts 代码&#xff1a; con…

【二叉树】Leetcode 222. 完全二叉树的节点个数【简单】

完全二叉树的节点个数 你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最…

【云原生_K8S系列】什么是 Kubernetes Pod?用实际例子解释

Kubernetes&#xff08;简称K8S&#xff09;是一个开源的容器编排平台&#xff0c;用于自动化容器化应用的部署、扩展和管理。在Kubernetes中&#xff0c;Pod是最小的部署单元。理解Pod的概念对于掌握Kubernetes至关重要。本篇文章将详细解释什么是Kubernetes Pod&#xff0c;并…

数字孪生概念、数字孪生技术架构、数字孪生应用场景,深度长文学习

一、数字孪生起源与发展 1.1 数字孪生产生背景 数字孪生的概念最初由Grieves教授于2003年在美国密歇根大学的产品全生命周期管理课程上提出&#xff0c;并被定义为三维模型&#xff0c;包括实体产品、虚拟产品以及二者间的连接&#xff0c;如下图所示&#xff1a; 2011年&…

【机器学习】机器学习在深度学习领域中的作用:半监督学习的视角

&#x1f440;时空之门&#x1f440; &#x1f50d;引言&#x1f388;半监督学习概述&#x1f69d;机器学习在深度学习领域中的作用☘特征提取与表示学习&#x1f340;复杂任务建模❀结合半监督学习提升性能 &#x1f680;半监督学习在深度学习中的应用场景&#x1f4d5;图像识…

反弹shell检测的一些思路

前言 反弹shell是攻击者常用的手段之一&#xff0c;通过反弹Shell&#xff0c;攻击者可以绕过防火墙&#xff0c;获取目标系统的shell访问权限&#xff0c;进行后续的恶意操作。因此&#xff0c;及时检测并阻止反弹Shell行为对于安全防护来说非常重要。本文通过介绍反弹shell的…

Baidu Comate帮开发者“代码搬砖”,2天搞定原先3周工作量

日常项目基础工作耗费大量时间、紧急任务一连“肝”几个大夜……对于一个计算机相关专业研究生来说&#xff0c;几乎是家常便饭。随着大模型能力赋能编码工具&#xff0c;被开发者们戏称的“代码搬砖”生活有了起色。 从去年开始&#xff0c;PPDE 飞桨开发者技术专家、澳门理工…

CV每日论文---2024.6.3

1、Video-MME: The First-Ever Comprehensive Evaluation Benchmark of Multi-modal LLMs in Video Analysis 中文标题&#xff1a;Video-MME&#xff1a;视频分析领域首个多模态法学硕士综合评估基准 简介&#xff1a;Video-MME 是一个全面评估多模态大语言模型&#xff08;M…

MAX7219(模拟SPI)驱动灯环的简单应用

文章目录 一、MAX7219是什么&#xff1f;二、使用步骤1.硬件1.1 引脚说明1.2 应用电路1.2.1 驱动数码管1.2.2 驱动点阵 2.软件2.1 时序2.2 寄存器2.2.1 掉电寄存器2.2.2 译码模式寄存器2.2.3 亮度寄存器2.2.4 扫描寄存器2.2.5 显示测试寄存器 2.3 初始化2.4 控制左侧灯环特定位…

大厂起诉了,协商拿了2N,整理点经验心得给大家,关于离职时如何让自己利益最大化!...

离职时&#xff0c;如何让自己的利益最大化&#xff1f; 一位跟大厂仲裁&#xff0c;并通过协商拿到2n的网友分享了自己的经验心得&#xff0c;干货满满&#xff0c;下面是要点总结&#xff1a; 1.大部分裁员都是违法裁员&#xff0c;应该给2n&#xff0c;但公司不会承认&…

【代码随想录——贪心算法——二周目】

1.买卖股票的最佳时间② 思路&#xff1a;构建每两天之间的利润之差&#xff0c;如果是正数则一直累加即可。 体现出来场景是&#xff0c;如果理论一直为正&#xff0c;则说明我们需要一直持有股票。当出现负数时&#xff0c;代表我们应该在前一天卖出。当出现正数时我们应该在…

【耗时十个小时】程序员最趁手的SVM算法,学完你会哭着感谢努力的自己!

❤ 纯 干 货 ❤ 在这之前咱们已经接触了 各个算法的优缺点的总结&#xff0c;以及8个回归类算法、7个正则化算法的总结、5 个集成算法模型的全部总结&#xff01; 感兴趣的可以翻到之前看看~ 咱们今天就大概一起学习一下关于SVM的方方面面。 线性支持向量机 非线性支持向量…