Apache POI 3.16生成Excel文件下载后无法正常打开问题求助
Apache POI 3.16生成XLSX文件下载异常解决方案
问题分析与修复
1. XLSX文件无法打开的修复
你提供的XSSF代码中,ContentType设置错误,仍然使用了xls格式的ms-vnd/excel,这会导致浏览器或Office识别文件格式异常。正确的XLSX格式ContentType必须设置为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,同时需确保响应头的文件名后缀与格式匹配。修复后的代码如下:
Workbook wb = new XSSFWorkbook(); Sheet sheet = wb.createSheet("sheet1"); Row row = null; Cell cell = null; int rowNum = 0; row = sheet.createRow(rowNum++); cell = row.createCell(0); cell.setCellValue("no"); for (int i=0; i<3; i++) { row = sheet.createRow(rowNum++); cell = row.createCell(0); cell.setCellValue(i); } // 修正ContentType为XLSX对应的值 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment;filename=example.xlsx"); OutputStream outputStream = response.getOutputStream(); wb.write(outputStream); // 刷新并关闭流 outputStream.flush(); outputStream.close(); wb.close();
2. 写入ByteArrayOutputStream后样式损坏的修复
你的代码存在两个关键错误:
- XSSFWorkbook写入流后内部资源会被关闭,第二次调用
wb.write(out)会导致文件内容不完整或样式损坏; - autoSizeColumns应该在写入流之前执行,写入后Workbook的状态已固化,再调整列宽不会生效。
修复后的代码逻辑应该是:先调整列宽,再将ByteArrayOutputStream的内容写入响应流,而不是重复写入Workbook:
OutputStream out = null; ByteArrayOutputStream bout = null; try { bout = new ByteArrayOutputStream(); // 先执行列宽调整 autoSizeColumns(wb); // 只写入一次Workbook到ByteArrayOutputStream wb.write(bout); setHeader(request, response, fileName); response.setContentLength(bout.size()); // 设置正确的ContentType(XLSX格式需对应正确值) response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); out = response.getOutputStream(); // 将ByteArrayOutputStream的内容写入响应流 bout.writeTo(out); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bout != null) bout.close(); if (out != null) out.close(); if (wb != null) wb.close(); } catch (IOException e) { e.printStackTrace(); } }
结论
这并非Apache POI 3.16的Bug,而是代码中ContentType设置错误、Workbook重复写入流、列宽调整时机错误导致的问题。按照上述方式修复后,XLSX文件即可正常下载并打开,样式也能保持完整。
内容的提问来源于stack exchange,提问作者recadro
相关产品推荐
相关产品推荐

