说明

最近有很多数据要处理,需要导出Excel表格。在使用POI时发现非常耗内存,在GitHub上发现阿里开源的Easy Excel项目,基于java的读写Excel,十分省内存。本篇博文主要是总结记录了使用EasyExcel进行写Excel的方法。

正文

引入依赖

在pom.xml文件引入easyexcel依赖,我使用的是2.1.4版本,目前最新是2.1.6。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.4</version>
</dependency>

简单写Excel

这是最基本的使用方式。通过在pojo类的属性上使用@ExcelProperty(“列名”)注解来指定该属性所属列名,通过@ExcelIgnore注解来忽略该属性。不同与之前的1.x版本,数据的pojo类不需要再继承BaseModel类。

官方指导文件中,提供了两种简单写的方法:

  1. 直接通过EasyExcel调用write方法
EasyExcel.write(fileName, clazz).sheet(sheetName).doWrite(dataList);
  1. 分别创建ExcelWriter和WriteSheet对象,调用excelWriter的write方法,并且在写完后要手动调用excelWriter的finish方法关闭流。
ExcelWriter excelWriter = EasyExcel.write(fileName, claxx).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
excelWriter.write(dataList, writeSheet);
excelWriter.finish();

在使用中,封装了一个Util类,通过createExcel进行简单的写:

public static <T> void createExcel(String filePath, List<T> dataList, String sheetName, Class<T> clazz) throws Exception {

    try {
        EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

动态生成复杂头写Excel

在导出数据要求中,需要针对每天的数据进行统计写入表格,而日期范围是不确定的,这就需要动态生成表头,并且在要求中,数据统计还分多个维度。所以,写excel的同时要先生成相对应的复杂头。

在官方文档中,有示例介绍如何实现负责头的写入。在pojo类中,对每个属性使用了@ExcelProperty({“主标题”, “子标题”})注解指定了属性对应列的复杂头名称。

示例:

public class ComplexHeadData {
    @ExcelProperty({"主标题", "字符串标题"})
    private String string;
    @ExcelProperty({"主标题", "日期标题"})
    private Date date;
    @ExcelProperty({"主标题", "数字标题"})
    private Double doubleData;
    
    ....省略set get方法
}

同样通过在EasyExcel.write方法进行写入。

我们知道了固定复杂头的写入方式,那么动态复杂头的写入,第一步就是要创建复杂头的List<List>。

如果要想得到与上示代码同样的复杂头结构,则需要:

public List<List<String>> getHead() {
        List<List<String>> headList = new ArrayList<>();
        List<String> head1 = new ArrayList<>();
        head1.add("主标题");
        head1.add("字符串标题");
        headList.add(head1);

        List<String> head2 = new ArrayList<>();
        head2.add("主标题");
        head2.add("日期标题");
        headList.add(head2);

        List<String> head3 = new ArrayList<>();
        head3.add("主标题");
        head3.add("数字标题");
        headList.add(head3);

        List<String> head4 = new ArrayList<>();
        head4.add("主标题II");
        headList.add(head4);
        return headList;
}

在构造数据时,也应该是List<List>,每个List表示表格中的一行数据。注意,list中数据中的顺序要和生成头中列名的顺序保持一致。

public List<List<String>> getdata() {
    List<List<String>> dataList = new ArrayList<>();
    List<String> list1 = new ArrayList<>();
    list1.add("1");
    list1.add("2");
    list1.add("3");
    list1.add("4");
    dataList.add(list1);
    List<String> list2 = new ArrayList<>();
    list2.add("5");
    list2.add("6");
    list2.add("7");
    list2.add("8");
    dataList.add(list2);
    return dataList;
}

导出表格示例:
在这里插入图片描述

同样,在Util类中封装了creatExcelDynamicHead方法。

public static <T> void createExcelDynamicHead(String filePath, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
    try {
        EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

重复多个sheet写Excel

在数据要求中,需要一个Excel中包含多个sheet,这就需要一个excel多次写入。在官方文档中,对此重复多次写入(写到单个或者多个Sheet)有详细的介绍。总共介绍了三种方法,每种实现不同的功能:

  1. 数据分批写到同一个sheet
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 这里注意 如果同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
  // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
  List<DemoData> data = data();
  excelWriter.write(data, writeSheet);
}
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
  1. 写到多个不同的sheet
// 方法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<DemoData> data = data();
  excelWriter.write(data, writeSheet);
}
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
  1. 写多个sheet,数据不同
    与第二种方法类似,但不同的是,在每次新建WriteSheet对象时,需要指定不同的数据类对象。
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 <T> void createExcelManySheets(String filePath, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
    ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
    try {
        int index = 0;
        for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
            String sheetName = entry.getKey();
            List<T> 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();
        }
    }
}

web中的写入下载

通过该方法对生成的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的输出流。

EasyExcelUtil

public class EasyExcelUtil {

    public static <T> void createExcel(String filePath, List<T> dataList, String sheetName, Class<T> clazz) throws Exception {

        try {
            EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelDynamicHead(String filePath, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
        try {
            EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelManySheets(String filePath, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
        ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
        try {
            int index = 0;
            for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
                String sheetName = entry.getKey();
                List<T> 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 <T> void createExcelWeb(OutputStream outputStream, List<T> dataList, String sheetName, Class<T> clazz) throws Exception{
        try {
            EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelDynamicHeadWeb(OutputStream outputStream, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
        try {
            EasyExcel.write(outputStream).head(head).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelManySheetsWeb(OutputStream outputStream, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
        ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build();
        try {
            int index = 0;
            for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
                String sheetName = entry.getKey();
                List<T> 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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐