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>

最新版本的iTextPdfBox库可在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的许可证限制。


原始标题:Creating PDF Files in Java | Baeldung

« 上一篇: JGit 使用指南
» 下一篇: Vavr 模式匹配指南