基于EasyExcel实现多Sheet数据导出功能详解

8 次阅读

EasyExcel是阿里巴巴开源的一款基于Java语言的Excel处理框架,相比传统的Apache POI,它采用流式读写方式,有效降低了大文件导出时的内存占用,因此在企业级系统中被广泛应用。实际业务开发中,Excel导出往往不只是单个Sheet的数据输出,而是需要按照业务模块、用户分类、时间范围等维度生成多个Sheet页。基于EasyExcel实现多Sheet数据导出,可以满足复杂报表、数据分析、运营统计等场景需求。

一、多Sheet导出的应用场景

单Sheet导出适用于数据结构简单的业务,例如用户列表、订单列表等。但随着系统功能不断扩展,数据展示需求也更加复杂,多Sheet Excel文件逐渐成为常见方案。

常见应用场景包括:

1. 分类数据导出

例如企业管理系统中,需要将不同部门的数据分别导出:

  • Sheet1:研发部门人员信息

  • Sheet2:销售部门人员信息

  • Sheet3:财务部门人员信息

用户打开Excel后即可快速定位对应数据。

2. 多维度报表生成

统计系统通常需要生成多个分析页面:

  • 销售汇总数据

  • 产品销售明细

  • 客户订单记录

  • 区域销售排名

通过多个Sheet展示不同维度的数据,可以提高报表可读性。

3. 数据分批导出

当单个Sheet数据量较大时,可以按照日期、区域或者业务类型拆分:

  • 2026年1月数据

  • 2026年2月数据

  • 2026年3月数据

避免单个Sheet数据过多导致Excel打开缓慢。


二、EasyExcel多Sheet导出的核心原理

EasyExcel导出Excel文件主要依赖ExcelWriter对象。

普通单Sheet导出通常直接调用:

Java
EasyExcel.write(response.getOutputStream(), UserData.class)
        .sheet("用户信息")
        .doWrite(dataList);

而多Sheet导出需要使用ExcelWriter持续写入不同Sheet:

Java
ExcelWriter excelWriter = EasyExcel.write(outputStream, UserData.class)
        .build();

WriteSheet sheet1 = EasyExcel.writerSheet(0, "用户信息")
        .build();

WriteSheet sheet2 = EasyExcel.writerSheet(1, "订单信息")
        .build();

excelWriter.write(userList, sheet1);
excelWriter.write(orderList, sheet2);

excelWriter.finish();

其中:

  • ExcelWriter负责整个Excel文件生命周期管理

  • WriteSheet代表一个具体Sheet页

  • write()方法负责向指定Sheet写入数据

  • finish()用于释放资源并完成文件生成


三、Spring Boot项目集成EasyExcel

在Spring Boot项目中,可以通过Maven引入EasyExcel依赖。

XML

    com.alibaba
    easyexcel
    3.3.4

引入依赖后即可使用EasyExcel提供的导出功能。

项目结构示例:

controller
 └── ExcelController.java

service
 └── ExcelExportService.java

entity
 └── UserData.java
 └── OrderData.java

通常将Excel生成逻辑放在Service层,Controller只负责接收请求并返回文件流。


四、定义Excel数据实体类

EasyExcel通过实体类映射Excel列。

例如用户数据:

Java
@Data
public class UserData {

    @ExcelProperty("用户编号")
    private Long id;

    @ExcelProperty("用户名")
    private String username;

    @ExcelProperty("手机号")
    private String phone;
}

订单数据:

Java
@Data
public class OrderData {

    @ExcelProperty("订单编号")
    private String orderNo;

    @ExcelProperty("订单金额")
    private BigDecimal amount;

    @ExcelProperty("创建时间")
    private Date createTime;
}

通过@ExcelProperty注解,可以控制Excel表头名称和字段映射关系。


五、实现多Sheet导出完整示例

假设系统需要导出用户信息和订单信息两个Sheet。

Controller代码:

Java
@GetMapping("/export")
public void export(HttpServletResponse response) throws IOException {

    response.setContentType(
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    );

    response.setCharacterEncoding("UTF-8");

    String fileName = URLEncoder.encode(
        "业务数据报表",
        StandardCharsets.UTF_8
    );

    response.setHeader(
        "Content-Disposition",
        "attachment;filename=" + fileName + ".xlsx"
    );

    excelService.export(response.getOutputStream());
}

Service实现:

Java
public void export(OutputStream outputStream) {

    List<UserData> userList = getUserData();

    List<OrderData> orderList = getOrderData();


    ExcelWriter excelWriter =
            EasyExcel.write(outputStream)
            .build();


    WriteSheet userSheet =
            EasyExcel.writerSheet(0, "用户信息")
            .head(UserData.class)
            .build();


    WriteSheet orderSheet =
            EasyExcel.writerSheet(1, "订单信息")
            .head(OrderData.class)
            .build();


    excelWriter.write(userList, userSheet);

    excelWriter.write(orderList, orderSheet);


    excelWriter.finish();
}

生成后的Excel文件结构:

业务数据报表.xlsx

├── 用户信息
│     ├── 用户编号
│     ├── 用户名
│     └── 手机号
│
└── 订单信息
      ├── 订单编号
      ├── 订单金额
      └── 创建时间

六、不同Sheet使用不同数据模型

实际开发中,不同Sheet的数据结构通常不同。

例如:

员工信息:

Java
@Data
public class EmployeeExcel {

    @ExcelProperty("员工姓名")
    private String name;

    @ExcelProperty("职位")
    private String position;
}

薪资信息:

Java
@Data
public class SalaryExcel {

    @ExcelProperty("员工编号")
    private String employeeId;

    @ExcelProperty("基本工资")
    private Double salary;
}

导出时:

Java
ExcelWriter writer =
        EasyExcel.write(outputStream)
        .build();


writer.write(
        employeeList,
        EasyExcel.writerSheet("员工信息")
        .head(EmployeeExcel.class)
        .build()
);


writer.write(
        salaryList,
        EasyExcel.writerSheet("薪资信息")
        .head(SalaryExcel.class)
        .build()
);


writer.finish();

这种方式可以让每个Sheet拥有独立的表头和数据结构,更符合复杂业务需求。


七、多Sheet动态生成实现方式

很多系统中的Sheet数量并不是固定的,例如按照月份生成Sheet。

示例:

Java
ExcelWriter writer =
        EasyExcel.write(outputStream)
        .build();


for(int i = 1; i <= 12; i++){

    List<OrderData> list =
            queryOrderByMonth(i);


    WriteSheet sheet =
            EasyExcel.writerSheet(
                i - 1,
                i + "月份订单"
            )
            .head(OrderData.class)
            .build();


    writer.write(list, sheet);
}


writer.finish();

最终生成:

订单统计.xlsx

├── 1月份订单
├── 2月份订单
├── 3月份订单
...
└── 12月份订单

这种方式非常适合年度报表、财务统计等业务场景。


八、多Sheet导出的性能优化技巧

1. 避免一次加载全部数据

如果数据量达到几十万甚至百万级,不建议直接查询全部数据:

Java
List<Data> list = mapper.selectAll();

这种方式容易造成内存压力。

推荐分页查询:

Java
int page = 1;

while(true){

    List<Data> list =
        queryPage(page,1000);

    if(list.isEmpty()){
        break;
    }

    writer.write(list,sheet);

    page++;
}

利用EasyExcel流式写入,可以明显降低内存消耗。


2. 合理控制Sheet数量

虽然Excel支持多个Sheet,但过多Sheet会影响文件打开速度。

建议:

  • 按业务维度拆分

  • 避免生成大量空Sheet

  • 控制单个文件大小


3. 使用自动关闭机制

如果手动管理资源,容易出现文件损坏。

推荐:

Java
try(ExcelWriter writer =
    EasyExcel.write(outputStream).build()){

    writer.write(data,sheet);

}

确保异常情况下资源正常释放。


九、设置Sheet样式优化展示效果

EasyExcel支持自定义样式,例如:

  • 表头加粗

  • 设置背景颜色

  • 调整列宽

  • 日期格式化

示例:

Java
@HeadStyle(
    fillPatternType = FillPatternType.SOLID_FOREGROUND
)
public class UserData {

}

也可以通过WriteHandler实现更加复杂的样式控制。


十、常见问题及解决方案

1. 导出的Excel打不开

常见原因:

  • ExcelWriter.finish()未调用

  • 输出流提前关闭

  • 文件名编码异常

解决:

确保完整执行:

Java
writer.finish();

2. Sheet名称重复导致异常

Excel要求同一个文件中的Sheet名称不能完全相同。

错误:

Java
writerSheet("用户")
writerSheet("用户")

应该修改为:

Java
writerSheet("用户1")
writerSheet("用户2")

3. 大数据导出内存溢出

原因:

一次性加载大量数据到List。

解决:

  • 分页查询

  • 流式写入

  • 控制单Sheet数据规模


4. 日期格式显示异常

可以使用:

Java
@DateTimeFormat(
    pattern="yyyy-MM-dd"
)

或者:

Java
@ExcelProperty("创建时间")
private String createTime;

提前格式化时间。


十一、EasyExcel多Sheet导出的优势总结

相比传统POI手动创建Workbook,EasyExcel实现多Sheet导出具有明显优势:

  1. API简单,开发效率高

  2. 支持百万级数据流式写入

  3. 内存占用低

  4. 支持复杂表头和样式扩展

  5. 与Spring Boot项目结合方便

  6. 适合企业级报表系统开发

在实际项目中,多Sheet导出通常需要结合数据查询、权限控制、异步任务、文件存储等模块共同实现。掌握EasyExcel的多Sheet写入机制,可以有效提升Java后台系统处理Excel报表需求的能力。