搞定Excel繁琐操作:一起轻松掌握EasyExcel的使用技巧
ztj100 2024-11-05 13:28 20 浏览 0 评论
作为一个经常进行数据分析的后端人员,免不了面对各种报表,且在日常的工作中,经常需要处理大量的数据,并进行各种复杂的计算和分析。而Excel作为一个重要的工具,在数据处理与分析上也起到了至关重要的作用。但是,Excel的操作繁琐、效率低下等问题也制约着我们的工作效率。为了解决这个问题,我们可以使用EasyExcel这个优秀的Java类库,来优化Excel数据的读写,并提高我们的工作效率。在本文中,我将向大家介绍如何使用EasyExcel的高效技巧,从而更好地搞定Excel繁琐操作。
一、EasyExcel简介
EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。
他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
EasyExcel是一个基于POI封装的Java类库,它能够对Excel文件进行读写操作。EasyExcel简单易用,性能优异,并且支持大量的Excel操作。无论是简单的数据导入还是复杂的数据处理和导出,EasyExcel都能够轻松实现。同时,EasyExcel也支持多种数据格式,包括Excel、CSV、TSV等。EasyExcel底层使用反射实现,因此也支持泛型。EasyExcel已被广泛应用于各种项目中,成为Java开发者优化Excel操作的首选库之一。
16M内存23秒读取75M(46W行25列)的Excel(3.2.1+版本)
- 官方网站:easyexcel.opensource.alibaba.com
- github地址:github.com/alibaba/eas…
- gitee地址:gitee.com/easyexcel/e…
二、EasyExcel的高效技巧
1. 读取Excel文件
在日常工作中,读取Excel文件是我们经常会遇到的需求之一。EasyExcel提供了多种读取Excel文件的方式,包括读取指定Sheet、读取指定列等。下面是一个简单的代码示例:
java复制代码//读取指定Sheet
List<YourModelName> list = EasyExcel.read(fileName)
.sheet(sheetNo)
.head(YourModelName.class)
.doReadSync();
java复制代码//读取指定列
List<Object> list = EasyExcel.read(fileName)
.sheet(sheetNo)
.headRow(rowNo)
.readRowFilter(new ReadRowFilter() {
@Override
public boolean doFilter(List<Object> list) {
if (list.get(0).equals("某一列的值")) {
return true;
}
return false;
}
})
.doReadSync();
2. 写入Excel文件
除了读取Excel文件外,我们在实际工作中也需要频繁地向Excel文件中写入数据。EasyExcel提供了多种写入Excel文件的方式,包括向指定Sheet写入数据、向指定行写入数据、动态合并单元格等。下面是一个简单的代码示例:
java复制代码//向指定Sheet写入数据
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, YourModelName.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
excelWriter.write(dataList, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
java复制代码//向指定行写入数据
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, YourModelName.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
excelWriter.write(dataList, writeSheet, new WriteTable()) .relativeHeadRowIndex(rowNo) .doWrite();
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
3. 填充Excel
在实际工作中,我们也经常需要对Excel文件进行填充。EasyExcel提供了多种填充Excel的方式,包括对象填充、自定义填充等。下面是一个简单的代码示例:
java复制代码//对象填充
List<YourModelName> dataList = getDataList();
OutputStream outputStream = new FileOutputStream(fileName);
EasyExcel.write(outputStream, YourModelName.class)
.sheet(sheetNo)
.doWrite(dataList);
outputStream.close();
java复制代码//自定义填充
List<Object> headList = getHeadList();
List<List<Object>> dataList = getDataList();
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).build();
excelWriter.fill(headList, fillConfig, writeSheet);
excelWriter.fill(dataList, fillConfig, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
4. 注意事项
在使用EasyExcel进行Excel操作时,我们也需要注意一些细节问题。下面是一些需要注意的事项:
- EasyExcel默认对读取到的单元格内容进行trim操作,因此如果需要保留前后空格需要手动设置。
java复制代码//禁止EasyExcel对单元格内容进行trim操作
Object value = cell.getStringCellValue();
cell.setCellValue(new HSSFRichTextString(value.toString()));
- 如果需要读取大量数据,可以使用异步读取的方式,提高读取效率。
java复制代码//异步读取
EasyExcel.read(fileName, YourModelName.class, new ReadListener<YourModelName>() {
// 重写方法
}).sheet().doRead();
5. 内部核心源码剖析
EasyExcel的底层代码实现是基于POI实现的,在POI的基础上又进一步进行了封装。具体来说,EasyExcel是通过反射来实现Excel文件的读写操作的,它利用了Java的泛型机制、注解等来实现高效简洁的Excel操作。EasyExcel底层的实现思路比较简单,我们可以通过阅读其源码来更好地理解其实现原理,从而更好地应用EasyExcel进行Excel数据的读写操作。
EasyExcel的底层代码实现主要基于Apache POI(Poor Obfuscation Implementation)和Java反射机制,其中Apache POI是一个支持Microsoft Office格式的Java类库,可以实现对Excel、Word、PowerPoint等文档格式的读写操作。EasyExcel利用了POI提供的接口来读写Excel文件,并在此基础上进行了封装和优化,以提高读写效率。
EasyExcel的数据读取主要涉及以下步骤:
- 创建Workbook对象,打开Excel文件,获取Sheet对象;
- 根据Sheet对象获取行和列对象,从而遍历Excel文件中的所有数据单元格;
- 通过反射机制将数据单元格中的值赋值给Java对象中的属性,最终得到完整的Java对象;
- 将Java对象添加到List集合中并返回。
EasyExcel的数据写入主要涉及以下步骤:
- 创建Workbook对象,创建Sheet对象;
- 遍历要写入的Java对象集合,将每个属性值写入Excel文件对应的单元格中;
- 加锁操作,将数据持久化到磁盘中。
在实际代码实现过程中,EasyExcel还采用了一些技术手段来提高性能和易用性:
- 使用线程池技术并发读写,多线程带来了更高的并发度,提高了读写效率。
- 缓存读取数据,将读取到的数据先缓存起来,再进行批量处理,大大提高了数据读取效率。
- 使用缓存技术,缓存Workbook、Sheet等对象,避免重复创建和销毁对象,从而提高运行效率。
- 利用Java的泛型机制和注解技术进行简洁的编程实现,减少了代码的冗余度,使代码更加易于维护和扩展。
EasyExcel的底层实现离不开Apache POI和Java反射机制,通过这些技术的应用,EasyExcel实现了对Excel文件的高效读写操作。
EasyExcel的核心源码实现主要涉及到以下几个方面:
1.使用POI进行Excel文件的读取和写入,POI提供了SXSSF等优化机制来提高读写效率。
2.采用反射机制自动将Excel中的数据映射为Java对象,并进行类型转换等操作。
3.使用注解来为Java对象中的属性和Excel中的表头进行映射,例如@ExcelProperty注解用于标记Java对象中的属性是Excel中的第几列。
4.使用缓存技术对Workbook、Sheet等对象进行缓存,避免重复创建和销毁对象,提高运行效率。
下面我们来具体看一下EasyExcel源码中的注解部分:
- @ExcelProperty注解
@ExcelProperty注解用于标记Java对象中的属性是Excel中的第几列。该注解包含三个属性:index、value和converter。
- index属性表示Java对象中的属性在Excel中对应的列的索引,默认值为-1,表示自动匹配。如果该值设置为2,则表示该属性与Excel中第3列对应。
- value属性表示Excel中该列的表头名称。如果设置了该值,则Excel中该列的表头名称为value的值;如果未设置,则默认为该属性的名称或字段名称。
- converter属性表示数据类型转换器,可将Excel文件中的数据进行类型转换。例如,当Excel中的数据为字符串时可以通过设置converter属性将其转换为指定的数据类型。
- @ExcelIgnore注解
@ExcelIgnore注解用于标记Java对象中不需要映射为Excel中的列的属性。使用该注解后,EasyExcel将自动忽略该属性,不对其进行映射。
- @ExcelPropertyRange注解
@ExcelPropertyRange注解用于标记Excel文件中某个列的取值范围。该注解包含两个属性:min和max。如果Excel文件中该列的取值范围不符合要求,则EasyExcel会抛出异常。
- @ExcelHeadRowNumber注解
@ExcelHeadRowNumber注解用于标记Excel文件中表头所在的行号,默认为0,即第一行。如果设置为1,则表示表头在第二行。使用该注解可以灵活地配置表头所在的位置。
EasyExcel的主要核心源码涉及到数据读取和写入两个方面,下面将分别进行详细的代码展示如下。
1. 数据读取
(1) ExcelReader类
首先来看ExcelReader类,它是EasyExcel中的核心类之一,用于读取Excel文件中的数据。以下是ExcelReader的定义:
java复制代码public class ExcelReader<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelReader.class);
private Sheet sheet;
private Workbook workbook;
private Class<T> currentSheetClazz;
// 省略部分成员变量及构造方法
}
ExcelReader类包含了Sheet对象、Workbook对象和当前Sheet对应的Java类信息,这些信息在进行数据读取时都会用到。
(2) read(ReadSheet readSheet)方法
read(ReadSheet readSheet)方法是ExcelReader类中读取数据的核心方法,其定义如下:
java复制代码public void read(ReadSheet readSheet) {
try {
readSheet.setClazz(currentSheetClazz);
readSheet.init();
process(readSheet);
} finally {
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
LOGGER.warn("Close IO exception ,msg is {}", e.getMessage());
}
}
}
}
该方法首先将当前Sheet对应的Java类信息设置到读取配置ReadSheet中,然后初始化ReadSheet对象,并调用process方法进行数据读取。
(3) process(ReadSheet readSheet)方法
process(ReadSheet readSheet)方法是ExcelReader中最核心的数据读取方法,其定义如下:
java复制代码private void process(ReadSheet readSheet) {
// 从Excel文件中读取所有的数据行
List<List<String>> rows = readSheet.getHead() == null ? sheet2List() : sheet2List(readSheet.getStartSheetIndex(), readSheet.getEndSheetIndex());
// 获取Java类中用于映射Excel中数据的属性列表
List<Field> fieldList = ReflectionUtil.getFieldListWithExcelColumn(currentSheetClazz);
// 缓存读取到的Java对象列表
List<T> dataList = new ArrayList<>();
if (CollectionUtils.isEmpty(rows)) {
return;
}
// 遍历Excel文件中每一行数据,将每一行数据映射为Java对象并添加到dataList中
for (int i = readSheet.getHead().getRowIndex(); i < rows.size(); i++) {
List<String> row = rows.get(i);
T data = ReflectionUtil.newInstance(currentSheetClazz);
for (int j = 0; j < fieldList.size(); j++) {
Field field = fieldList.get(j);
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
int index = excelProperty.index();
if (index >= row.size()) {
continue;
}
String value = row.get(index);
ReflectionUtil.setFieldValue(field, data, value);
}
dataList.add(data);
}
// 将读取到的数据返回给调用方
readSheet.getResultList().addAll(dataList);
}
该方法首先通过sheet2List方法将Excel文件中的每一行数据读取到List<List>类型的rows集合中,然后通过反射机制将Excel中的数据映射为Java对象并添加到dataList中,最后将dataList返回给调用方。
(4) sheet2List方法
sheet2List方法是ExcelReader类中的一个私有方法,用于将Excel文件中的所有数据读取到List<List>类型的rows集合中。以下是sheet2List方法的实现:
java复制代码private List<List<String>> sheet2List() {
// 从Sheet中获取所有行
int rownum = sheet.getLastRowNum();
List<List<String>> rows = new ArrayList<>(rownum);
for (int i = sheet.getFirstRowNum(); i <= rownum; i++) {
Row row = sheet.getRow(i);
if (null == row) {
continue;
}
List<String> cells = new ArrayList<>(row.getLastCellNum());
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
String cellValue = ExcelUtil.getCellValue(cell);
cells.add(cellValue);
}
rows.add(cells);
}
return rows;
}
该方法首先通过Sheet对象的getLastRowNum方法获取Excel文件中的总行数,然后遍历每一行数据,将每一行数据读取到List类型的cells集合中,并将所有行的数据添加到一个List<List>类型的rows集合中,最终返回rows集合。
2. 数据写入
(1) ExcelWriter类
ExcelWriter类是EasyExcel中的另一个核心类,用于写入数据到Excel文件中。以下是ExcelWriter类的定义:
java复制代码public class ExcelWriter extends AbstractExcelWriter<WriteSheet> {
// 省略部分代码及构造方法
}
ExcelWriter类继承自AbstractExcelWriter类,其主要作用是将WriteSheet对象中的数据写入到Excel文件中。
(2) write(List data, WriteSheet sheet)方法
write(List data, WriteSheet sheet)方法是ExcelWriter类中最核心的方法之一,它负责将Java对象集合data写入到Excel文件中。以下是write方法的定义:
java复制代码public void write(List data, WriteSheet sheet) {
sheetHolder.set(sheet);
if (sheet == null) {
return;
}
sheet.init();
int index = sheetHolder.get().getIndex() == null ? 0 : sheetHolder.get().getIndex();
String sheetName = sheetHolder.get().getSheetName() == null ? "Sheet" + index : sheetHolder.get().getSheetName();
currentSheet = workbook.createSheet(sheetName);
write(data);
sheetHolder.remove();
}
该方法首先将当前的WriteSheet对象设置到sheetHolder中,并进行相应的初始化工作,然后创建一个新的Sheet对象,并将Java对象中的数据写入到该Sheet对象中,最后清空sheetHolder中的内容。
(3) write(List data)方法
write(List data)方法是ExcelWriter类中真正的数据写入方法,其定义如下:
java复制代码private void write(List data) {
WriteHandler handler = sheetHolder.get().getWriteHandler();
if (handler != null && handler instanceof WorkbookHolder) {
((WorkbookHolder) handler).setWorkbook(workbook);
}
// 获取Java对象中用于映射Excel中数据的属性列表
List<Field> fieldList = ReflectionUtil.getFieldListWithExcelColumn(data.get(0).getClass());
// 设置Excel文件中的表头
setHead(handler, fieldList);
try {
// 遍历Java对象并将其写入到Excel文件中
for (int i = 0; i < data.size(); i++) {
Object rowModel = data.get(i);
setIndexValue(i + 1);
Row row = currentSheet.createRow(getRowIndex());
for (int j = 0; j < fieldList.size(); j++) {
Field field = fieldList.get(j);
if (needIgnore(j)) {
continue;
}
String stringValue = ReflectionUtil.getFieldStringValue(field, rowModel);
Cell cell = row.createCell(j);
if (handler != null && handler instanceof AbstractCellStyleStrategy) {
((AbstractCellStyleStrategy) handler).setCellStyle(cell, field, rowModel, getStringValue(stringValue));
}
CellData cellData = converterAndSet(cell, stringValue, field);
setCellComment(row, field, cellData);
}
}
} finally {
setIndexValue(null);
}
}
在该方法中,首先获取Java对象中用于映射Excel中数据的属性列表,并设置Excel文件中的表头。然后遍历Java对象并将其写入到Excel文件中,将Java对象中的每个属性值写入到Excel文件对应单元格中,并设置单元格样式、注释等信息。
三、小结一下
通过本文的简单介绍,相信大家对于了解使用EasyExcel进行高效的Excel数据操作已经有了一个基础的入门认识。无论是读取Excel文件、写入Excel文件还是填充Excel文件,EasyExcel都提供了非常简单、易用且高效的解决方案。在实际工作中,我们可以结合自身的需求,选择不同的EasyExcel技巧来更好地完成任务。同时,我们还需要注意一些细节问题,以确保Excel操作的正确性和效率。最后,我也希望大家能够通过阅读本文,更好地掌握Springboot和EasyExcel的使用技巧,并在实际工作中得到应用,给具体的项目添砖加瓦~ v ~ v ~。
作者:Cosolar
链接:https://juejin.cn/post/7243727901782376509
相关推荐
- 作为后端开发,你知道MyBatis有哪些隐藏的 “宝藏” 扩展点吗?
-
在互联网大厂后端开发领域,MyBatis作为一款主流的持久层框架,凭借其灵活的配置与强大的数据处理能力,广泛应用于各类项目之中。然而,随着业务场景日趋复杂、系统规模不断扩张,开发过程中常面临SQL...
- 基于Spring+SpringMVC+Mybatis分布式敏捷开发系统架构(附源码)
-
前言zheng项目不仅仅是一个开发架构,而是努力打造一套从前端模板-基础框架-分布式架构-开源项目-持续集成-自动化部署-系统监测-无缝升级的全方位J2EE企业级开发解...
- 基于Java实现,支持在线发布API接口读取数据库,有哪些工具?
-
基于java实现,不需要编辑就能发布api接口的,有哪些工具、平台?还能一键发布、快速授权和开放提供给第三方请求调用接口的解决方案。架构方案设计:以下是一些基于Java实现的无需编辑或只需少量编辑...
- Mybatis Plus框架学习指南-第三节内容
-
自动填充字段基本概念MyBatis-Plus提供了一个便捷的自动填充功能,用于在插入或更新数据时自动填充某些字段,如创建时间、更新时间等。原理...
- 被你误删了的代码,在 IntelliJ IDEA中怎么被恢复
-
在IntelliJIDEA中一不小心将你本地代码给覆盖了,这个时候,你ctrl+z无效的时候,是不是有点小激动?我今天在用插件mybatisgenerator自动生成mapper的时候,...
- 修改 mybatis-generator 中数据库类型和 Java 类型的映射关系
-
使用mybatis-generator发现数据库类型是tinyint(4),生成model时字段类型是Byte,使用的时候有点不便数据库的类型和Model中Java类型的关系...
- 又被问到了, java 面试题:反射的实现原理及用途?
-
一、反射的实现原理反射(Reflection)是Java在运行时动态获取类的元数据(如方法、字段、构造器等)并操作类对象的能力。其核心依赖于...
- Spring Boot 中JPA和MyBatis技术那个更好?
-
你在进行SpringBoot项目开发时,是不是也经常在选择JPA和MyBatis这两个持久化技术上犯难?面对众多前辈的经验之谈,却始终拿不准哪种技术才最适合自己的项目?别担心,今天咱们就...
- Spring Boot (七)MyBatis代码自动生成和辅助插件
-
一、简介1.1MyBatisGenerator介绍MyBatisGenerator是MyBatis官方出品的一款,用来自动生成MyBatis的mapper、dao、entity的框架,让...
- 解决MyBatis Generator自动生成.java.1文件
-
MyBatis框架操作数据库,一张表对应着一个实体类、一个Mapper接口文件、一个Mapper映射文件。一个工程项目通常最少也要几十张表,那工作量可想而知非常巨大的,MyBatis框架替我们想好了解...
- Linux yq 命令使用详解
-
简介yq是一个轻量级、可移植的命令行...
- Python学不会来打我(62) json数据操作汇总
-
很多小伙伴学了很久的python一直还是没有把数据类型之间的转换搞明白,上一篇文章我们详细分享了python的列表、元组、字典、集合之间的相互转换,这一篇文章我们来分享json数据相关的操作,虽然严格...
- 之前3W买的Python全系列教程完整版(懂中文就能学会)
-
今天给大家带来了干货,Python入门教程完整版,完整版啊!完整版!言归正传,小编该给大家介绍一下这套教程了,希望每个小伙伴都沉迷学习,无法自拔...
- x-cmd pkg | grex - 正则表达式生成利器,解决手动编写的烦恼
-
简介grex是一个旨在简化创作正则表达式的复杂且繁琐任务的库和命令行程序。这个项目最初是DevonGovett编写的JavaScript工具regexgen的Rust移植。但re...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 作为后端开发,你知道MyBatis有哪些隐藏的 “宝藏” 扩展点吗?
- 基于Spring+SpringMVC+Mybatis分布式敏捷开发系统架构(附源码)
- 基于Java实现,支持在线发布API接口读取数据库,有哪些工具?
- Mybatis Plus框架学习指南-第三节内容
- 被你误删了的代码,在 IntelliJ IDEA中怎么被恢复
- 修改 mybatis-generator 中数据库类型和 Java 类型的映射关系
- 又被问到了, java 面试题:反射的实现原理及用途?
- Spring Boot 中JPA和MyBatis技术那个更好?
- Spring Boot (七)MyBatis代码自动生成和辅助插件
- 解决MyBatis Generator自动生成.java.1文件
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)