Apache PDFBox 实战案例详解
Apache PDFBox 是 Java 中处理 PDF 文件最常用的开源库之一,下面通过几个完整的实战案例来展示它的核心功能。

创建带格式的 PDF 文档
场景
生成一份包含标题、段落、表格和图片的员工入职通知书。
完整代码
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.font.*;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import java.io.IOException;
public class CreatePDF {
public static void main(String[] args) throws IOException {
// 1. 创建空白文档
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4); // A4 纸张
document.addPage(page);
// 2. 创建内容流
PDPageContentStream content = new PDPageContentStream(document, page);
// 3. 设置字体(中文需要加载系统字体)
PDType0Font font = PDType0Font.load(document,
new java.io.File("C:/Windows/Fonts/simhei.ttf")); // 黑体
// 4. 写入标题
content.beginText();
content.setFont(font, 20);
content.setLeading(30); // 行距
content.newLineAtOffset(50, 750); // 起始位置
content.showText("员工入职通知书");
content.newLine();
content.showText("尊敬的张三先生:");
content.endText();
// 5. 添加段落文字
String paragraph = "恭喜您通过我司面试!请您于2024年3月1日携带相关证件";
content.beginText();
content.setFont(font, 12);
content.newLineAtOffset(50, 700);
content.showText(paragraph);
content.newLine();
content.showText("到公司人力资源部报到。");
content.endText();
// 6. 画一条分隔线
content.setLineWidth(1f);
content.moveTo(50, 680);
content.lineTo(545, 680);
content.stroke();
// 7. 插入图片(Logo)
PDImageXObject logo = PDImageXObject.createFromFile("logo.png", document);
content.drawImage(logo, 470, 740, 80, 50);
// 8. 关闭内容流
content.close();
// 9. 保存文件
document.save("offer_letter.pdf");
document.close();
System.out.println("PDF 创建成功!");
}
}
读取并提取 PDF 文本
场景
从大量 PDF 文件中提取文本内容用于数据分析。
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.PDFTextStripperByArea;
import java.io.File;
import java.io.IOException;
public class ReadPDF {
public static void main(String[] args) throws IOException {
File pdfFile = new File("employee_contract.pdf");
// 打开 PDF 文档
try (PDDocument document = PDDocument.load(pdfFile)) {
// 检查加密状态
if (document.isEncrypted()) {
System.out.println("PDF 文件已加密,需要密码");
return;
}
// 全文提取
PDFTextStripper stripper = new PDFTextStripper();
stripper.setStartPage(1); // 从第1页开始
stripper.setEndPage(2); // 到第2页结束
String text = stripper.getText(document);
System.out.println("提取的文本内容:");
System.out.println(text);
// 按区域提取(适用于表格等特定区域)
PDFTextStripperByArea areaStripper = new PDFTextStripperByArea();
areaStripper.setSortByPosition(true);
// 获取页面信息
System.out.println("PDF 页数: " + document.getNumberOfPages());
System.out.println("页面尺寸: " + document.getPage(0).getMediaBox());
}
}
}
PDF 表单填写与生成
场景
批量填写电子合同或申请表。
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.form.*;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class FillForm {
public static void main(String[] args) throws IOException {
// 1. 加载模板
try (PDDocument document = PDDocument.load(new File("employee_form.pdf"))) {
// 2. 获取表单
PDAcroForm form = document.getDocumentCatalog().getAcroForm();
if (form == null) {
System.out.println("该 PDF 不包含表单!");
return;
}
// 3. 获取所有表单字段
System.out.println("可用的表单字段:");
form.getFields().forEach(field ->
System.out.println(" - " + field.getFullyQualifiedName()));
// 4. 填写表单数据
Map<String, String> data = new HashMap<>();
data.put("name", "张三");
data.put("idNumber", "110101199001011234");
data.put("position", "Java 高级工程师");
data.put("salary", "25000");
data.put("startDate", "2024-03-01");
// 5. 逐个字段赋值
for (Map.Entry<String, String> entry : data.entrySet()) {
PDField field = form.getField(entry.getKey());
if (field != null) {
field.setValue(entry.getValue());
// 针对复选框特殊处理
if (field instanceof PDCheckBox) {
((PDCheckBox) field).check();
}
}
}
// 6. 保存填写后的新文件
document.save("filled_form.pdf");
System.out.println("表单填写完成,已保存为 filled_form.pdf");
}
}
}
PDF 加密与权限控制
场景
为 PDF 文件设置密码并限制打印、复制等操作。
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import java.io.File;
import java.io.IOException;
public class ProtectPDF {
public static void main(String[] args) throws IOException {
try (PDDocument document = PDDocument.load(new File("sensitive.docx"))) {
// 1. 设置访问权限
AccessPermission ap = new AccessPermission();
ap.setCanPrint(false); // 禁止打印
ap.setCanModify(false); // 禁止修改
ap.setCanCopy(false); // 禁止复制
ap.setCanExtractContent(true); // 允许提取内容
// 2. 创建加密策略
StandardProtectionPolicy policy = new StandardProtectionPolicy(
"owner123", // 所有者密码(最高权限)
"user123", // 用户密码(受限权限)
ap
);
// 3. 设置加密强度(128-bit AES)
policy.setEncryptionKeyLength(128);
// 4. 应用加密
document.protect(policy);
// 5. 保存加密后的文件
document.save("protected.pdf");
System.out.println("PDF 加密完成,文件已保护!");
} catch (Exception e) {
System.err.println("加密失败: " + e.getMessage());
}
}
}
批量文档处理(合并/拆分)
场景
批量合并多个 PDF 合同为一个文件。
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.multipdf.Splitter;
import org.apache.pdfbox.pdmodel.PDDocument;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class BatchProcess {
// 合并多个 PDF
public static void mergePDFs(List<String> filePaths, String outputPath) throws IOException {
PDFMergerUtility merger = new PDFMergerUtility();
// 添加要合并的文件
for (String path : filePaths) {
merger.addSource(new File(path));
}
// 设置输出文件
merger.setDestinationFileName(outputPath);
// 执行合并
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
System.out.println("已合并 " + filePaths.size() + " 个 PDF 文件");
}
// 拆分 PDF 为单独页面
public static void splitPDF(String filePath, String outputDir) throws IOException {
try (PDDocument document = PDDocument.load(new File(filePath))) {
Splitter splitter = new Splitter();
List<PDDocument> pages = splitter.split(document);
// 保存每一页为独立文件
for (int i = 0; i < pages.size(); i++) {
String outputPath = outputDir + "/page_" + (i+1) + ".pdf";
pages.get(i).save(outputPath);
pages.get(i).close();
System.out.println("已生成: " + outputPath);
}
}
}
public static void main(String[] args) throws IOException {
// 合并示例
mergePDFs(
Arrays.asList("contract1.pdf", "contract2.pdf", "contract3.pdf"),
"merged_contracts.pdf"
);
// 拆分示例
splitPDF("resource_plan.pdf", "output_pages");
}
}
复杂布局 - 生成财务报表
场景
生成带图形元素的数据报表。
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import java.awt.Color;
import java.io.IOException;
public class FinancialReport {
public static void main(String[] args) throws IOException {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
PDPageContentStream cos = new PDPageContentStream(document, page);
// 绘制表格线
cos.setStrokingColor(Color.BLACK);
cos.setLineWidth(1f);
// 表头
cos.setNonStrokingColor(Color.LIGHT_GRAY);
cos.addRect(50, 700, 150, 30);
cos.fill();
cos.setNonStrokingColor(Color.WHITE);
// 表头文字
cos.beginText();
cos.setFont(PDType1Font.HELVETICA_BOLD, 12);
cos.newLineAtOffset(60, 712);
cos.showText("项目名称");
cos.endText();
// 更多表头...
// 柱状图示例
int[] salesData = {120, 180, 150, 200, 240, 300, 280};
String[] months = {"1月", "2月", "3月", "4月", "5月", "6月", "7月"};
int baseY = 300;
int barWidth = 40;
int spacing = 20;
for (int i = 0; i < salesData.length; i++) {
int x = 100 + i * (barWidth + spacing);
int barHeight = salesData[i];
// 柱体
cos.setNonStrokingColor(new Color(52, 152, 219));
cos.addRect(x, baseY, barWidth, barHeight);
cos.fill();
// 月份标签
cos.beginText();
cos.setFont(PDType1Font.HELVETICA, 10);
cos.newLineAtOffset(x + 5, baseY - 20);
cos.showText(months[i]);
cos.endText();
// 数值标签
cos.beginText();
cos.newLineAtOffset(x + 5, baseY + barHeight + 5);
cos.showText(String.valueOf(salesData[i]));
cos.endText();
}
// 坐标轴
cos.setLineWidth(2f);
cos.moveTo(50, baseY - 30); // X 轴
cos.lineTo(550, baseY - 30);
cos.stroke();
cos.moveTo(50, 100); // Y 轴
cos.lineTo(50, 600);
cos.stroke();
cos.close();
document.save("monthly_sales_report.pdf");
}
}
}
中文支持
// 正确加载中文字体(必须!)
PDType0Font.load(document, new File("C:/Windows/Fonts/simhei.ttf"));
内存优化
// 大文件处理时使用流式加载 PDDocument.load(file, MemoryUsageSetting.setupTempFileOnly());
异常处理
// 统一处理 PDF 相关异常
try (PDDocument doc = new PDDocument()) {
// 操作...
} catch (IOException e) {
System.err.println("PDF 处理错误: " + e.getMessage());
// 记录日志并恢复
}
版本兼容
- PDFBox 2.x 使用
PDPageContentStream - 升级到 3.x 后注意 API 变更
常见问题解决
| 问题现象 | 解决方案 |
|---|---|
| 中文乱码 | 加载系统 TTF 字体文件 |
| 内存溢出 | 使用临时文件模式 |
| 加密无法读取 | 提供密码参数 |
| 表单字段无法填写 | 检查字段是否被锁定 |
通过这些案例,你可以快速掌握 PDFBox 的主要功能,建议在实际项目中结合 Apache POI 处理 Excel 数据,iText 处理复杂 PDF 生成,实现更强大的文档处理能力。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播