引言
本文将要说明通过Alibaba的easyExcel技术实现对Excel文档存取的操作,在此之前,同学应该接触过POI技术,是比较早的实现了读写Excel的技术之一,但是有个很大的问题就是很占内存。我在项目中遇到一个问题就是导出客户订单,通常有数十万条记录,采用POI发现内存压力太大,甚至有可能出现内存溢出、服务器宕机的风险,这在线上是不允许存在的,所以想到了采用easyExcel技术,通过实践证明,easyExcel响应快而且相对于POI确实节省了大量的内存。在此,笔者强烈安利这门技术。
快速上手
导包
首先导入需要的jar包,一如既往的采用maven管理jar,导入easyExcel及lombok:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
</dependencies>
写入Excel
首先定义数据模型,本文采用多行复杂的格式:
程序清单1:数据模型
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 12:08
* @description 数据模型
*/
@ContentRowHeight(18)
@HeadRowHeight(25)
@ColumnWidth(25)
public class DataModel {
/**
* 复杂标题 将整合为一个单元格效果如下:
* —————————————————————————
* | 天猫 |
* —————————————————————————
* |旗舰店名称|日期|营收|
* —————————————————————————
*/
/* 旗舰店名称 */
@ExcelProperty({"天猫", "旗舰店名称"})
private String shopName;
/* 日期 */
@ExcelProperty({"天猫", "日期"})
private Date date;
/* 营收数据(小数型) */
@ExcelProperty({"天猫", "营收"})
private Double profit;
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Double getProfit() {
return profit;
}
public void setProfit(Double profit) {
this.profit = profit;
}
}
其次定义对象格式转换:
程序清单2:对象转换
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 12:21
* @description 基础数据类.这里的排序和excel里面的排序一致
*/
public class ConverterData {
/**
* 我想所有的 字符串起前面加上"格式化:"三个字
*/
@ExcelProperty(value = "店铺名称", converter = CustomStringStringConverter.class)
private String shopName;
/**
* 我想写到excel 用年月日时分秒的格式
*/
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期")
private Date date;
/**
* 我想写到excel 用小数表示
*/
@NumberFormat("#.##")
@ExcelProperty(value = "营收")
private Double profit;
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Double getProfit() {
return profit;
}
public void setProfit(Double profit) {
this.profit = profit;
}
}
然后是自定义转换器:
程序清单3:自定义转换器
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 12:24
* @description
*/
public class CustomStringStringConverter implements Converter<String> {
public Class supportJavaTypeKey() {
return String.class;
}
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 这里是读的时候会调用 不用管
*
* @param cellData NotNull
* @param contentProperty Nullable
* @param globalConfiguration NotNull
* @return
*/
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getStringValue();
}
/**
* 这里是写的时候会调用 不用管
*
* @param value NotNull
* @param contentProperty Nullable
* @param globalConfiguration NotNull
* @return
*/
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData("格式化:" + value);
}
}
最后给出写入Excel的工具类:
程序清单4:写入Excel工具类
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 12:33
* @description
*/
public class WriteUtil {
public static void main(String[] args) {
try {
new WriteUtil().simpleWrite();
} catch (Exception e) {
e.printStackTrace();
}
}
public void simpleWrite() throws Exception {
// 写法1
String fileName = "demo1.xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DataModel.class).sheet("店铺每天营收数据").doWrite(dataGenerator());
// 写法2,方法二需要手动关闭流
fileName = "demo2.xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DataModel.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("店铺每天营收数据").build();
excelWriter.write(dataGenerator(), writeSheet);
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
/**
* @description 手动生成数据写入Excel
* @params []
* @returns java.util.List<com.pers.common.DataModel>
*/
private List<DataModel> dataGenerator() {
Date curTime = new Date();
List<DataModel> list = new ArrayList<DataModel>();
for (int i = 0; i < 12; i++) {
DataModel dataModel = new DataModel();
dataModel.setShopName("店铺名称" + i);
dataModel.setDate(curTime);
dataModel.setProfit(i * 66.6);
list.add(dataModel);
}
return list;
}
}
下图是结果图:
读取Excel
读取Excel的时候需要定义监听器:
程序清单5:监听器
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 13:18
* @description
*/
public class DataListenerModel extends AnalysisEventListener<DataModel> {
List<DataModel> list = new ArrayList<DataModel>();
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public DataListenerModel() {
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* @param context
*/
@Override
public void invoke(DataModel data, AnalysisContext context) {
System.out.printf("解析到一条数据:{%s}", JSON.toJSONString(data));
System.out.println();
list.add(data);
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println(JSON.toJSONString(list));
}
}
程序清单6:读取Excel工具类
/**
* @author Carson Chu
* @email 1965704869@qq.com
* @date 2020/1/29 13:20
* @description
*/
public class ReadUtil {
public static void main(String[] args) {
new ReadUtil().simpleRead();
}
public void simpleRead() {
// 写法1:
String fileName = "demo1.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DataModel.class, new DataListenerModel()).sheet().doRead();
// 写法2:
fileName = "demo2.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName, DataModel.class, new DataListenerModel()).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
//写法3:
DataListenerModel readListener = new DataListenerModel();
Sheet sheet = new Sheet(1, 1, DataModel.class);
try {
EasyExcelFactory.readBySax(new FileInputStream(fileName), sheet, readListener);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
源码速传
所有相关源码已经上传到我的GitHub上了,欢迎学习交流,附跳转路径:
easyExcel操作Excel的源码