You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SXSSFWorkbook写入数据时提示document已关闭异常该如何排查

异常触发原因

你的代码执行顺序存在逻辑错误:

  1. 你将workbook::write方法引用绑定给StreamingOutput时,仅做了方法绑定,并未真正执行写入操作,实际写入逻辑是由Jersey框架在你返回Response对象之后才异步触发的。
  2. 你在构造完Response对象、返回结果之前,就提前执行了workbook.dispose()和workbook.close(),这两个操作会释放SXSSFWorkbook持有的OPCPackage资源,将对应引用置为null。
  3. 当Jersey框架后续触发响应流写入,调用workbook.write方法时,就会命中你贴出的源码中p == null的判断,抛出对应异常。
    你用XSSFWorkbook未复现问题,是因为XSSF的普通写入逻辑是同步执行,你之前的XSSF代码大概率是在write执行完成后才关闭资源,和当前异步流处理的执行时序不同。

修复方案

核心原则是必须等workbook的write操作执行完成后,再释放资源,禁止提前关闭workbook,修改后的代码参考:

public static Response createResponseUsingStreaming() throws IOException {
    SXSSFWorkbook workbook = report.generateStreamingExcelReport(100);
    final String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

    // 重写StreamingOutput的写入逻辑,在写入完成后再释放资源
    StreamingOutput outputStream = output -> {
        try {
            workbook.write(output);
        } finally {
            workbook.dispose();
            workbook.close();
        }
    };

    Response.ResponseBuilder responseBuilder = Response.ok(outputStream);
    // 补充xlsx后缀,避免浏览器识别格式错误
    responseBuilder.header("Content-Disposition", "attachment; filename=test.xlsx");
    responseBuilder.header("Access-Control-Expose-Headers", "Content-Disposition");
    responseBuilder.header("Content-Type", contentType);
    return responseBuilder.build();
}

额外提示:你之前填写的application/vnd.ms-excel是xls格式的MIME类型,SXSSF生成的是xlsx格式,建议替换为代码中的对应MIME类型,避免部分设备下载后无法正常打开文件。

内容的提问来源于stack exchange,提问作者Suhas Munishamaiah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 06:45:03