2. Maven依赖
首先,我们需要在项目中添加以下Maven依赖:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.4</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.5</version>
</dependency>
最新版本的iText和PdfBox库可在Maven中央仓库获取。
⚠️ 重要提示:iText提供AGPL开源许可证和商业许可证两种选择:
- 购买商业许可证可保留源代码所有权
- 使用AGPL版本需免费发布源代码以确保合规
如果需要加密文件,还需添加Bouncy Castle依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.80</version>
</dependency>
3. 使用iText创建PDF
iText是开发者首选的PDF处理库。
3.1 插入文本
下面是创建包含"Hello World"文本的PDF文件示例:
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextHelloWorld.pdf"));
document.open();
Font font = FontFactory.getFont(FontFactory.COURIER, 16, BaseColor.BLACK);
Chunk chunk = new Chunk("Hello World", font);
document.add(chunk);
document.close();
✅ 核心机制:iText通过操作Document中实现Elements接口的对象(5.5.10版本有45种实现)来创建PDF。
最小可添加元素是Chunk(应用字体的字符串),可与其他元素(如Paragraph、Section)组合生成美观文档。
3.2 插入图片
iText提供了便捷的图片添加方式:
Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextImageExample.pdf"));
document.open();
Image img = Image.getInstance(path.toAbsolutePath().toString());
document.add(img);
document.close();
3.3 添加段落
添加段落的实现方式:
Document documentParagraph = new Document();
PdfWriter.getInstance(documentParagraph, new FileOutputStream("iTextParagraph.pdf"));
documentParagraph.open();
Paragraph paragraph = new Paragraph("This paragraph will be horizontally centered.");
paragraph.setAlignment(Element.ALIGN_CENTER);
document.add(paragraph);
document.close();
3.4 插入表格
iText支持添加表格数据:
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextTable.pdf"));
document.open();
PdfPTable table = new PdfPTable(3);
addTableHeader(table);
addRows(table);
addCustomRows(table);
document.add(table);
document.close();
创建3列表格,首行作为表头:
private void addTableHeader(PdfPTable table) {
Stream.of("column header 1", "column header 2", "column header 3")
.forEach(columnTitle -> {
PdfPCell header = new PdfPCell();
header.setBackgroundColor(BaseColor.LIGHT_GRAY);
header.setBorderWidth(2);
header.setPhrase(new Phrase(columnTitle));
table.addCell(header);
});
}
第二行添加纯文本单元格:
private void addRows(PdfPTable table) {
table.addCell("row 1, col 1");
table.addCell("row 1, col 2");
table.addCell("row 1, col 3");
}
第三行添加图片和自定义格式单元格:
private void addCustomRows(PdfPTable table)
throws URISyntaxException, BadElementException, IOException {
Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
Image img = Image.getInstance(path.toAbsolutePath().toString());
img.scalePercent(10);
PdfPCell imageCell = new PdfPCell(img);
table.addCell(imageCell);
PdfPCell horizontalAlignCell = new PdfPCell(new Phrase("row 2, col 2"));
horizontalAlignCell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(horizontalAlignCell);
PdfPCell verticalAlignCell = new PdfPCell(new Phrase("row 2, col 3"));
verticalAlignCell.setVerticalAlignment(Element.ALIGN_BOTTOM);
table.addCell(verticalAlignCell);
}
3.5 设置表格单元格宽度
列宽决定单元格宽度,需通过PdfTable的setWidths()方法设置:
绝对宽度设置
private static void setAbsoluteColumnWidths(PdfPTable table) {
table.setTotalWidth(500);
table.setLockedWidth(true);
float[] columnWidths = { 100f, 200f, 200f };
table.setWidths(columnWidths);
}
⚠️ 注意:必须同时设置和锁定宽度,否则iText会使用默认宽度百分比计算。
通过表格宽度设置
private static void setAbsoluteColumnWidthsInTableWidth(PdfPTable table) {
table.setTotalWidth(new float[] { 72f, 144f, 216f }); // 1英寸, 2英寸, 3英寸
table.setLockedWidth(true);
}
相对宽度设置
private static void setRelativeColumnWidths(PdfPTable table) {
table.setWidths(new float[] { 1, 2, 1 }); // 1:2:1比例
table.setWidthPercentage(80); // 页面宽度的80%
}
初始化时设置
PdfPTable table = new PdfPTable(new float[] { 1, 2, 1 });
3.6 文件加密
使用iText加密PDF文件:
PdfReader pdfReader = new PdfReader("HelloWorld.pdf");
PdfStamper pdfStamper
= new PdfStamper(pdfReader, new FileOutputStream("encryptedPdf.pdf"));
pdfStamper.setEncryption(
"userpass".getBytes(),
"ownerpass".getBytes(),
0,
PdfWriter.ENCRYPTION_AES_256
);
pdfStamper.close();
双密码机制:
- 用户密码(userpass):只读权限,禁止打印
- 所有者密码(ownerpass):完全访问权限
允许用户打印的权限设置:
PdfWriter.ALLOW_PRINTING
组合权限示例:
PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY
⚠️ 踩坑提醒:加密过程会创建临时PDF文件,使用后必须删除!
4. 使用PdfBox创建PDF
Apache PDFBox是开源PDF处理库。
4.1 插入文本
与iText不同,PdfBox基于流操作API:
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.setFont(PDType1Font.COURIER, 12);
contentStream.beginText();
contentStream.showText("Hello World");
contentStream.endText();
contentStream.close();
document.save("pdfBoxHelloWorld.pdf");
document.close();
4.2 插入图片
图片插入方式:
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDImageXObject image
= PDImageXObject.createFromFile(path.toAbsolutePath().toString(), document);
contentStream.drawImage(image, 0, 0);
contentStream.close();
document.save("pdfBoxImage.pdf");
document.close();
4.3 插入表格或设置列宽
❌ PdfBox不直接支持表格,需手动绘制或使用Boxable库(基于PDFBox封装)。
4.4 文件加密
PdfBox的加密实现:
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
AccessPermission accessPermission = new AccessPermission();
accessPermission.setCanPrint(false);
accessPermission.setCanModify(false);
StandardProtectionPolicy standardProtectionPolicy
= new StandardProtectionPolicy("ownerpass", "userpass", accessPermission);
document.protect(standardProtectionPolicy);
document.save("pdfBoxEncryption.pdf");
document.close();
权限控制:通过AccessPermission类设置用户权限(修改/提取内容/打印等),使用StandardProtectionPolicy添加密码保护。
5. 总结
本文详细介绍了使用iText和PdfBox两种主流Java库创建PDF文件的完整方法,包括:
- 文本/图片/表格/段落的插入
- 表格宽度控制
- 文件加密与权限管理
两种库的核心差异:
- iText:基于元素对象操作,功能更全面
- PdfBox:基于流操作,更轻量级
根据项目需求选择合适库,注意iText的许可证限制。