当前位置:网站首页>EasyExcel 学习笔记
EasyExcel 学习笔记
2022-06-28 17:39:00 【笑虾】
EasyExcel 学习笔记
基本上就是官方的快速开始,自己走了一遍,并笔记。没有完全照抄官方示例,正好可以做对比。
pom.xml 添加依赖
另外为了方便还引入了fastjson 2.0.3, lombok 1.18.24, junit 4.11
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
</dependency>
测试数据
测试的 excel 放在此处:
private String filePath = "E:\\temp\\测试数据.xlsx";
实体类
- @ExcelProperty 可设置字段。
| 用法 | 说明 |
|---|---|
@ExcelProperty(index = 0) | 指定列的索引 |
@ExcelProperty("日期标题") | 指定列名 |
@ExcelProperty(converter = CustomStringStringConverter.class) | 自定义转换器 |
@DateTimeFormat("yyyy-MM-dd HH:mm:ss") | string 接格式化的日期 |
@NumberFormat("#.##%") | string 接格式的化百分比数字 |
@Data
@EqualsAndHashCode
public class DemoData {
// @ExcelProperty(index = 0)
private String string;
// @ExcelProperty("日期标题")
private Date date;
// @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
// private String dateStr;
private Double doubleData;
}
自定义转换器
public class CustomStringStringConverter implements Converter<String> {
@Override
public Class<?> supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/** 这里读的时候会调用 */
@Override
public String convertToJavaData(ReadConverterContext<?> context) {
return "自定义:" + context.getReadCellData().getStringValue();
}
/** 这里是写的时候会调用 */
@Override
public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
return new WriteCellData<>(context.getValue());
}
}
最简单的读
写法1
- 我们使用自带的监听器 PageReadListener ,它每次会读取
BATCH_COUNT = 100条数据。然后进行消费。 invoke:每一行读取完毕会调用。doAfterAllAnalysed:每个sheet读取完毕会调用。- 我们创建时要给它传个消费者
Consumer<List<T>> consumer。(invoke、doAfterAllAnalysed会调用消费者) - 这里需要指定所使用的实体类型
DemoData.class,读取sheet(默认索引0)后,文件流会自动关闭。 - 以下就是官网的例了,我只是把写法调整了一下:
@Test
public void simpleRead() {
// 这个消费者在 PageReadListener 的 invoke、doAfterAllAnalysed 中会被调用。
Consumer<List<DemoData>> consumer = dataList -> {
dataList.forEach(demoData -> log.info("读取到一条数据{}", JSON.toJSONString(demoData)));
};
// 用上面的消费者创建监听器
PageReadListener<DemoData> myListener = new PageReadListener<>(consumer);
// 开始读取
EasyExcel.read(fileName, DemoData.class, myListener).sheet().doRead();
}
写法2
- 直接用
匿名类实现 ReadListener接口。重写了invoke、doAfterAllAnalysed这两个方法就行了。 - 官方示例代码有点长:略。
写法3
具名类实现 ReadListener接口得到一个监听器。和上面只是具名类与匿名类的区别。
写法4
一个文件一个 ExcelReader
// 这里直接用了前文中的监听器 myListener
try (ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, myListener ).build()) {
// 构建一个sheet 这里可以指定名字或者索引(注意我给的索引是第二个sheet)
ReadSheet readSheet = EasyExcel.readSheet(1).build();
// 读取这个sheet
excelReader.read(readSheet);
}
多行头(跳过N行)
如果头有多行,那么可以指定跳过多少行,开始读取。
只要加了一个 headRowNumber 用于说明头有多少行。
@Test
public void headRead() {
EasyExcel.read(filePath, new NoModelDataListener()).sheet().headRowNumber(7).doRead();
}
读多个sheet
节约篇幅我这里直接用了 PageReadListener。
这里需要注意:每个sheet读取完毕后调用一次doAfterAllAnalysed。
因为这里只给了一个监听器,最后所有sheet都会写进同一个监听器里。(直观的效果就是如下代码每次输出都包含上一次的内容。人个理解是要处理数据的话,在读完最后一个sheet时再一起处理就好了。)
读全部 sheet
EasyExcel.read(fileName, DemoData.class, new PageReadListener<>(dataList -> {
dataList.forEach(demoData -> log.info("读取到一条数据{}", JSON.toJSONString(demoData)));
})).doReadAll();
读部分 sheet
这里读取第1与第3个表,每个sheet对应各自的监听器,所以是分开输出的。
如果用同一个监听器,则效果与上面一样。
// 监听器
Consumer<List<DemoData>> consumer = dataList -> {
dataList.forEach(demoData -> log.info("读取到一条数据{}", JSON.toJSONString(demoData)));
};
// 用上面的监听器,生成 ReadSheet 列表。(第1、第3 个Sheet)
List<ReadSheet> sheets = Stream.of(0, 2)
.map(i -> EasyExcel.readSheet(i)
.head(DemoData.class)
.registerReadListener(new PageReadListener<>(consumer))
.build())
.collect(Collectors.toList());
// 读取 sheets 中的表
try (ExcelReader excelReader = EasyExcel.read(fileName).build()) {
excelReader.read(sheets);
}
同步的返回
与最简单的读的区别只是把doRead 换成 doReadSync。
下面是不带head(DemoData.class)的写法。直接用List<Map<Integer, String>>接。
List<Map<Integer, String>> objects = EasyExcel.read(fileName).sheet().doReadSync();
objects.forEach(demoData -> log.info("读取到一条数据{}", JSON.toJSONString(demoData)));
读取表头数据
懒得从头实现一个监听器,直接用 SyncReadListener 复写 nvokeHeadMap 。
这里设置了headRowNumber(3) 头有3行。
SyncReadListener syncReadListener = new SyncReadListener() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
}
};
EasyExcel.read(fileName, DemoData.class, syncReadListener).sheet().headRowNumber(3).doRead();
额外信息(批注、超链接、合并单元格信息读取)
官网示例代码 中按类型分别判断并处理有点长,我这直接输出就好了。
同样偷个懒重写 SyncReadListener 直接用。
SyncReadListener syncReadListener = new SyncReadListener() {
@Override
public void extra(CellExtra extra, AnalysisContext context) {
log.info("\n额外信息的类型(批注、超链接、合并单元格)是:{};" +
"\n行:{},列{};\n开始行:{},开始列{};\n结束行:{},结束例:{};\n内容为:{}",
extra.getType(),
extra.getRowIndex(), extra.getColumnIndex(),
extra.getFirstRowIndex(), extra.getFirstColumnIndex(),
extra.getLastRowIndex(), extra.getLastColumnIndex(),
extra.getText());
}
};
// 三种额外信息默认都是不读取,需要手动添加。
EasyExcel.read(fileName, null, syncReadListener)
.extraRead(CellExtraTypeEnum.COMMENT)// 读取批注
.extraRead(CellExtraTypeEnum.HYPERLINK)// 读取超链接
.extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();// 读取合并单元格信息
读取公式和单元格类型
关键在于实体中的字体用 CellData 进行包裹,就能拿到单元格信息了。
注意:字段顺序要与表格列对应
@Data
@EqualsAndHashCode
@JSONType(orders = {
"string", "date", "doubleData", "formulaValue"}) // 设置下顺序好看些
public class CellDataReadDemoData {
private CellData<String> string;
private CellData<Date> date; // excel 中的日期值其实是数字
private CellData<Double> doubleData;
private CellData<String> formulaValue; // 不一定能完美的获取,等官方后续
}
List<CellDataReadDemoData> objects = EasyExcel.read(fileName).head(CellDataReadDemoData.class).sheet().doReadSync();
objects.forEach(demoData -> log.info("解析到一条数据{}", JSON.toJSONString(demoData)));
这里表的内容

这是一行的效果
{
"string":{
"data":"字符串0","dataFormatData":{
"format":"General","index":0},"stringValue":"字符串0","type":0
},
"date":{
"data":"2022-06-27 00:00:00","dataFormatData":{
"format":"yyyy/m/d","index":14},"numberValue":44739.0,"type":2
},
"doubleData":{
"data":1.0,"dataFormatData":{
"format":"General","index":0},"numberValue":1.0,"type":2
},
"formulaValue":{
"data":"字符串0447391","dataFormatData":{
"format":"General","index":0},
"formulaData":{
"formulaValue":"A2&B2&C2"},"stringValue":"字符串0447391","type":0
}
}
不创建对象的读
正常创建按表字段,创建实体,然后读数据,没什么好说的。这里看一下:不创建对象的读
监听器
就是官方代码,只是补充了一下注释。
package com.jerry.excel.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
@Slf4j
public class NoModelDataListener extends AnalysisEventListener<Map<Integer, String>> {
/** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */
private static final int BATCH_COUNT = 5;
private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/** * 每一行读取完毕会调用 * @param data 当前行数据 * @param context */
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/** * 每个sheet读取完毕会调用 */
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
log.info("所有数据解析完成!");
}
/** * 写入数据库操作 */
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
log.info("存储数据库成功!");
}
}
测试代码
这注释也是官方的,好像少字了。
@Test
public void noModelRead() {
// 这里 只要,然后读取第一个sheet 同步读取会自动finish
EasyExcel.read(filePath, new NoModelDataListener()).sheet().doRead();
}
参考资料
Easy Excel 官网
Easy Excel 官方文档:快速开始 (常规操作这里都有,照做就行了)
Easy Excel 官方文档:读excel-通用参数
边栏推荐
- 数据源只能连阿里云的云数据库吗?阿里云服务器里装的数据库连不上嘛?
- R programming language - Introduction
- oracle cdc 但是使用的服务名没有sid 该怎么配置呢?
- 工业数字化与新一代数字化系统设计平台----讲座
- 58技术沙龙第三十一期|Flutter动态化专题沙龙
- How to back up a WordPress database
- Use PEGA to develop a simple RPA program
- 2022年山东省安全员C证考试练习题及模拟考试
- Xiaoxin black apple sound card ID injection
- Q: how bad can a programmer be?
猜你喜欢

2022年化工自动化控制仪表考试模拟100题模拟考试平台操作

Redis 原理 - Hash

Kubernetes visual interface dashboard

Redis6笔记04 主从复制,集群,应用问题,Redis6新功能

IDC:阿里云获2021中国数据治理平台市场份额第一

2022a special equipment related management (elevator) special operation certificate examination question bank and online simulation examination

Solve the problem of sqoop error manager SqlManager: Generic SqlManager. listDatabases() not implemented

面部識別試驗涉及隱私安全問題?國外一公司被緊急叫停

win10用cmake3.22与vs2019编译curl库源码并调用

2022危险化学品生产单位安全生产管理人员复习题及答案
随机推荐
How to open a futures account? Where is it safer to open an account?
Flutter 小技巧之 MediaQuery 和 build 优化你不知道的秘密
How to put your WordPress website in maintenance mode
使用Pega进行一个简单的RPA程序开发
想请教股票开户找人办比较方便么?网上开户安全么?
Matlb| visual learning (plot and bar)
面部识别试验涉及隐私安全问题?国外一公司被紧急叫停
Xiaoxin black apple sound card ID injection
Pure big resentment! Those who were discouraged from taking the postgraduate entrance examination
oracle cdc 但是使用的服务名没有sid 该怎么配置呢?
How to configure the Oracle CDC service name without Sid?
工业数字化与新一代数字化系统设计平台----讲座
节点基础~节点层级
Introduction to PMD source code analyzer
[tcapulusdb knowledge base] modify business modify cluster
Google launches advanced API security to protect APIs from security threats
How to back up a WordPress database
Kubernetes visual interface dashboard
Leetcode 6. Z 字形变换(牛逼,解决了)
Go all out to unreal