EasyExcel的简单使用
前言
EasyExcel类是一套基于Java的开源Excel解析工具类,相较于传统的框架如Apache poi、jxl等更加快速、简洁,还可以解决大文件内存溢出问题,即能让使用者在不用考虑性能、内存的等因素的情况下,快速完成Excel的读(导入)、写(导出)等功能。
版本支持:
2+版本支持Java7&Java6
3+版本支持Java8
这里使用的EasyExcel版本为3.1.1,JDK版本为1.8.0_161,同时辅助使用lombok和fastjson以简化代码或转化为Jason数据。
Maven依赖配置:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> //非必要
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> //非必要
<version>1.2.47</version>
</dependency>
</dependencies>
Excel读
样例内容:
1.实体类
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TextReadObject {
@ExcelProperty(index = 0)
private Integer studentId;
@ExcelProperty(index = 1)
private String studentName;
@ExcelProperty(index = 2)
private String institute;
@ExcelProperty(index = 3)
private Integer level_11;
@ExcelProperty(index = 4)
private Integer level_12;
@ExcelProperty(index = 5)
private Integer level_21;
@ExcelProperty(index = 6)
private Integer level_22;
}
其中注解@ExcelProperty可包含两个参数index和value,在简单表头(即表头只占用一行)中以下两条注解基本等价
@ExcelProperty(index = 0)
@ExcelProperty(value = “学号”)
而在复杂表头(即本例)中,需要使用index表示。
另外需要注意的是加入表头名字出现重复,会导致只有一个字段读取到数据,此外在读取操作时不建议index和value同时使用。综上所述,在已知excel表头内容的情况下使用参数index。
2.读监听器与测试类
四个监听器,这里使用前两个
名称 | 说明 |
---|---|
AnalysisEventListener < T > | 分析事件侦听器:接收解析的每条数据的返回。 |
SyncReadListener | 同步读取侦听器。 |
AbstractIgnoreExceptionReadListener | 抽象忽略异常读取侦听器。 |
ModelBuildEventListener | 模型构建事件侦听器。 |
AnalysisEventListener < T >
所有已实现的接口:Listener、ReadListener
直接已知子类:SyncReadListener
返回值类型 | 方法 | 说明 |
---|---|---|
boolean | hasNext | 验证是否有另一条数据,可以通过返回 false 来停止读取。 |
void | invokeHead | 分析第一行时触发调用函数。 |
void | invokeHeadMap | 以map的形式放回表头,覆盖当前方法以接收表头数据 |
void | onException | 任何一个监听器进行错误报告时,所有监听器都会收到此方法 |
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.Map;
import java.util.List;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class DemoDataListener extends AnalysisEventListener<TextReadObject> {
private List<TextReadObject> dataList;
//读取表头的内容
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头->"+headMap);
}
//一行一行读取excel中的内容
@Override
public void invoke(TextReadObject data, AnalysisContext context) {
dataList.add(data);
}
//读取完成之后执行的方法
@Override
public void doAfterAllAnalysed(AnalysisContext context) {}
}
读取Excel的测试类:
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
public class ExcelImport {
public static void simpleRead() {
String fileName = "F:\\rdtext.xls";
List<TextReadObject> dataList = new ArrayList<>();
//每次会读取100条数据然后返回过来,直接调用使用数据就行
EasyExcel.read(fileName, TextReadObject.class, new DemoDataListener(dataList))
.sheet(0)//读取第一个sheet
.headRowNumber(3) //跳过前三行表头内容,假如是简单表头则这句可省略
.doRead();
//若需要实现读取全部sheet,可以使用.doReadAll()代替.sheet(0).doRead()
for (TextReadObject dl : dataList) {
System.out.println(JSON.toJSONString(dl));
}
}
public static void main(String[] args) { simpleRead(); }
}
SyncReadListener:
所有已实现的接口:Listener、ReadListener
直接已知父类:AnalysisEventListener < T >
返回值类型 | 方法 | 说明 |
---|---|---|
void | doAfterAllAnalysed | 如果有什么操作在全部分析结束后执行 |
List < Object > | getList | |
void | invoke | 当分析一行触发器调用函数 |
void | setList (List < Object > list) | |
此处将监听器写到测试类内部 |
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ExcelImportSync {
public static void simpleRead() {
String fileName = "F:\\text.xls";
final List dataList = new ArrayList();
EasyExcel.read(fileName, TextReadObject.class, new SyncReadListener() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头->"+headMap);
}
@Override
public void invoke(Object object, AnalysisContext context) {
dataList.add(object);
}
}).sheet(0).headRowNumber(3).doRead();
for (Object o : dataList) {
TextReadObject TOB = (TextReadObject) o;
System.out.println(JSON.toJSONString(TOB));
}
}
public static void main(String[] args) { simpleRead(); }
}
相较于AnalysisEventListener < T >,SyncReadListener更加适合对多种实体类实施相同操作的情况,在定义监听器时没有指定具体的实体类。
3.输出结果
二者输出结果一样:
Excel写
1.实体类
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ColumnWidth(15) //列宽,最大值为255
@HeadRowHeight(16) //表头行高
@ContentRowHeight(16) //数据行高
public class TextWriteObject {
//复杂表头自动合并相同的内容
@ExcelProperty(index = 0, value = {"学号", "学号", "学号"})
private Integer studentId;
@ExcelProperty(index = 1, value = {"姓名", "姓名", "姓名"})
private String studentName;
@ColumnWidth(25)//单独设置列宽
@ExcelProperty(index = 2, value = {"学院", "学院", "学院"})
private String institute;
//复杂表头嵌套
@ExcelProperty(index = 3, value = {"成绩", "第一学年", "第一学期"})
private Integer level_11;
@ExcelProperty(index = 4, value = {"成绩", "第一学年", "第二学期"})
private Integer level_12;
@ExcelProperty(index = 5, value = {"成绩", "第二学年", "第一学期"})
private Integer level_21;
@ExcelProperty(index = 6, value = {"成绩", "第二学年", "第二学期"})
private Integer level_22;
}
此时在注解@ExcelProperty中可以同时使用参数index和value,用于同时指定位置和内容。
其他未使用注解:
@ContentStyle
用于设置内容格式
参数 | 说明 |
---|---|
dataFormat | 日期格式 |
hidden | 设置单元格使用此样式隐藏 |
locked | 设置单元格使用此样式锁定 |
quotePrefix | 在单元格前面增加`符号,数字或公式将以字符串形式展示 |
horizontalAlignment | 设置是否水平居中 |
wrapped | 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见 |
verticalAlignment | 设置是否垂直居中 |
rotation | 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°~90°,07版本的Excel旋转角度区间为0°-180° |
indent | 设置单元格中缩进文本的空格数 |
borderLeft | 设置左边框的样式 |
borderRight | 设置右边框样式 |
borderTop | 设置上边框样式 |
borderBottom | 设置下边框样式 |
leftBorderColor | 设置左边框颜色 |
rightBorderColor | 设置右边框颜色 |
topBorderColor | 设置上边框颜色 |
bottomBorderColor | 设置下边框颜色 |
fillPatternType | 设置填充类型 |
fillBackgroundColor | 设置背景色 |
fillForegroundColor | 设置前景色 |
shrinkToFit | 设置自动单元格自动大小 |
@ContentFontStyle
用于设置单元格内容字体格式
参数 | 说明 |
---|---|
fontName | 字体名称 |
fontHeightInPoints | 字体高度 |
italic | 是否斜体 |
strikeout | 是否设置删除水平线 |
color | 字体颜色 |
typeOffset | 偏移量 |
underline | 下划线 |
bold | 是否加粗 |
charset | 编码格式 |
@HeadFontStyle
用于定制标题字体格式
参数 | 说明 |
---|---|
fontName | 设置字体名称 |
fontHeightInPoints | 设置字体高度 |
italic | 设置字体是否斜体 |
strikeout | 是否设置删除线 |
color | 设置字体颜色 |
typeOffset | 设置偏移量 |
underline | 设置下划线 |
charset | 设置字体编码 |
bold | 设置字体是否加粗 |
@ExcelIgnore
不将该字段转换成Excel
@ExcelIgnoreUnannotated
没有注解的字段都不转换
2.写入Excel的测试类
import com.alibaba.excel.EasyExcel;
import java.util.ArrayList;
import java.util.List;
public class ExcelExport {
public static void simpleWrite(){
String fileName = "F:\\wttext.xls";
List<TextWriteObject> dataList = new ArrayList<>();
dataList.add(new TextWriteObject(2022101, "张三",
"生命科学院", 653, 602, 683, 707));
dataList.add(new TextWriteObject(2022102, "李四",
"生命科学院", 568, 596, 611, 632));
dataList.add(new TextWriteObject(2022103, "王五",
"生命科学院", 606, 673, 624, 653));
dataList.add(new TextWriteObject(2022201, "赵六",
"语言文学院", 710, 722, 686, 703));
EasyExcel.write(fileName, TextWriteObject.class)
.sheet(0)
.doWrite(dataList);
}
public static void main(String[] args) { simpleWrite(); }
}
3.输出结果
填充Excel
填充功能可以事先在Excel中设计好格式和排版,再在后台将需要导出的数据传入fill方法完成最终Excel文件。
1.Excel模板
此模板允许多条填充,以第一列为例,若为{studentId}
则仅允许单条填充。
如果本来就有 {
和 }
,用转义\{
和\}
代替。
2.测试类
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import java.util.ArrayList;
import java.util.List;
public class ExcelFill {
public static void simpleFill(){
List dataList = new ArrayList();
dataList.add(new TextWriteObject(2022101, "张三",
"生命科学院", 653, 602, 683, 707));
dataList.add(new TextWriteObject(2022102, "李四",
"生命科学院", 568, 596, 611, 632));
dataList.add(new TextWriteObject(2022103, "王五",
"生命科学院", 606, 673, 624, 653));
dataList.add(new TextWriteObject(2022201, "赵六",
"语言文学院", 710, 722, 686, 703));
String writeFile = "F:\\filltext.xls";
String templateFile = "F:\\template.xls";
ExcelWriterBuilder writerBuilder = EasyExcel
.write(writeFile, TextReadObject.class)
.withTemplate(templateFile);
WriteSheet writeSheet = writerBuilder.sheet().build();
ExcelWriter excelWriter = writerBuilder.build();
//在填充玩多结果数据后,要强制换行,不然后续的单结果数据会发生覆盖现象
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
excelWriter.fill(dataList, fillConfig, writeSheet);
excelWriter.finish();//调用finish方法,关闭文件流
}
public static void main(String[] args) { simpleFill(); }
}
3.输出结果
更详细的内容请参考官方文档:
https://easyexcel.opensource.alibaba.com/docs/current/