Java PDF操作指南:iText与PDFBox实战对比 1. Java操作PDF的常见场景与工具选型PDF作为跨平台文档格式在企业级应用中有着广泛的使用场景。Java开发者经常需要处理PDF文档的生成、编辑和内容提取等需求。从发票生成、报表导出到合同签署PDF操作几乎成为Java后台开发的标配技能。目前主流的Java PDF操作库主要有以下几个iText功能最全面的开源库支持PDF生成、编辑、加密等全套操作AGPL/commercial双协议Apache PDFBoxApache旗下的开源项目专注PDF内容提取和基础操作OpenPDFiText分支版本LGPL协议更友好Flying Saucer适合HTML转PDF场景JasperReports报表工具内置PDF导出功能对于数据写入场景iText和PDFBox是最常用的选择。iText在生成复杂PDF时更具优势而PDFBox在已有PDF修改方面更轻量。我们以iText 7为例进行演示这是目前最新的商业友好版本。2. 基础环境准备与依赖配置2.1 Maven依赖配置使用iText 7需要添加以下依赖到pom.xmldependency groupIdcom.itextpdf/groupId artifactIditext7-core/artifactId version7.2.5/version typepom/type /dependency如果需要处理中文等亚洲字符还需添加额外的字体模块dependency groupIdcom.itextpdf/groupId artifactIdfont-asian/artifactId version7.2.5/version /dependency2.2 字体资源准备处理中文内容时必须明确指定支持中文的字体。推荐将字体文件(.ttf)放在resources/fonts目录下。常用开源字体如思源黑体(Source Han Sans)阿里巴巴普惠体文泉驿系列字体注意直接使用系统字体可能导致部署环境缺少对应字体而出错建议将字体文件随项目一起打包。3. 基础文本写入实现3.1 创建PDF文档基础框架以下是创建PDF并写入文本的最小实现import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Paragraph; public class BasicPdfWriter { public static void main(String[] args) throws Exception { // 1. 创建PdfWriter指向输出文件 PdfWriter writer new PdfWriter(output.pdf); // 2. 创建PdfDocument对象 PdfDocument pdf new PdfDocument(writer); // 3. 创建Document对象用于添加内容 Document document new Document(pdf); // 4. 添加段落内容 document.add(new Paragraph(Hello PDF World!)); // 5. 关闭文档 document.close(); } }3.2 中文内容处理处理中文需要特别注意字体设置// 加载字体(假设resources/fonts下有SourceHanSans.ttf) PdfFont font PdfFontFactory.createFont( fonts/SourceHanSans.ttf, PdfEncodings.IDENTITY_H, true); // 创建支持中文的段落 Paragraph p new Paragraph(这是一个中文段落) .setFont(font) .setFontSize(14); document.add(p);3.3 文本样式控制iText提供了丰富的文本样式控制Paragraph styledText new Paragraph() .add(new Text(加粗文本).setBold()) .add( ) .add(new Text(斜体文本).setItalic()) .add( ) .add(new Text(红色文本).setFontColor(Color.RED)) .add( ) .add(new Text(带背景色).setBackgroundColor(Color.YELLOW)) .setFont(font) .setFontSize(12);4. 高级数据写入技巧4.1 表格数据写入表格是数据展示的常见形式iText表格操作示例// 创建3列表格 Table table new Table(new float[]{1, 2, 1}); // 添加表头 table.addHeaderCell(new Cell().add(new Paragraph(ID).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(商品名称).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(价格).setBold())); // 添加数据行 for(Product product : productList) { table.addCell(new Cell().add(new Paragraph(product.getId()))); table.addCell(new Cell().add(new Paragraph(product.getName()))); table.addCell(new Cell().add(new Paragraph(product.getPrice()))); } // 设置表格宽度占页面80% table.setWidth(UnitValue.createPercentValue(80)); // 添加到文档 document.add(table);4.2 列表数据展示有序列表和无序列表的实现// 无序列表 List list new List() .setSymbolIndent(12) .setListSymbol(•) .setFont(font); list.add(列表项1); list.add(列表项2); document.add(list); // 有序列表 List numberedList new List(ListNumberingType.DECIMAL); numberedList.add(第一项); numberedList.add(第二项); document.add(numberedList);4.3 图片插入处理插入图片到PDF的完整流程// 加载图片(假设在resources/images下) ImageData imageData ImageDataFactory.create(images/logo.png); Image image new Image(imageData); // 设置图片属性 image.setAutoScale(true); // 自动缩放 image.setHorizontalAlignment(HorizontalAlignment.CENTER); // 居中 // 添加到文档 document.add(image);提示处理大图片时建议先压缩避免PDF体积过大。iText支持JPEG、PNG、BMP等多种格式。5. 页面布局与样式控制5.1 页面大小与边距创建文档时指定页面属性// 自定义页面大小(A4竖版) PageSize pageSize PageSize.A4; Document document new Document(pdfDoc, pageSize); // 设置页边距(上下左右) document.setMargins(50, 30, 50, 30);5.2 分页与页眉页脚添加页眉页脚的实现方式// 总页数 int totalPages pdfDoc.getNumberOfPages(); // 为每页添加页脚 for (int i 1; i totalPages; i) { PdfPage page pdfDoc.getPage(i); Rectangle pageSize page.getPageSize(); // 在页面底部创建Canvas Canvas canvas new Canvas(page, pageSize); float y 20; // 距离底部20单位 // 添加页脚文本 canvas.showTextAligned( new Paragraph(String.format(第 %d 页/共 %d 页, i, totalPages)) .setFontSize(10), pageSize.getWidth() / 2, y, TextAlignment.CENTER); canvas.close(); }5.3 多栏布局创建类似报纸的多栏布局// 创建两栏布局 ColumnDocumentRenderer renderer new ColumnDocumentRenderer( document, new float[]{250, 250} // 两栏宽度 ); document.setRenderer(renderer); // 添加内容时会自动分栏 document.add(new Paragraph(第一栏内容...)); document.add(new Paragraph(第二栏内容...));6. 常见问题排查6.1 中文乱码问题中文显示异常通常由以下原因导致未正确设置支持中文的字体字体编码未使用PdfEncodings.IDENTITY_H字体文件路径错误或未打包到最终jar中解决方案// 确保使用以下方式加载字体 PdfFont font PdfFontFactory.createFont( fonts/YourChineseFont.ttf, PdfEncodings.IDENTITY_H, true);6.2 内存泄漏问题iText操作PDF时需要及时关闭资源try (PdfWriter writer new PdfWriter(outputPath); PdfDocument pdf new PdfDocument(writer); Document doc new Document(pdf)) { // 操作文档 } catch (Exception e) { e.printStackTrace(); }6.3 性能优化建议处理大批量数据时使用PdfWriter.setSmartMode(true)启用智能模式对于大型表格考虑分页显示图片使用适当压缩质量复用字体等资源对象7. 实际应用案例7.1 生成销售报表典型销售报表生成流程public void generateSalesReport(ListSaleRecord records, String outputPath) throws IOException { // 初始化文档 PdfWriter writer new PdfWriter(outputPath); PdfDocument pdf new PdfDocument(writer); Document document new Document(pdf, PageSize.A4.rotate()); // 横向A4 // 添加标题 document.add(new Paragraph(月度销售报表) .setFont(titleFont) .setFontSize(18) .setTextAlignment(TextAlignment.CENTER)); // 添加生成日期 document.add(new Paragraph(生成日期: LocalDate.now()) .setFont(bodyFont) .setFontSize(10)); // 创建表格 Table table new Table(new float[]{1, 3, 2, 2, 2}); table.setWidth(UnitValue.createPercentValue(100)); // 添加表头 addTableHeader(table); // 添加数据行 for (SaleRecord record : records) { addTableRow(table, record); } // 添加表格到文档 document.add(table); // 添加统计信息 addSummary(document); document.close(); }7.2 合同文档生成合同生成的关键要点使用固定格式模板关键字段高亮显示添加数字签名区域设置文档权限// 合同关键信息高亮示例 Paragraph contractItem new Paragraph() .add(甲方: ) .add(new Text(partyA).setUnderline()) .add( 乙方: ) .add(new Text(partyB).setUnderline()); document.add(contractItem); // 添加签名区域 Table signatureTable new Table(2); signatureTable.addCell(new Cell().add(new Paragraph(甲方签字:))); signatureTable.addCell(new Cell().add(new Paragraph(乙方签字:))); signatureTable.addCell(new Cell().setHeight(50)); // 留空签字处 signatureTable.addCell(new Cell().setHeight(50)); document.add(signatureTable);8. 扩展功能实现8.1 PDF加密与权限控制设置文档打开密码和权限WriterProperties props new WriterProperties() .setStandardEncryption( userPass.getBytes(), // 用户密码 ownerPass.getBytes(), // 所有者密码 EncryptionConstants.ALLOW_PRINTING, // 允许打印 EncryptionConstants.ENCRYPTION_AES_256 // 加密强度 ); PdfWriter writer new PdfWriter(outputPath, props);8.2 添加条形码/二维码使用Barcode4J集成生成条形码// 生成二维码 BarcodeQRCode qrCode new BarcodeQRCode(https://example.com); Image qrCodeImage new Image(qrCode.createFormXObject(pdf)); document.add(qrCodeImage);8.3 动态水印添加为PDF添加文字水印for (int i 1; i pdf.getNumberOfPages(); i) { PdfPage page pdf.getPage(i); PdfCanvas canvas new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf); // 设置水印样式 canvas.saveState() .setFillColor(Color.LIGHT_GRAY) .setFontAndSize(font, 40) .beginText(); // 在页面中心添加旋转文字 canvas.showTextAligned(CONFIDENTIAL, page.getPageSize().getWidth() / 2, page.getPageSize().getHeight() / 2, i, TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45); canvas.restoreState(); }9. 最佳实践与性能优化9.1 对象复用提升性能避免重复创建相同资源// 在文档级别共享字体等资源 PdfFont sharedFont PdfFontFactory.createFont(...); Style sharedStyle new Style() .setFont(sharedFont) .setFontSize(12); // 在多个段落中复用 Paragraph p1 new Paragraph(段落1).addStyle(sharedStyle); Paragraph p2 new Paragraph(段落2).addStyle(sharedStyle);9.2 大文档分块处理处理大型PDF时的内存管理// 启用智能模式减少内存占用 writer.setSmartMode(true); // 定期释放资源 if(docCounter % 100 0) { document.flush(); System.gc(); }9.3 错误处理与日志记录完善的错误处理机制try { // PDF操作代码 } catch (PdfException e) { logger.error(PDF处理错误: {}, e.getMessage()); throw new BusinessException(PDF生成失败, e); } catch (IOException e) { logger.error(IO异常: {}, e.getMessage()); throw new BusinessException(文件操作失败, e); } finally { // 确保资源释放 IOUtils.closeQuietly(document); IOUtils.closeQuietly(pdf); IOUtils.closeQuietly(writer); }10. 替代方案比较10.1 iText vs PDFBox特性iTextPDFBox生成PDF功能强大API丰富基础功能完善修改PDF支持但较复杂简单直接中文支持需要额外配置字体同左性能中等较高许可协议AGPL/CommercialApache 2.0学习曲线较陡峭较平缓10.2 HTML转PDF方案对于已有HTML内容的情况Flying Saucer Thymeleaf/Freemarker// 使用模板引擎渲染HTML String htmlContent templateEngine.process(template, context); // 转换为PDF OutputStream os new FileOutputStream(output.pdf); ITextRenderer renderer new ITextRenderer(); renderer.setDocumentFromString(htmlContent); renderer.layout(); renderer.createPDF(os); os.close();OpenHTMLToPDF更现代的替代方案10.3 云端PDF生成服务对于无服务器环境需求AWS TextractGoogle Document AI阿里云智能媒体服务这些服务提供REST API接口适合分布式系统集成但需要考虑网络延迟和成本因素。