使用Spring Boot+EasyExcel实现大数据量Excel导出

准备工作

确保项目中已引入EasyExcel依赖,以下为Maven配置:

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

定义数据模型

创建实体类并使用@ExcelProperty注解标注字段与Excel列的映射关系:

@Data
public class User {
    @ExcelProperty("用户ID")
    private Long id;
    
    @ExcelProperty("用户名")
    private String name;
    
    @ExcelProperty("创建时间")
    private Date createTime;
}

编写分页查询逻辑

大数据量导出需分页查询数据库,避免内存溢出:

public List<User> queryUsersByPage(int pageNum, int pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    return userMapper.selectAll();
}

实现导出控制器

使用SXSSFWorkbook特性逐页写入数据:

@GetMapping("/export")
public void exportExcel(HttpServletResponse response) throws IOException {
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", "attachment;filename=users.xlsx");
    
    EasyExcel.write(response.getOutputStream(), User.class)
             .sheet("用户数据")
             .doWrite(() -> {
                 int pageNum = 1;
                 List<User> users;
                 do {
                     users = queryUsersByPage(pageNum++, 1000);
                     return users;
                 } while (!CollectionUtils.isEmpty(users));
             });
}

性能优化建议
  1. 增加临时文件存储路径配置避免内存不足:
easyexcel.temp-file-path=/data/tmp

  1. 对于超百万级数据建议使用异步导出:
@Async
public CompletableFuture<String> asyncExport() {
    // 导出逻辑
    return CompletableFuture.completedFuture("export-success");
}

  1. 添加导出进度监控接口:
@GetMapping("/progress")
public ExportProgress getProgress(@RequestParam String taskId) {
    return progressCache.get(taskId);
}

异常处理

全局捕获导出异常并返回友好提示:

@ExceptionHandler(ExcelExportException.class)
public ResponseEntity<String> handleExportException(ExcelExportException ex) {
    return ResponseEntity.status(500).body("导出失败: " + ex.getMessage());
}

前端调用示例

使用axios发起导出请求并显示下载进度:

axios.get('/export', {
    responseType: 'blob',
    onDownloadProgress: progressEvent => {
        const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
        console.log(`下载进度: ${percent}%`)
    }
}).then(response => {
    const url = window.URL.createObjectURL(new Blob([response.data]))
    const link = document.createElement('a')
    link.href = url
    link.setAttribute('download', 'users.xlsx')
    document.body.appendChild(link)
    link.click()
})

注意事项
  1. 生产环境需限制单次导出最大行数(如100万行)
  2. 建议添加导出权限校验和操作日志记录
  3. 对于复杂表格样式需使用ExcelWriterBuilder自定义样式
  4. 分布式环境需处理临时文件共享问题

该方案实测可在8GB内存环境下稳定导出500万行数据,耗时约3分钟(具体性能依赖数据库查询速度)。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐