(记)Excel导出优化之路

(记)Excel导出优化之路

经过了几个月的迭代,项目上的导出组件逐渐完善,想以本篇文章来记录项目上的导出组件的优化过程。

Excel导出组件是一个注解驱动的spring-boot-starter导出组件,利用Spring AOP拦截controller中的GET方法的查询API,并通过注解声明在DTO上来表示数据与excel中的映射关系和单元格属性,依赖于Apache POI完成excel数据填充的工作。

  • 与easyexcel比较

easyexcel提供了非常简单方便的导出api,支持注解驱动的导出配置,以及excel的读取和写入api,且声称在内存占用上消耗非常少。

Excel导出组件支持注解驱动的导出配置,而同时也提供了相对灵活的低层api,另外,Excel导出组件还支持异步,并封装了HTTP下载逻辑,在使用时无需关心文件下载的流操作。

Excel导出组件的API在单一需求的导出场景下更具优势(基于数据库查询的导出场景)。

Excel导出组件支持灵活分页导出,可根据配置调整,减少内存占用。

声明

由于源码逻辑比较复杂,看起来比较晦涩难懂,这里我手写了一个简单的demo,以及通过监控工具、统计数据来逐步分析和优化,感兴趣的可以下载源码跑看看。

环境准备:

Jdk8

Maven

Idea

项目地址:

Demo代码已上传至个人Github:https://github.com/XCXCXCXCX/export-optimization

优化之路

  • 传统POI导出

导出组件的诞生就是为了简化业务团队的开发工作,减少代码量,基于aop做出来的第一版,使用了Apache POI做excel数据填充的工作。

使用示例:

@GetMapping
public List<UserDTO> list() {
   
  return userService.list();
}


@GetMapping
@Export
public List<UserDTO> export() {
   
  return userService.list();
}

// 同时需要在UserDTO上声明数据填充映射关系和属性
// 简单示例如下
@ExportDTO
class UserDTO {
   
  
  @ExportColumn(column="id", width=100)
  private long id;
  
  @ExportColumn(column="name", color = Color.RED)
  private String name;
  
}

第一版的逻辑非常简单:

  1. 查询list数据
  2. 将list数据填充到一个excel的一个sheet中
  3. 设置excel下载响应头,写入响应流并结束响应

第一版基本能满足一些小项目的需求。

代码demo如下:

public class ExcelExporterV1 implements ExcelExporter {
   

    private List<String> data;

    public ExcelExporterV1(List<String> data) {
   
        this.data = data;
    }

    @Override
    public void export0() {
   
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        SXSSFSheet sheet = workbook.createSheet("sheet0");;
        for (int i = 0; i < data.size(); i++) {
   
            int index = i / 1000000;
            if (index > workbook.getNumberOfSheets() - 1) {
   
                workbook.createSheet("sheet" + index);
            }
            sheet = workbook.getSheetAt(index);
            SXSSFRow row = sheet.createRow(i);
            SXSSFCell cell = row.createCell(0);
            cell.setCellValue(data.get(i));
        }
        try {
   
            sheet.flushRows();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
        File file = Static.getFile("v1-" + UUID.randomUUID() + ".xlsx");
        try (FileOutputStream fos = new FileOutputStream(file)){
   
            workbook.write(fos);
        } catch (IOException e) {
   
            e.printStackTrace()

你可能感兴趣的:(记,java,后端)