导出导入Excel文件(详解-基于EasyExcel)

前言:

        近期由于工作的需要,根据需求需要导出导入Excel模板。于是自学了一下下,在此记录并分享!!

EasyExcel:

        首先我要在这里非常感谢阿里的大佬们!封装这么好用的Excel相关的API,真的是拯救了许多猿猿们!!

        EasyExcel官网:关于Easyexcel | Easy Excel 官网

导出Excel(write):

        接到项目之后,我负责的其中一个小需求是需要导出Excel,网上查了大量资料,发现EasyExcel包中已经包含了大量的对Excel的操作,当然对于一些特殊的需求可能需要自己写一个对Excel操作的方法~

@ExcelProperty注解:

        我将这个注解作为首要讲解对象,足以看出其重要性。

        示例代码:

    @ExcelProperty(value = "序号",order = 1,converter = IdConverter.class)private Long id = 1L;@ExcelProperty(value = "出生日期", format = "yyyy-MM-dd",headStyle = CustomHeadStyleStrategy.class)private Date birthDate;

只要在对应字段上加上该注解以后,意味着该字段将作为表头出现在Excel中,其中有一些参数如下:

1. value

  • 类型String[]
  • 作用:指定 Excel 表头的名称。可以传入一个字符串数组,当存在多级表头时,数组中的元素按顺序对应各级表头。

2. index

  • 类型int
  • 作用:指定该属性对应 Excel 表格中的列索引,索引从 0 开始。当 Excel 列顺序固定时,可以使用此参数进行精确映射。

3. converter

  • 类型Class<? extends Converter<?>>
  • 作用:指定自定义的转换器,用于将 Java 对象属性与 Excel 单元格数据进行转换。当默认的转换器无法满足需求时,可以自定义转换器并通过此参数指定。

4. format

  • 类型String
  • 作用:用于指定日期、数字等类型数据的格式化模式。当读取或写入 Excel 时,会按照指定的格式进行转换。

5. order

  • 类型int
  • 作用:指定该属性在生成 Excel 表格时的列顺序,数值越小越靠前。

6. headStyle

  • 类型Class<? extends HeadStyleStrategy>
  • 作用:指定表头样式的策略类,用于自定义表头的样式,如字体、颜色、背景色等。

7. contentStyle

  • 类型Class<? extends ContentStyleStrategy>
  • 作用:指定内容样式的策略类,用于自定义表格内容的样式,如字体、颜色、对齐方式等。

当然随着EasyExcel引入的版本不一样,有些参数可能被淘汰或者是换成了新的~

着重需要说明两个参数:

1.converter参数,这个参数需要实现Converter接口

public class IdConverter implements Converter<Integer> {
//todo
}

这个接口需要重写三个方法:

Class<?> supportJavaTypeKey();
  • 作用:指明此转换器所支持的 Java 类型。返回值是一个 Class 对象,代表支持转换的 Java 类型。

CellDataTypeEnum supportExcelTypeKey();
  • 作用:指定该转换器支持的 Excel 单元格数据类型。CellDataTypeEnum 是一个枚举类型,包含了各种 Excel 单元格数据类型,像字符串、数字、日期等。

T convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception;
  • 作用:把 Excel 单元格数据转换为 Java 对象属性。参数如下:
    • cellData:表示从 Excel 读取到的单元格数据。
    • contentProperty:包含单元格的一些属性信息。
    • globalConfiguration:全局配置信息。

综上示例如下:

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;public class StringConverter implements Converter<String> {@Overridepublic Class<?> supportJavaTypeKey() {return String.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return cellData.getStringValue();}@Overridepublic WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new WriteCellData<>(value);}
}

当然也可以根据自身的需求进行补充,例如:希望在数字后面+单位,在人名后面+称呼,希望id是一个自增的等等行为~~

Excel中的id列自增:

        这里我举例id列希望是自增的:

实体类代码:

    @ExcelProperty(value = "序号",order = 1,converter = IdConverter.class)private Long id = 1L;

converter代码: 

public class IdConverter implements Converter<Integer> {private int currentId = 1;@Overridepublic Class<?> supportJavaTypeKey() {return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.NUMBER;}@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) {return new WriteCellData<>(String.valueOf(currentId++));}
}

效果如下:

        

复杂表头:

        如果想要一个多级表头,使用上述的注解一样可以做到:

只不过value的值要变成层级关系:

    @ExcelProperty(value = {"项目交付信息","牵头部门名称"},order = 14)private String leadingDepartment;@ExcelProperty(value = {"项目交付信息","交付部门名称"},order = 15)private String deliveryDepartment;@ExcelProperty(value = {"项目交付信息","项目PO"},order = 16)private String projectPo;@ExcelProperty(value = {"项目交付信息","项目经理"},order = 17)private String projectManager;

@DateTimeFormat注解:

        该注解也是一个确定时间格式的注解,由于版本的迭代,上述的@ExcelProperty的format

属性已经被废除,建议使用该注解进行时间格式的限制。

        @DateTimeFormat 注解是 Spring 框架提供的一个用于日期和时间格式化的注解,它主要用于将字符串类型的日期时间数据绑定到 Java 对象的日期时间类型字段上,或者将 Java 对象中的日期时间类型字段按照指定格式输出为字符串。

pattern

  • 类型String
  • 作用:指定日期时间的格式化模式。模式遵循 Java 的 SimpleDateFormat 或 DateTimeFormatter 的规则。例如,"yyyy-MM-dd" 表示年 - 月 - 日的格式,"yyyy-MM-dd HH:mm:ss" 表示年 - 月 - 日 时:分: 秒的格式。

iso

  • 类型ISO 枚举类型
  • 作用:使用预定义的 ISO 日期时间格式。ISO 枚举包含了几个常用的 ISO 日期时间格式,如 ISO.DATE 表示 yyyy-MM-dd 格式,ISO.TIME 表示 HH:mm:ss.SSSXXX 格式,ISO.DATE_TIME 表示 yyyy-MM-dd'T'HH:mm:ss.SSSXXX 格式。

示例如下:

 @DateTimeFormat(pattern = "yyyy-MM-dd")private Date birthDate;

@ContentRowHeight,@HeadRowHeight,@ColumnWidth

        设置行高与列宽,上述的三个注解可以实现设置操作,注意,上述注解@ColumnWidth可以使用在类上面,也可以单独注解在属性上面。

        示例如下:

@ContentRowHeight(20)//内容行高
@HeadRowHeight(20)//表头行高
@ColumnWidth(25)//列宽
public class DeriveExcelDTO {@ColumnWidth(40)@ExcelProperty(value = "项目名称",order = 2)private String projectName;
}

这里就不展示效果图了,大家有兴趣可以自己进行尝试!!!

示例完整导出代码:

// 实体类,用于映射Excel列
public class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;// 构造函数、getter和setterpublic DemoData() {}public DemoData(String string, Date date, Double doubleData) {this.string = string;this.date = date;this.doubleData = doubleData;}// getters and setterspublic String getString() { return string; }public void setString(String string) { this.string = string; }public Date getDate() { return date; }public void setDate(Date date) { this.date = date; }public Double getDoubleData() { return doubleData; }public void setDoubleData(Double doubleData) { this.doubleData = doubleData; }
}// 控制器示例(Spring MVC)
@RestController
public class ExcelExportController {@GetMapping("/export")public void export(HttpServletResponse response) throws IOException {// 准备数据List<DemoData> data = new ArrayList<>();for (int i = 0; i < 10; i++) {DemoData demoData = new DemoData();demoData.setString("字符串" + i);demoData.setDate(new Date());demoData.setDoubleData(0.56 + i);data.add(demoData);}// 设置响应头response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 导出ExcelEasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(data);}
}

导入Excel(read):

        导出Excel其实和导入是差不多的,但是在使用EasyExcel时,需要注意表头的书写是否和读取时一致(例如读取时读二级表头,Excel中对应的数据的表头必须也是二级的)!后面会详细介绍到。

设置监听器:

        读取Excel表格时,必须设置一个监听器,但是需要注意的是该监听器不能被Spring管理,每次使用时必须手动new。

@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;/*** 缓存的数据*/private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/private DemoDAO demoDAO;public DemoDataListener() {// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数demoDAO = new DemoDAO();}/*** 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来** @param demoDAO*/public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}/*** 这个每一条数据解析都会来调用** @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {log.info("解析到一条数据:{}", JSON.toJSONString(data));cachedDataList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}/*** 所有数据解析完成了 都会来调用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", cachedDataList.size());demoDAO.save(cachedDataList);log.info("存储数据库成功!");}
}

当然阿里为了更加方便猿猿们,也就行了二次封装,封装后的ReadListener可以交给Spring进行管理,也是非常方便了~

        没错就是这个AnalysisEventListener类,里面继承了ReadListener,也是更加简便清晰了~

可以重写一下的方法:

每个方法的作用以及参数如下:

        

onException(Exception exception, AnalysisContext context)

  • 作用:读取过程中发生异常时触发
  • 参数
    • exception:异常对象
    • context:读取上下文

doAfterAllAnalysed(AnalysisContext context)

  • 作用:整个 Excel 文件读取完成后触发
  • 参数:读取上下文

invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context)

  • 作用:解析表头时触发(默认表头占 1 行)
  • 参数
    • headMap:表头数据(key 为列索引,value 为单元格数据)
    • context:读取上下文

hasNext(AnalysisContext context)

  • 作用:控制是否继续读取下一行(返回 false 时终止读取)
  • 参数:读取上下文

 完整示例如下:

public class DemoDataListener extends AnalysisEventListener<DemoData> {private List<DemoData> dataList = new ArrayList<>();@Overridepublic void invoke(DemoData data, AnalysisContext context) {// 每行数据解析后调用dataList.add(data);System.out.println("解析第" + context.readRowHolder().getRowIndex() + "行:" + data.getName());}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有数据解析完成后调用System.out.println("共解析" + dataList.size() + "行数据");}@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {// 表头解析后调用System.out.println("解析表头:" + headMap.get(0).getStringValue());}@Overridepublic void onException(Exception exception, AnalysisContext context) {// 异常处理System.err.println("解析失败,行号:" + context.readRowHolder().getRowIndex());exception.printStackTrace();}public List<DemoData> getDataList() {return dataList;}
}

 完整代码:

        

public String importUser(@RequestParam("file") MultipartFile file) {try {EasyExcel.read(file.getInputStream(), User.class, new UserExcelListener(userService)).sheet().doRead();return "导入并更新成功";} catch (Exception e) {return "导入并更新失败:" + e.getMessage();}}

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

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

相关文章

python版本管理工具-pyenv轻松切换多个Python版本

在使用python环境开发时&#xff0c;相信肯定被使用版本所烦恼&#xff0c;在用第三方库时依赖兼容的python版本不一样&#xff0c;有没有一个能同时安装多个python并能自由切换的工具呢&#xff0c;那就是pyenv&#xff0c;让你可以轻松切换多个Python 版本。 pyenv是什么 p…

Elasticsearch 索引副本数

作者&#xff1a;来自 Elastic Kofi Bartlett 解释如何配置 number_of_replicas、它的影响以及最佳实践。 更多阅读&#xff1a;Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica 想获得 Elastic 认证&#xff1f;查看下一期 Elasticsearc…

AXI4总线协议 ------ AXI_LITE协议

一、AXI 相关知识介绍 https://download.csdn.net/download/mvpkuku/90841873 AXI_LITE 选出部分重点&#xff0c;详细文档见上面链接。 1.AXI4 协议类型 2.握手机制 二、AXI_LITE 协议的实现 1. AXI_LITE 通道及各通道端口功能介绍 2.实现思路及框架 2.1 总体框架 2.2 …

idea运行

各种小kips Linuxidea上传 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目录下&#xff0c;找到对应项目目录&#xff0c;把原来的jar包放在bak文件夹里面 3、杀死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再进行上传新的jar…

FPGA: XILINX Kintex 7系列器件的架构

本文将详细介绍Kintex-7系列FPGA器件的架构。以下内容将涵盖Kintex-7的核心架构特性、主要组成部分以及关键技术&#xff0c;尽量全面且结构化&#xff0c;同时用简洁的语言确保清晰易懂。 Kintex-7系列FPGA架构概述 Kintex-7是Xilinx 7系列FPGA中的中高端产品线&#xff0c;基…

【LLM】大模型落地应用的技术 ——— 推理训练 MOE,AI搜索 RAG,AI Agent MCP

【LLM】大模型落地应用的技术 ——— 推理训练MOE&#xff0c;AI搜索RAG&#xff0c;AI Agent MCP 文章目录 1、推理训练 MOE2、AI搜索 RAG3、AI Agent MCP 1、推理训练 MOE MoE 是模型架构革新&#xff0c;解决了算力瓶颈。原理是多个专家模型联合计算。 推理训练MoE&#xff…

10 web 自动化之 yaml 数据/日志/截图

文章目录 一、yaml 数据获取二、日志获取三、截图 一、yaml 数据获取 需要安装 PyYAML 库 import yaml import os from TestPOM.common import dir_config as Dir import jsonpathclass Data:def __init__(self,keyNone,file_name"test_datas.yaml"):file_path os…

中exec()函数因$imagePath参数导致的命令注入漏洞

exec(zbarimg -q . $imagePath, $barcodeList, $returnVar); 针对PHP中exec()函数因$imagePath参数导致的命令注入漏洞&#xff0c;以下是安全解决方案和最佳实践&#xff1a; 一、漏洞原理分析 直接拼接用户输入$imagePath到系统命令中&#xff0c;攻击者可通过注入特殊字…

this.$set的用法-响应式数据更新

目录 一、核心作用 三、使用场景与示例 1. 给对象添加新属性 四、与 Vue.set 的关系 五、底层原理 六、Vue 3 的替代方案 七、最佳实践 八、常见问题 Q&#xff1a;为什么修改嵌套对象属性不需要 $set&#xff1f; Q&#xff1a;$set 和 $forceUpdate 的区别&#xf…

【生成式AI文本生成实战】DeepSeek系列应用深度解析

目录 &#x1f31f; 前言&#x1f3d7;️ 技术背景与价值&#x1fa79; 当前技术痛点&#x1f6e0;️ 解决方案概述&#x1f465; 目标读者说明 &#x1f9e0; 一、技术原理剖析&#x1f4ca; 核心概念图解&#x1f4a1; 核心作用讲解&#x1f527; 关键技术模块说明⚖️ 技术选…

c/c++的opencv的图像预处理讲解

OpenCV 图像预处理核心技术详解 (C/C) 图像预处理是计算机视觉任务中至关重要的一步。原始图像往往受到噪声、光照不均、尺寸不一等多种因素的影响&#xff0c;直接用于后续分析&#xff08;如特征提取、目标检测、机器学习模型训练等&#xff09;可能会导致性能下降或结果不准…

使用 Docker 部署 React + Nginx 应用教程

目录 1. 创建react项目结构2. 创建 .dockerignore3. 创建 Dockerfile4. 创建 nginx.conf5. 构建和运行6. 常用命令 1. 创建react项目结构 2. 创建 .dockerignore # 依赖目录 node_modules npm-debug.log# 构建输出 dist build# 开发环境文件 .git .gitignore .env .env.local …

Java 流(Stream)API

一、理论说明 1. 流的定义 Java 流&#xff08;Stream&#xff09;是 Java 8 引入的新特性&#xff0c;用于对集合&#xff08;如 List、Set&#xff09;或数组进行高效的聚合操作&#xff08;如过滤、映射、排序&#xff09;和并行处理。流不存储数据&#xff0c;而是按需计…

网络协议分析 实验七 FTP、HTTP、DHCP

文章目录 实验7.1 FTP协议练习二 使用浏览器登入FTP练习三 在窗口模式下&#xff0c;上传/下传数据文件实验7.2 HTTP(Hyper Text Transfer Protocol)练习二 页面提交练习三 访问比较复杂的主页实验7.3 DHCP(Dynamic Host Configuration Protocol) 实验7.1 FTP协议 dir LIST&…

go语言学习进阶

目录 第一章 go语言中包的使用 一.main包 二.package 三.import 四.goPath环境变量 五.init包初始化 六.管理外部包 第二章 time包 第三章 File文件操作 一.FileInfo接口 二.权限 三.打开模式 四.File操作 五.读文件 参考1&#xff1a;Golang 中的 bufio 包详解…

Hue面试内容整理-后端框架

Cloudera 的 Hue 项目在后端采用了成熟的 Python Web 框架 Django,结合其他组件构建了一个可扩展、模块化的系统,便于与 Hadoop 生态系统中的各个组件集成。以下是 Hue 后端架构的详细介绍: 后端架构概览 1. Django Web 框架 Hue 的核心是基于 Django 构建的 Web 应用,负责…

Web-CSS入门

WEB前端&#xff0c;三部分&#xff1a;HTML部分、CSS部分、Javascript部分。 1.HTML部分&#xff1a;主要负责网页的结构层 2.CSS部分&#xff1a;主要负责网页的样式层 3.JS部分&#xff1a;主要负责网页的行为层 **基本概念** 层叠样式表&#xff0c;Cascading Style Sh…

2025年PMP 学习十六 第11章 项目风险管理 (总章)

2025年PMP 学习十六 第11章 项目风险管理 &#xff08;总章&#xff09; 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 目标: 提高项目中积极事件的概率和…

基于SpringBoot的小区停车位管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

HTML常用标签用法全解析:构建语义化网页的核心指南

HTML作为网页开发的基石&#xff0c;其标签的合理使用直接影响页面的可读性、SEO效果及维护性。本文系统梳理HTML核心标签的用法&#xff0c;结合语义化设计原则与实战示例&#xff0c;助你构建规范、高效的网页结构。 一、基础结构与排版标签 1.1 文档结构 <!DOCTYPE htm…