Spring控制器通过PDFBox导出PDF至用户时返回空文件的问题
解决Spring控制器导出PDFBox生成PDF为空的问题
嘿,我来帮你搞定这个导出PDF返回空文件的问题!先看看你代码里几个关键的问题,这些就是导致空文件的元凶:
1. 请求方法与响应类型完全不匹配
你用了PUT请求方法,而且produces设置成了APPLICATION_JSON_VALUE——但我们要导出的是PDF啊!PUT一般用来更新资源,下载用GET或者POST更合适;同时produces得改成PDF的媒体类型MediaType.APPLICATION_PDF_VALUE,不然服务器会告诉浏览器返回的是JSON,浏览器自然解析不了PDF。
2. 没给HttpServletResponse设置正确的响应头
浏览器需要知道返回的内容是什么类型、要不要触发下载,你得设置Content-Type和Content-Disposition这些头,不然浏览器可能把PDF当成空白内容处理。
3. 核心问题:没把PDDocument写入响应输出流
你创建了PDDocument,但看起来没把它写到response的输出流里,这肯定会返回空文件啊!另外还要记得关闭资源,别搞内存泄漏。
修正后的完整代码示例
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @RestController @RequestMapping("/reports") public class PDFReportController { @PostMapping(value = "/pdfReport", produces = MediaType.APPLICATION_PDF_VALUE) public void downloadPDFReport(HttpServletResponse response, @RequestBody PDFReport pdfReport) throws IOException { // 1. 这里替换成你从storageManager获取内容并构建PDF的逻辑 PDDocument document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); // 示例:把storageManager返回的StringBuilder内容写入PDF String content = storageManager.getPDF(pdfReport).toString(); try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) { contentStream.beginText(); contentStream.setFont(PDType1Font.HELVETICA, 12); contentStream.newLineAtOffset(50, 750); // 设置起始位置 // 换行处理内容,避免超出页面 String[] lines = content.split("\n"); for (String line : lines) { contentStream.showText(line); contentStream.newLineAtOffset(0, -15); // 每行下移15个单位 } contentStream.endText(); } catch (IOException e) { e.printStackTrace(); // 这里可以加异常处理,比如返回错误给前端 } // 2. 设置响应头,告诉浏览器这是可下载的PDF response.setContentType(MediaType.APPLICATION_PDF_VALUE); response.setHeader("Content-Disposition", "attachment; filename=\"pdf_report.pdf\""); // 可选:如果能获取PDF的大小,可以设置Content-Length,让浏览器显示下载进度 // response.setContentLength((int) document.getDocument().getLength()); // 3. 把PDF写入响应输出流,这是核心! document.save(response.getOutputStream()); // 4. 关闭资源,避免内存泄漏 document.close(); response.getOutputStream().flush(); response.getOutputStream().close(); } }
几个必须注意的点
- 响应头一定要对:
Content-Disposition里的attachment会让浏览器弹出下载窗口,filename是用户下载后看到的文件名;Content-Type必须是application/pdf,不然浏览器可能识别错误。 - 资源要管好:用try-with-resources处理
PDPageContentStream,它会自动关闭;写完PDF后一定要关闭PDDocument,不然内存会爆。 - 请求方法选对:如果你的PDF不需要传复杂的请求体,用
GET更直观;如果必须传JSON参数,就用POST,别用PUT了,不符合REST规范。 - 输出流要刷干净:写完后调用
flush()确保所有内容都发送到客户端,再关闭流。
要是你storageManager.getPDF返回的内容有特殊排版需求,比如加粗、换行,就调整PDPageContentStream的逻辑就行,核心就是把内容正确写入PDF,再输出到响应流里。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

