每日一例 | easyExcel简单读写
共 12241字,需浏览 25分钟
·
2021-05-09 20:24
前言
在web
开发中,我们经常会遇到数据导入或者导出excel
的需求,如果用原生的poi
(阿帕奇的顶级项目,项目地址:https://poi.apache.org/
),虽然能够满足我们的需求,但是原生的接口用起来很不方便,数据格式都需要我们设定,而且它又是基于单元格的操作,在多个数据导出导入的场景下,每个场景都需要定制化的导出入方法,很不方便。
那有没有一个组件,能够根据我们的Vo
导出excel
,导出的时候,每行一条数据,传入一个lsit
就可以实现所有数据的导出;导入的时候,指定vo
,然后就可以把excel
转成一个vo
的list
,方便我们的操作?
easyExcel是什么
有呀,当然有呀,easyExcel
就是这样的一个组件,它是由阿里巴巴开发的一个基于Java
的简单、省内存的读写Excel
的开源组件,在尽可能节约内存的情况下支持读写百M
的Excel
。
github
地址:https://github.com/alibaba/easyexcel
根据官方文档,该组件有着较好的性能:
接下来,我们就来看下如何在我们自己的项目中快速地使用它。
简单应用
添加依赖
首先需要先引入easyExcel
的依赖,目前最新的发布版本是2.2.6
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
创建数据对应的VO
这里用到了lombox
,所有就不需要自己创建getter
和setter
方法,如果你不想用lombox
,可以手动创建getter/setter
方法。
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* @program: example-2021.05.08
* @description: demoData
* @author: syske
* @date: 2021-05-08 18:12
*/
@Data
public class DemoData {
@ExcelProperty("名称")
private String name;
@ExcelProperty("标题")
private String title;
@ExcelProperty("描述")
private String description;
}
核心的点就一个,@ExcelProperty
其实就是指定数据的表头,当然也可以通过注解的方式,直接指定表头样式
简单写excel
public static String writeExcel() {
String fileName = UUID.randomUUID().toString() + ".xlsx";
// 创建ExcelWriterBuilder
ExcelWriterBuilder write = EasyExcel.write(fileName, DemoData.class);
// 创建sheet
ExcelWriterSheetBuilder sheet = write.sheet("模板");
// 构建数据
DemoData demoData = new DemoData();
demoData.setDescription("描述信息");
demoData.setName("名称");
demoData.setTitle("标题");
List<DemoData> dataList = Lists.newArrayList(demoData);
// 写入数据
sheet.doWrite(dataList);
return fileName;
}
注释已经够详细了,这里再简单解释下,我们先要创建ExcelWriterBuilder
,这里要指定生成的excel
的完整文件名(包括保存路径)和excel
对应的VO
;
然后再创建sheet
,如果经常用excel
的小伙伴应该知道,一个excel
可以创建多个sheet
,而且sheet
的名字必须唯一,这里我们指定的sheet
名称是“模板”;
再接着,我们要创建我们要写入的数据,也就是前面VO
对应的List
。
最后,将List
的数据写入。
跑一下上面的代码,会生成这样的excel
:
我们并没有指定表头,但是发现生成的excel
是有表头的,而且就是我们前面创建VO
指定的ExcelProperty
,这也印证了我们前面的说法,当然它也支持自定义表头,我们稍后再看
简单读excel
自定义解析事件监听
相比写,读稍微复杂一点,需要我们自定义一个EventListener
,继承AnalysisEventListener
就可以了:
public class DemoDataListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<DemoData> list = Lists.newArrayList();
public DemoDataListener() {}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
System.out.println("解析数据:" + JSON.toJSONString(data));
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
LOGGER.info("存储数据库成功!");
}
}
这里其实就相当于excel
的解析器,我们只需要重写相应的方法即可。invoke(DemoData data, AnalysisContext context)
方法是每解析一行数据,就会被调用,在这里你可以做数据的校验和转换操作;doAfterAllAnalysed(AnalysisContext context)
是所有数据解析完成后进行的操作,类似回调函数,你可以根据自己的业务需求进行修改。
开始读
然后读取的话,就很简单了:
public static void readExcel(String filePath) {
EasyExcel.read(filePath, DemoData.class, new DemoDataListener()).sheet().doRead();
}
默认情况下,数据是从第二行开始读取的,第一行默认为表头,当然你也可以通过headRowNumber(Integer headRowNumber)
指定从第几行开始读取:
EasyExcel.read(filePath, DemoData.class, new DemoDataListener()).sheet().headRowNumber(0).doRead();
另外,有一点需要注意,就是读取的时候,excel
的字段顺序要和VO
的字段顺序保持一致,否则会出现串行的问题,当然你也可以通过指定字段顺序的方式解决这个问题,索引顺序从0
开始,当然这个index
也会影响导出的excel
里面的字段顺序。
设定写的样式
设定样式有两种方式,一种是通过代码的方式设定,另一种就是通过注解的方式实现,我们先看第一种方式。
代码设定样式
public static String writeExcel() {
String fileName = UUID.randomUUID().toString() + ".xlsx";
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 20);
headWriteCellStyle.setWriteFont(headWriteFont);
// 设定bord
headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
headWriteCellStyle.setBorderTop(BorderStyle.THIN);
headWriteCellStyle.setBorderRight(BorderStyle.THIN);
headWriteCellStyle.setBorderLeft(BorderStyle.THIN);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 背景绿色
contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
// 设定边框样式
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
WriteFont contentWriteFont = new WriteFont();
// 字体大小
contentWriteFont.setFontHeightInPoints((short) 20);
contentWriteCellStyle.setWriteFont(contentWriteFont);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// 设定样式
ExcelWriterBuilder write = EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy);
ExcelWriterSheetBuilder sheet = write.sheet("模板");
DemoData demoData = new DemoData();
demoData.setDescription("描述信息");
demoData.setName("名称");
demoData.setTitle("标题");
List<DemoData> dataList = Lists.newArrayList(demoData);
sheet.doWrite(dataList);
return fileName;
}
代码和上面写的代码一样,只是增加了样式的设定,就是在创建ExcelWriterBuilder
的时候,指定样式registerWriteHandler(horizontalCellStyleStrategy)
。
setFillForegroundColor
设定背景颜色,也就是填充颜色;
setFontHeightInPoints
设定字体大小;
setWriteFont
是设定字体样式;
setBorder
是设定边框样式;
然后我们再来看下生成的效果:
但是我发现,这里的样式没法指定列宽,下面我们看下注解的样式是不是可以指定。
注解设定样式
首先我们看下列宽度如何设定,设置方式很简单,只需要在对应的字段上加上ColumnWidth
注解即可:
之后的效果如下
然后,我们在通过注解设定其他样式,我在名称上面添加如下注解:
然后生成的效果变成这样了:
代码里面的样式设定也没有删除,说明启用注解之后,代码里面设定的样式就失效了。其中,HeadStyle
是设定标题栏样式,HeadFontStyle
是设定标题字体字体样式,ContentStyle
是设定内容的样式,ContentFontStyle
是设置内容的字体样式,样式的内容可以根据自己的需求进行调整,这里就不作过多的说明了。
总结
easyExcel
对于列表式的数据导入导出,是特别友好的,而且用起来也特别方便,但是对于不规律的表格(比如票据)poi
可能是更好的选择,当然easyExcel
本身也是基于poi
实现的,只是前者对用户更友好。
简单总结下,今天我们通过几个简单的示例,演示了如何用easyExcel
实现数据的导入导出,展示了设置样式的两种方式,可以说上面的这些内容基本上可以满足我们大部分的应用场景,但如果你还有很多其他的业务需求,建议你再去研究下官方文档,更高级的用法还有很多,今天我们算是抛砖引玉了,有兴趣的小伙伴自己去看吧!
好了,今天是母亲节,让我们一起祝所有的母亲节日快乐,当然更重要的是别忘了给自己的妈妈打个电话,给一句问候,一句关心……
项目路径:
https://github.com/Syske/example-everyday
本项目会每日更新,让我们一起学习,一起进步,遇见更好的自己,加油呀
- END -