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
相关产品推荐
相关产品推荐

