使用Java、Thymeleaf和Spring Boot导出PDF失败问题求助
问题分析与解决方案
PDF加载失败的核心原因
你的代码里导致PDF损坏的关键问题有3个:
- 流操作冲突:
pdfAsc中同时创建本地文件流和response.getOutputStream,但PdfWriter仅绑定了response流,后续关闭本地流会打乱PDF输出逻辑,导致文件内容不完整; - 内容生成错误:直接把
getNumAsc()列表转成字符串添加到ListItem,生成的是Troops对象的内存引用(比如[Troops@123, Troops@456]),这种非标准文本会引发PDF解析失败; - 未实现的依赖:
exportToPDFAsc中调用的PDF基类export方法无具体实现,执行时会抛出异常中断PDF生成。
改成表格能解决问题吗?
改成表格不仅能让导出内容更规整易读,更关键的是重构代码时可以修正上述流操作和内容生成的错误,从根源解决PDF损坏问题。
iText创建表格的实现教程
下面是修复后的完整PDF导出代码,替换你原来的pdfAsc、exportToPDFAsc等相关方法:
1. 确保依赖正确
如果用Maven,在pom.xml中添加iText依赖:
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.3</version> </dependency>
2. 修正后的PDF导出方法
// 导出升序表格PDF @GetMapping("/pdfasc") public void exportAscToPDF(HttpServletResponse response) throws DocumentException, IOException { // 设置响应头,告知浏览器返回PDF文件 response.setContentType("application/pdf"); DateFormat dateFormatter = new SimpleDateFormat("yyyy-dd-MM_HH-mm"); String currentDateTime = dateFormatter.format(new Date()); String headerValue = "attachment; filename=Troops_Asc_" + currentDateTime + ".pdf"; response.setHeader("Content-Disposition", headerValue); // 初始化iText文档 com.itextpdf.text.Document document = new com.itextpdf.text.Document(); PdfWriter.getInstance(document, response.getOutputStream()); document.open(); // 创建2列表格(ID、姓名),宽度占满页面 com.itextpdf.text.pdf.PdfPTable table = new com.itextpdf.text.pdf.PdfPTable(2); table.setWidthPercentage(100); // 添加表头 table.addCell(new com.itextpdf.text.Phrase("ID")); table.addCell(new com.itextpdf.text.Phrase("姓名")); // 循环添加表格数据 List<Troops> ascList = getNumAsc(); for (Troops troop : ascList) { table.addCell(new com.itextpdf.text.Phrase(String.valueOf(troop.getId()))); table.addCell(new com.itextpdf.text.Phrase(troop.getFullName())); } // 将表格加入文档并关闭 document.add(table); document.close(); } // 导出降序表格PDF @GetMapping("/pdfdesc") public void exportDescToPDF(HttpServletResponse response) throws DocumentException, IOException { response.setContentType("application/pdf"); DateFormat dateFormatter = new SimpleDateFormat("yyyy-dd-MM_HH-mm"); String currentDateTime = dateFormatter.format(new Date()); String headerValue = "attachment; filename=Troops_Desc_" + currentDateTime + ".pdf"; response.setHeader("Content-Disposition", headerValue); com.itextpdf.text.Document document = new com.itextpdf.text.Document(); PdfWriter.getInstance(document, response.getOutputStream()); document.open(); com.itextpdf.text.pdf.PdfPTable table = new com.itextpdf.text.pdf.PdfPTable(2); table.setWidthPercentage(100); table.addCell(new com.itextpdf.text.Phrase("ID")); table.addCell(new com.itextpdf.text.Phrase("姓名")); List<Troops> descList = getNumDes(); for (Troops troop : descList) { table.addCell(new com.itextpdf.text.Phrase(String.valueOf(troop.getId()))); table.addCell(new com.itextpdf.text.Phrase(troop.getFullName())); } document.add(table); document.close(); }
3. 关键修复说明
- 统一流操作:仅使用
response.getOutputStream作为PDF输出流,避免本地流干扰,确保内容完整写入响应; - 规范内容生成:用
PdfPTable创建表格,循环遍历Troops列表逐个添加单元格数据,避免对象toString的无效内容; - 移除无效代码:删除未实现的
PDF基类、DataPDFExporter等冗余代码,直接在Controller方法中完成PDF生成逻辑。
4. 确保Troops类有getter方法
你的Troops类需要提供获取字段的方法,示例如下:
public class Troops { private String fullName; private int id; public Troops(String fullName, int id) { this.fullName = fullName; this.id = id; } public String getFullName() { return fullName; } public int getId() { return id; } }
内容的提问来源于stack exchange,提问作者Neet
相关产品推荐
相关产品推荐

