excel-plus
是基于 Apache POI 框架的一款扩展封装小库,让我们在开发中更快速的完成导入导出的需求。
尽管很多人会提出 poi
能干这事儿为什么还要封装一层呢?
excel-plus
很大程度上简化了代码、让使用者更轻松的
读、写 Excel 文档,也不用去关心格式兼容等问题,很多时候我们在代码中会写很多的 for
循环,各种 getXXXIndex
来获取行或列让代码变的更臃肿。多个项目之间打一枪换一个地方,代码 Copy 来 Copy 去十分凌乱,
如果你也在开发中遇到类似的问题,那么 excel-plus
是你值得一试的工具。
excel-plus
不是万能的,比如你想合并某几列,或者让第三行的某一列设置样式或特殊格式,
很抱歉它是做不到的,因为这让事情复杂化了,即便支持也会像原始的 POI API 一样让人痛恶。
如果真的需要,你可能需要在网络上寻找一些 Utils
结尾的工具类自行编写了,祝你好运 :P
如果你在使用过程中遇到什么问题或者建议可以发一个 issue 告诉我
- 基于 Java 8 开发
- 简洁的 API 操作
- 注解驱动
- 高性能低损耗
- 可配置列顺序
- 支持按模板导出
- 支持过滤行数据
- 支持数据类型转换
- 支持自定义列样式
- 支持读取时校验
- 支持一行代码下载 Excel 文件
- 支持 Excel 2003、2007、CSV 格式
加入以下 maven
依赖到你的 pom.xml
文件中,该项目使用的 poi
版本是 4.0.1,
如果你的项目已经存在,请注意删除或者排除依赖。
<dependency>
<groupId>io.github.biezhi</groupId>
<artifactId>excel-plus</artifactId>
<version>1.0.8</version>
</dependency>
也可以使用快照版本,最新的 bug 修复和功能更新都在这里
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependency>
<groupId>io.github.biezhi</groupId>
<artifactId>excel-plus</artifactId>
<version>1.0.8-SNAPSHOT</version>
</dependency>
注意:这里的版本号请使用
maven
仓库较新版本,可在 Github 的 README 中看到。
下面是我们的 Java 模型类,用于存储 Excel 的行数据。
public class Sample {
@ExcelColumn(index = 0, datePattern = "M/d/yy")
private LocalDate date;
@ExcelColumn(index = 1)
private String location;
@ExcelColumn(index = 4)
private int proportion;
@ExcelColumn(index = 5)
private double ss;
@ExcelColumn(index = 6)
private BigDecimal amount;
// getter setter 省略
}
这是一个简单的模型类,使用 @ExcelColumn
来匹配 Excel 中的列关系,这个表格的数据在 这里。
测试的 Excel 文档中有很多个 Sheet
,我们只需读取名为 SalesOrders
的就可以了,其他的不关心。
List<Sample> samples = Reader.create(Sample.class)
.from(new File("SampleData.xlsx"))
.sheet("SalesOrders")
.start(1)
.asList();
这样就可以读取到了,非常简单!
这里设置
start
为 1 的原因:
- 读取行的索引总是从 0 开始
- 这个表格中索引为 0 的行是列信息,故从索引为 1 的开始读取
接下来试试写入一个表格到磁盘上吧 :)
List<Sample> samples = new ArrayList<>();
// 这里的数据需自行准备
Writer.create()
.headerTitle("一份简单的Excel表格")
.withRows(samples)
.to(new File("sample_test.xlsx"));
此时看看本地是否产生了一个名为 sample_test.xlsx
的 Excel 表格。
读取 Excel 文档通过 Reader
API 来完成,你只需要创建一个 Reader 对象,就可以读取文档了。
导入包的时候注意是
io.github.biezhi.excel.plus.Reader
创建 Reader 的方式可以通过构造函数或者工厂方法,我们建议你这样使用:
Reader.create(Sample.class);
这里是 Sample.class
是一个 Java 中的类型,它和 Excel 的行进行绑定,通过 @ExcelColumn
来表示列关系。
有些时候在一个 Excel 文档中有多个 Sheet,默认这个库会读取第一个,也就是 index
为 0 的 Sheet。
如果你想读取其他的 excel-plus
提供了 API 帮助你。
Reader.create(Sample.class)
.from(new File("SampleData.xlsx"))
.sheet(1)
这样会读取 index
为 1 的 Sheet,如果你想按名称读取可以参考如下代码
Reader.create(Sample.class)
.from(new File("SampleData.xlsx"))
.sheet("sheetName")
默认情况,Reader
会从索引为 2 的行开始读取,有些时候我们的表格并非有表头或者标题,所以需要重新设置开始读取的行。
这里设置的是一个索引值,假设 Excel 中只有 2 行数据,没有其他的,那么可以这样设置:
Reader.create(Sample.class)
.from(new File("SampleData.xlsx"))
.start(0)
如果数据行上面有一行列头显示,我们就可以从索引为 1 的行开始读取
Reader.create(Sample.class)
.from(new File("SampleData.xlsx"))
.start(1)
大多数情况下 Excel 以文件的形式存在,在某些特殊情况下可能是一个 InputStream
,excel-plus
也支持从流中读取文档数据。
但你要记住,File
参数形式的效率会更高,因为内部的一些判断和 POI 本身的机制导致。
Reader.create(Sample.class)
.from(YOU_INPUT_STREAM)
有时候我们需要对读取的行数据做一下过滤,这时候就可以使用 filter
函数来筛选出合适的数据项。
List<Sample> samples = Reader.create(Sample.class)
.from(new File(classPath() + "/SampleData.xlsx"))
.sheet("SalesOrders")
.startRow(1)
.asStream()
.filter(sample -> sample.getAmount().intValue() > 1000)
.collect(toList());
为了方便,我们也支持直接读取一份 CSV 文档,使用方式和前面没有差异,只是在 from
的时候文件名不同了而已。
写入一份 Excel 文档通过使用 Writer
API 来完成,创建一个 Writer 对象就可以操作 Excel 写入了。
导入包的时候注意是
io.github.biezhi.excel.plus.Writer
你可以通过使用构造函数的方式或者工厂方法来创建一个 Writer 对象,下面的方式更简洁:
Writer.create();
默认情况下创建的 Writer 对象会写入一个 XLSX
格式的 Excel 文档,如果你要写入一份 XLS
或者 CSV
文档的话可以修改入参
Writer.create(ExcelType.XLS);
Writer.create(ExcelType.CSV);
默认写入一份 Excel 文档的 Sheet 名称是 Sheet0
,如果你在意这个名字的话可以修改它。
Writer.create().sheet("my_sheet");
设置标题是一个可选项,如果你想在写入 Excel 的时候加入一个大标题,如 “2018 年 5 月 书籍 TOP 10”。
Writer.create().headerTitle("2018 年 5 月 书籍 TOP 10");
该标题在 Excel 文档生成后显示在第一行,自动合并为一列。
这一选项不建议使用,默认是通过是否设置标题来计算得出的,如果你愿意中间空一些行再写入的话可以设置。
Writer.create().start(4);
这将从索引为 4 的行开始写入。
大多数情况下我们是无需设置样式的,在 excel-plus
中提供了设置表头和列的样式 API。
在某些需求下可能需要设置字体大小、颜色、居中等,你可以像下面的代码这样干。
如果你对样式的操作不熟悉可以参考 POI 的列设置 文档。
Writer.create()
.headerTitle("一份自定义样式的Excel表格")
.withRows(buildData())
.titleStyle((wb, style) -> {
Font font = wb.createFont();
font.setFontHeightInPoints((short) 40);
font.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
style.setFont(font);
})
.headerStyle((wb, style) -> {
Font font = wb.createFont();
font.setFontHeightInPoints((short) 20);
font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
style.setFont(font);
})
.cellStyle((wb, style) -> {
Font font = wb.createFont();
font.setFontHeightInPoints((short) 20);
font.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex());
style.setFont(font);
})
.to(new File(fileName));
为了方便我们将查询的数据直接输出到浏览器弹出下载,excel-plus
也做了一点 手脚 让你一行代码就可以搞定。
如果你使用的是基于 servlet
的应用可以使用如下方式。
Writer.create()
...
.to(ResponseWrapper.createXLSX(servletResponse, "xxx表格.xlsx"))
只需要将 HttpServletResponse
对象传入,并输入导出的文件名称,其他的都见鬼去吧。
有时候我们需要导出的 Excel 表格样式比较复杂,可以事先设置好一个模板表格,数据为空, 由程序向模板中填入数据,然后导出即可,这样就满足了美观的需求。
Writer.create()
.withTemplate(classPath() + "/template.xls")
.withRows(buildData())
.to(new File(fileName));
需要注意的是这里的
template.xls
位于classpath
路径下。
Reader
: 用于读取一份 Excel 文档Writer
: 用于写入一份 Excel 文档Converter
: 数据类型转换的顶层接口,处理自定义的读取、写入规则
create(Class)
:创建指定类型的 Readerfrom(File)
:从文件中读取from(InputStream)
:从 InputStream 中读取startRow(int)
:设置从第几行开始读,索引从 0 开始sheet(int)
:要读取的 sheet 索引,默认为 0sheet(String)
:要读取的 sheet 名称,如果设置则不会根据 sheetIndex 读取asStream()
:将读取结果存储在 Stream 中返回asList()
:将读取结果存储在 List 中返回
Writer(ExcelType)
:构造函数,写入什么类型的文件,支持 XLSX、XLS、CSV 格式withRows(Collection)
:写入的数据,该方法接收一个集合sheet(String)
:写入的 Sheet 名称,默认为Sheet0
startRow(int)
:从第几行开始写入,索引从 0 开始,默认是计算出的,建议不设置headerTitle(String)
:Sheet 的大标题,可选项titleStyle(BiConsumer)
:自定义标题样式headerStyle(BiConsumer)
:自定义列头样式cellStyle(BiConsumer)
:自定义行中的单元格样式withTemplate(File)
:根据模板文件创建 ExcelbufferSize(int)
:写入一个 XLSX 格式的文件时缓冲大小,默认为 100,建议不修改withRaw()
:自定义写入行,启用该配置后不会根据集合数据写 ExcelcreateRow(int)
:withRaw
启用后可使用该 API,用于自定义创建Row
和Cell
isAppend(boolean)
: 默认为false,设置为true文件写入将使用追加而不是覆盖to(File)
:写入 Excel 文档到文件to(OutputStream)
:写入 Excel 文档到 OutputStream
通过使用注解来配置如何读取、写入 Excel 文档。
@ExcelColumn 注解
选项 | 默认值 | 描述 |
---|---|---|
index |
-1 |
用于标识 Excel 中的列索引,从 0 开始,该选项适用于读取或写入 Excel |
title |
"" |
导出 Excel 时的列名称,如:状态、姓名、手机号 |
datePattern |
"" |
日期格式化的 pattern ,对 Date 、LocalDate 、LocalDateTime 生效 |
converter |
NullConverter.class |
数据类型转换的类 Class,实现自 Converter 接口,实现类需提供无参构造函数 |
width |
-1 |
导出为 Excel 时的列宽度,建议以 字符数 * 256 为基准进行设置 |
在使用过程中遇到什么问题或者建议可以发一个 issue
v1.0-SNAPSHOT
- 修复性能问题
- 重构部分 API
- 简化代码