本文目录导读:

我来详细介绍Java生成PDF的几种主流方法及具体案例。
iText库(最常用)
Maven依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.5</version>
<type>pom</type>
</dependency>
基础案例:创建简单PDF
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
public class SimplePdfGenerator {
public static void createSimplePdf(String dest) throws Exception {
// 1. 创建PdfWriter
PdfWriter writer = new PdfWriter(dest);
// 2. 创建PdfDocument
PdfDocument pdfDoc = new PdfDocument(writer);
// 3. 创建Document
Document document = new Document(pdfDoc);
// 4. 添加内容
document.add(new Paragraph("Hello World!"));
document.add(new Paragraph("这是中文PDF示例"));
// 5. 关闭文档
document.close();
}
public static void main(String[] args) throws Exception {
createSimplePdf("simple.pdf");
System.out.println("PDF生成成功!");
}
}
高级案例:表格和样式
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
public class AdvancedPdfGenerator {
public static void createTablePdf(String dest) throws Exception {
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc);
// 添加中文标题
document.add(new Paragraph("员工信息表")
.setTextAlignment(TextAlignment.CENTER)
.setFontSize(20)
.setBold());
// 创建表格
float[] columnWidths = {1, 2, 3, 2};
Table table = new Table(UnitValue.createPercentArray(columnWidths));
// 添加表头
String[] headers = {"ID", "姓名", "部门", "薪资"};
for (String header : headers) {
Cell cell = new Cell().add(new Paragraph(header))
.setBackgroundColor(ColorConstants.LIGHT_GRAY)
.setTextAlignment(TextAlignment.CENTER);
table.addCell(cell);
}
// 添加数据
String[][] data = {
{"001", "张三", "技术部", "15000"},
{"002", "李四", "市场部", "12000"},
{"003", "王五", "人事部", "10000"}
};
for (String[] row : data) {
for (String cellData : row) {
table.addCell(new Cell().add(new Paragraph(cellData))
.setTextAlignment(TextAlignment.CENTER));
}
}
document.add(table);
document.close();
}
}
Apache POI(适用于简单PDF)
Maven依赖
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.27</version>
</dependency>
案例:使用PDFBox创建PDF
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
public class PdfBoxExample {
public static void createPdf() throws Exception {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// 设置字体
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 24);
contentStream.beginText();
contentStream.newLineAtOffset(100, 700);
contentStream.showText("Hello PDFBox!");
contentStream.endText();
contentStream.close();
document.save("pdfbox-example.pdf");
}
}
}
JasperReports(报表生成)
Maven依赖
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.20.5</version>
</dependency>
案例:从数据生成PDF报表
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import java.util.*;
public class JasperReportExample {
public static void generateReport() throws JRException {
// 准备数据
List<Employee> employees = Arrays.asList(
new Employee("001", "张三", "技术部"),
new Employee("002", "李四", "市场部")
);
// 创建数据源
JRBeanCollectionDataSource dataSource =
new JRBeanCollectionDataSource(employees);
// 编译报表模板
JasperReport jasperReport = JasperCompileManager
.compileReport("template.jrxml");
// 填充数据
JasperPrint jasperPrint = JasperFillManager
.fillReport(jasperReport, new HashMap<>(), dataSource);
// 导出PDF
JasperExportManager.exportReportToPdfFile(
jasperPrint, "report.pdf");
}
}
class Employee {
private String id;
private String name;
private String department;
// 构造方法和getter/setter
}
使用模板引擎+HTML转PDF
Maven依赖(使用Flying Saucer)
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
案例:HTML模板转PDF
import org.xhtmlrenderer.pdf.ITextRenderer;
public class HtmlToPdfExample {
public static void convertHtmlToPdf() throws Exception {
String htmlContent = """
<html>
<head>
<style>
body { font-family: SimSun; }
h1 { color: blue; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid black; padding: 8px; }
</style>
</head>
<body>
<h1>用户信息报告</h1>
<table>
<tr><th>ID</th><th>姓名</th><th>邮箱</th></tr>
<tr><td>001</td><td>张三</td><td>zhang@example.com</td></tr>
<tr><td>002</td><td>李四</td><td>li@example.com</td></tr>
</table>
</body>
</html>
""";
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(htmlContent);
renderer.layout();
try (OutputStream os = new FileOutputStream("output.pdf")) {
renderer.createPDF(os);
}
}
}
完整实用示例:生成发票PDF
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.TextAlignment;
public class InvoicePdfGenerator {
public static void createInvoice(String fileName,
InvoiceData data) throws Exception {
PdfWriter writer = new PdfWriter(fileName);
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc);
// 公司信息
document.add(new Paragraph("XX科技有限公司")
.setTextAlignment(TextAlignment.CENTER)
.setFontSize(24).setBold());
document.add(new Paragraph("发票号码:" + data.getInvoiceNo())
.setTextAlignment(TextAlignment.RIGHT));
// 客户信息
document.add(new Paragraph("客户:" + data.getCustomerName()));
document.add(new Paragraph("日期:" + data.getDate()));
document.add(new Paragraph("\n"));
// 商品明细表格
float[] columnWidths = {1, 3, 2, 2, 2};
Table table = new Table(UnitValue.createPercentArray(columnWidths));
// 表头
String[] headers = {"序号", "商品名称", "数量", "单价", "金额"};
for (String header : headers) {
table.addHeaderCell(new Cell().add(new Paragraph(header))
.setBold().setTextAlignment(TextAlignment.CENTER));
}
// 商品数据
double total = 0;
int index = 1;
for (InvoiceItem item : data.getItems()) {
table.addCell(String.valueOf(index++));
table.addCell(item.getName());
table.addCell(String.valueOf(item.getQuantity()));
table.addCell(String.format("%.2f", item.getPrice()));
double amount = item.getQuantity() * item.getPrice();
table.addCell(String.format("%.2f", amount));
total += amount;
}
document.add(table);
// 总计
document.add(new Paragraph("\n"));
document.add(new Paragraph("总计金额:¥" + String.format("%.2f", total))
.setTextAlignment(TextAlignment.RIGHT)
.setBold().setFontSize(16));
document.close();
}
// 测试
public static void main(String[] args) throws Exception {
InvoiceData data = new InvoiceData();
data.setInvoiceNo("INV-2024-001");
data.setCustomerName("阿里巴巴集团");
data.setDate("2024-01-15");
data.setItems(Arrays.asList(
new InvoiceItem("笔记本电脑", 5, 5999.00),
new InvoiceItem("显示器", 10, 1599.00),
new InvoiceItem("键盘", 20, 299.00)
));
createInvoice("invoice.pdf", data);
System.out.println("发票PDF生成成功!");
}
}
// 数据模型
class InvoiceData {
private String invoiceNo;
private String customerName;
private String date;
private List<InvoiceItem> items;
// getter/setter省略
}
class InvoiceItem {
private String name;
private int quantity;
private double price;
// 构造方法、getter/setter省略
}
性能优化建议
// 1. 使用连接池管理字体资源
public class PdfFontProvider {
private static Map<String, PdfFont> fontCache = new HashMap<>();
public static PdfFont getFont(String fontPath) throws Exception {
return fontCache.computeIfAbsent(fontPath,
path -> PdfFontFactory.createFont(path));
}
}
// 2. 批量处理时复用资源
public class BatchPdfGenerator {
public void batchGenerate(List<Data> dataList) throws Exception {
// 预编译模板,复用PdfWriter等资源
PdfFont font = PdfFontFactory.createFont("STSong-Light");
for (Data data : dataList) {
try (PdfWriter writer = new PdfWriter(data.getFileName());
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc)) {
// 生成PDF
generateContent(document, data, font);
}
}
}
}
选型建议
| 场景 | 推荐方案 | 优点 | 缺点 |
|---|---|---|---|
| 简单PDF | iText/iText7 | 功能强大,社区活跃 | 商业使用需授权 |
| 报表类 | JasperReports | 模板化,支持复杂报表 | 学习曲线较陡 |
| 基于HTML | Flying Saucer | 可用CSS样式 | 对CSS支持有限 |
| 官方格式 | Apache PDFBox | Apache许可证,免费 | 功能相对基础 |
| 跨平台 | Aspose.Words | 功能全面 | 商业授权费用高 |
选择合适的方案时,考虑以下因素:
- 预算:商业使用要注意许可证
- 复杂度:简单文档用iText,复杂报表用JasperReports
- 团队技能:熟悉HTML可选HTML转PDF方式
- 性能要求:大数据量时选择性能更好的方案