最近有很多数据要处理,需要导出Excel表格。在使用POI时发现非常耗内存,在GitHub上发现阿里开源的Easy Excel项目,基于java的读写Excel,十分省内存。本篇博文主要是总结记录了使用EasyExcel进行写Excel的方法。
在pom.xml文件引入easyexcel依赖,我使用的是2.1.4版本,目前最新是2.1.6。
com.alibaba
easyexcel
2.1.4
这是最基本的使用方式。通过在pojo类的属性上使用@ExcelProperty(“列名”)注解来指定该属性所属列名,通过@ExcelIgnore注解来忽略该属性。不同与之前的1.x版本,数据的pojo类不需要再继承BaseModel类。
在官方指导文件中,提供了两种简单写的方法:
EasyExcel.write(fileName, clazz).sheet(sheetName).doWrite(dataList);
ExcelWriter excelWriter = EasyExcel.write(fileName, claxx).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
excelWriter.write(dataList, writeSheet);
excelWriter.finish();
在使用中,封装了一个Util类,通过createExcel进行简单的写:
public static void createExcel(String filePath, List dataList, String sheetName, Class clazz) throws Exception {
try {
EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
在导出数据要求中,需要针对每天的数据进行统计写入表格,而日期范围是不确定的,这就需要动态生成表头,并且在要求中,数据统计还分多个维度。所以,写excel的同时要先生成相对应的复杂头。
在官方文档中,有示例介绍如何实现负责头的写入。在pojo类中,对每个属性使用了@ExcelProperty({“主标题”, “子标题”})注解指定了属性对应列的复杂头名称。
示例:
public class ComplexHeadData {
@ExcelProperty({"主标题", "字符串标题"})
private String string;
@ExcelProperty({"主标题", "日期标题"})
private Date date;
@ExcelProperty({"主标题", "数字标题"})
private Double doubleData;
....省略set get方法
}
同样通过在EasyExcel.write方法进行写入。
我们知道了固定复杂头的写入方式,那么动态复杂头的写入,第一步就是要创建复杂头的List。
如果要想得到与上示代码同样的复杂头结构,则需要:
public List> getHead() {
List> headList = new ArrayList<>();
List head1 = new ArrayList<>();
head1.add("主标题");
head1.add("字符串标题");
headList.add(head1);
List head2 = new ArrayList<>();
head2.add("主标题");
head2.add("日期标题");
headList.add(head2);
List head3 = new ArrayList<>();
head3.add("主标题");
head3.add("数字标题");
headList.add(head3);
List head4 = new ArrayList<>();
head4.add("主标题II");
headList.add(head4);
return headList;
}
在构造数据时,也应该是List,每个List表示表格中的一行数据。注意,list中数据中的顺序要和生成头中列名的顺序保持一致。
public List> getdata() {
List> dataList = new ArrayList<>();
List list1 = new ArrayList<>();
list1.add("1");
list1.add("2");
list1.add("3");
list1.add("4");
dataList.add(list1);
List list2 = new ArrayList<>();
list2.add("5");
list2.add("6");
list2.add("7");
list2.add("8");
dataList.add(list2);
return dataList;
}
同样,在Util类中封装了creatExcelDynamicHead方法。
public static void createExcelDynamicHead(String filePath, List dataList, List> head, String sheetName) throws Exception {
try {
EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
在数据要求中,需要一个Excel中包含多个sheet,这就需要一个excel多次写入。在官方文档中,对此重复多次写入(写到单个或者多个Sheet)有详细的介绍。总共介绍了三种方法,每种实现不同的功能:
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 这里注意 如果同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List data = data();
excelWriter.write(data, writeSheet);
}
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
// 方法2 如果写到不同的sheet 同一个对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 指定文件
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo
writeSheet = EasyExcel.writerSheet(i, "模板").build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List data = data();
excelWriter.write(data, writeSheet);
}
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变
writeSheet = EasyExcel.writerSheet(i, "模板").head(DemoData.class).build();
.....
}
在Util类中,封装了createExcelManySheets方法,该方法是对第二种使用相同的数据写入多个sheet方法的封装。datMap的key为不同sheet的名称。
public static void createExcelManySheets(String filePath, Map> dataMap, Class clazz) throws Exception {
ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
try {
int index = 0;
for (Map.Entry> entry : dataMap.entrySet()) {
String sheetName = entry.getKey();
List data = entry.getValue();
WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
excelWriter.write(data, sheet);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
通过该方法对生成的excel进行下载。在官方文档中也有详细的示例:
将数据写入到HttpServletResponse的输出流outputstream中。
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
可以发现,与以上调用EasyExcel.write方法进行写入不同的是将filename替换为了response的输出流。
public class EasyExcelUtil {
public static void createExcel(String filePath, List dataList, String sheetName, Class clazz) throws Exception {
try {
EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void createExcelDynamicHead(String filePath, List dataList, List> head, String sheetName) throws Exception {
try {
EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void createExcelManySheets(String filePath, Map> dataMap, Class clazz) throws Exception {
ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
try {
int index = 0;
for (Map.Entry> entry : dataMap.entrySet()) {
String sheetName = entry.getKey();
List data = entry.getValue();
WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
excelWriter.write(data, sheet);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
public static void createExcelWeb(OutputStream outputStream, List dataList, String sheetName, Class clazz) throws Exception{
try {
EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void createExcelDynamicHeadWeb(OutputStream outputStream, List dataList, List> head, String sheetName) throws Exception {
try {
EasyExcel.write(outputStream).head(head).sheet(sheetName).doWrite(dataList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void createExcelManySheetsWeb(OutputStream outputStream, Map> dataMap, Class clazz) throws Exception {
ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build();
try {
int index = 0;
for (Map.Entry> entry : dataMap.entrySet()) {
String sheetName = entry.getKey();
List data = entry.getValue();
WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
excelWriter.write(data, sheet);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
}
更多的使用方式请查阅官方文档。
参考资料:
https://alibaba-easyexcel.github.io/index.html
https://www.cnblogs.com/oukele/p/11444234.html