EasyExcel
Posted 皓洲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EasyExcel相关的知识,希望对你有一定的参考价值。
EasyExcel
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。
官网:(https://github.com/alibaba/easyexcel)
常见api · 语雀 (https://www.yuque.com/easyexcel/doc/api)。
定义格式
package com.bootcrab.cos.dto.coms.easyexcel;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
/**
* @author ZhzGod
* @date 2022/4/25 17:44
* @introduction
*/
public class CardIdentifierRequestDTO
/**
* 客户编号
*/
//@ExcelProperty("客户编号")
@ExcelProperty(index = 0)
private String customerId;
public String getCustomerId()
return customerId;
public void setCustomerId(String customerId)
this.customerId = customerId;
监听模板
package com.bootcrab.cos.service.coms.notice.batch.easyexcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.fastjson.JSON;
import com.bootcrab.cos.dto.coms.easyexcel.CardIdentifierRequestDTO;
import com.bootcrab.cos.service.third.social.CreditInfoInquireService;
import com.bootcrab.cos.util.DateProUtil;
import com.bootcrab.cos.xface.dto.maintenance.ocr.dopa.XfaceCardIdentifierRequestDTO;
import com.bootcrab.cos.xface.dto.maintenance.ocr.dopa.XfaceCardIdentifierResponseDTO;
import com.bootcrabframework.cloud.core.component.SessionContext;
import com.bootcrabframework.cloud.core.util.CommonUtil;
import com.bootcrabframework.cloud.core.util.IDUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* @author ZhzGod
* @date 2022/4/25 18:05
* @introduction
*/
public class DemoTestListener extends AnalysisEventListener<CardIdentifierRequestDTO>
private CreditInfoInquireService creditInfoInquireService;
private static int cnt=1;
//注入service
public DemoTestListener(CreditInfoInquireService creditInfoInquireService)
this.creditInfoInquireService = creditInfoInquireService;
private static final Logger LOGGER = LoggerFactory.getLogger(DemoTestListener.class);
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<CardIdentifierRequestDTO> list = new ArrayList<CardIdentifierRequestDTO>();
/**
* 读取时,每条数据都会从这里解析
*/
@Override
public void invoke(CardIdentifierRequestDTO data, AnalysisContext context)
// LOGGER.info("解析到一条数据:", JSON.toJSONString(data));
list.add(data);
cnt++;
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT)
saveData();
// 存储完成清理 list
list.clear();
/**
* 所有数据解析完成了 都会来调用
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context)
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
/**
* 加上存储数据库
*/
private void saveData()
// LOGGER.info("条数据,开始存储数据库!", list.size());
//这里真实的保存数据。
// LOGGER.info("存储数据库成功!");
/**
* 读取表头数据
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context)
LOGGER.info("解析到一条头数据:", JSON.toJSONString(headMap));
/**
* 读取额外信息
* @param extra
* @param context
*/
@Override
public void extra(CellExtra extra, AnalysisContext context)
LOGGER.info("读取到了一条额外信息:", JSON.toJSONString(extra));
switch (extra.getType())
case COMMENT:
LOGGER.info("额外信息是批注,在rowIndex:,columnIndex;,内容是:", extra.getRowIndex(), extra.getColumnIndex(),
extra.getText());
break;
case HYPERLINK:
if ("Sheet1!A1".equals(extra.getText()))
LOGGER.info("额外信息是超链接,在rowIndex:,columnIndex;,内容是:", extra.getRowIndex(),
extra.getColumnIndex(), extra.getText());
else if ("Sheet2!A1".equals(extra.getText()))
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:,firstColumnIndex;,lastRowIndex:,lastColumnIndex:,"
+ "内容是:",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex(), extra.getText());
else
LOGGER.info("Unknown hyperlink!");
break;
case MERGE:
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:,firstColumnIndex;,lastRowIndex:,lastColumnIndex:",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex());
break;
default:
/**
* 用日期去接字符串 肯定报错,此时需要用到异常处理
* 在转换异常获取其他异常下会调用本接口。
* 抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
*/
@Override
public void onException(Exception exception, AnalysisContext context)
LOGGER.error("第行,解析失败,但是继续解析下一行:",cnt,exception.getMessage());
// 如果是某一个单元格的转换异常 能获取到具体行号
// 如果要获取头的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException)
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
LOGGER.error("第行,第列解析异常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
main方法测试:
public class DemoMain
public static void main(String[] args)
String fileName = "D:\\\\excel.xlsx";
//读取单个sheet
EasyExcel.read(fileName, ImportContent.class, new DemoTestListener())
// 需要读取批注 默认不读取
.extraRead(CellExtraTypeEnum.COMMENT)
// 需要读取超链接 默认不读取
.extraRead(CellExtraTypeEnum.HYPERLINK)
// 需要读取合并单元格信息 默认不读取
.extraRead(CellExtraTypeEnum.MERGE).sheet()
.doRead();
//多个sheet,读取全部
// 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写。
EasyExcel.read(fileName, ImportContent.class, new DemoTestListener()).doReadAll();
//以下定义自定义格式转换
EasyExcel.read(fileName, ImportContent.class, new DemoTestListener())
// 若全局使用自定义转换可以用registerConverter,所有java为string,excel为string的都会用这个转换器。
// 如果就想单个字段使用请使用@ExcelProperty 指定converter
// .registerConverter(new CustomStringStringConverter())
.sheet()
//如果多行头,可以设置其他值。默认第一行为行头。
.headRowNumber(1)
.doRead();
//可以同步返回进行数据处理,但是不推荐,数据量大会放到内存里。
List<ImportContent> list = EasyExcel.read(fileName).head(ImportContent.class).sheet().doReadSync();
以上是关于EasyExcel的主要内容,如果未能解决你的问题,请参考以下文章