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

Spring Boot基于JDBC结果集导出Word时如何避免报错生成空文件

问题原因

你当前的代码执行顺序是先设置响应的下载头、内容类型,再执行业务逻辑生成Word。一旦业务逻辑抛出异常,浏览器已经收到了下载相关的响应头,就会把后续返回的空内容/错误页内容当成Word文件保存,自然就会出现空文件的情况。

解决方案

核心思路是先完成所有业务逻辑校验和文件生成,确认无异常后再写入下载响应头和文件内容,具体修改如下:

步骤1:调整执行顺序,先完成文件生成逻辑

不要直接把response的输出流传给generateWord方法,先将Word生成到字节数组或者服务器临时目录,确认生成成功后再操作response。

步骤2:增加异常捕获逻辑,报错时返回正常的错误提示

如果生成过程中抛出异常,重置response的响应头,设置为JSON格式的错误响应,避免浏览器识别为下载文件。

修改后的代码示例
@GetMapping(produces = "application/vnd.openxmlformats-officedocument.wordprocessingml.document", value = "export/word")
@ApiOperation(value = "Export table as word")
public void generateword(HttpServletResponse response, @RequestParam(required = true) String tableName,
        @RequestParam(required = false) String search, @RequestParam(required = false) String searchColumn,
        @RequestHeader(required = false, value = "x-remote-user") String username)
        throws IOException {
    // 1. 先定义字节数组接收生成的Word内容
    byte[] wordContent;
    try {
        // 2. 执行业务逻辑生成Word,需要将原来的generateWord方法改造为返回byte[],不直接写response
        if (StringUtils.hasLength(search)) {
            wordContent = describeDatabaseRepository.generateWord(tableName, username, search, searchColumn);
        } else {
            wordContent = describeDatabaseRepository.generateWord(tableName, username);
        }
        // 3. 确认生成无异常后,再设置下载响应头
        DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
        String currentDateTime = dateFormatter.format(new Date());
        String headerKey = "Content-Disposition";
        String headerValue = "attachment; filename=" + tableName + "_" + currentDateTime + ".docx";
        response.setHeader(headerKey, headerValue);
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        // 4. 把生成好的内容写入响应
        response.getOutputStream().write(wordContent);
        response.getOutputStream().flush();
    } catch (DataAccessException | RuntimeException e) {
        // 5. 发生异常时重置响应,返回错误信息
        response.reset();
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        // 可替换为项目统一的错误返回格式
        response.getWriter().write("{\"code\":500,\"msg\":\"导出失败:" + e.getMessage() + "\"}");
    }
}

不便改造generateWord方法的替代方案

如果generateWord方法不方便修改返回值,可以用ByteArrayOutputStream先包装输出流,无需改动原方法内部逻辑:

// 生成阶段用字节数组流暂存内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (StringUtils.hasLength(search)) {
    describeDatabaseRepository.generateWord(tableName, username, search, searchColumn, baos);
} else {
    describeDatabaseRepository.generateWord(tableName, username, baos);
}
// 确认无异常后再转写到response的输出流
byte[] wordContent = baos.toByteArray();
// 后续设置响应头、写回响应的逻辑和上面一致

内容的提问来源于stack exchange,提问作者Ladu anand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:15:04