HttpServletResponse,瀏覽器內聯顯示或下載,無需客戶端插件。// 1. 創建文檔模型 (頁面大小、邊距)
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
// 2. 綁定寫入器 (輸出目標: 文件/輸出流/HTTP 響應)
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("report.pdf"));
// Web 場景: PdfWriter.getInstance(document, response.getOutputStream());
// 3. 打開文檔 (必須在添加內容前)
document.open();
// 4. 添加內容 (Paragraph, Table, Image, List, Chapter...)
// ... 見下文詳解 ...
// 5. 關閉文檔 (刷新緩衝區、寫入 xref 表、釋放資源)
document.close();
| 功能 | API | 說明 |
|---|---|---|
| 元數據 | document.addTitle/Author/Subject/Keywords/Creator() | PDF 屬性欄顯示 |
| 頁眉/頁腳 | document.setHeader/Footer(new HeaderFooter(...)) | 需在 open() 前設置首頁;換頁自動重複 |
| 頁碼 | HeaderFooter(..., true) 最後一參為 true 自動生成頁碼 | 可自定義格式 "第 {PAGE} 頁" |
| 水印 | document.add(new Watermark("CONFIDENTIAL")) | 斜向灰色文字覆蓋 |
| 頁面大小/橫向 | document.setPageSize(PageSize.A4.rotate()) | 新頁面生效;首頁需 open() 前設置 |
| 加密權限 | writer.setEncryption(userPass, ownerPass, PdfWriter.ALLOW_PRINTING, PdfWriter.STRENGTH128BITS) | 設置用戶/擁有者密碼、禁止複製/修改/打印 |
| 查看器偏好 | writer.setViewerPreferences(PdfWriter.PageLayoutSinglePage | PdfWriter.HideToolbar) | 控制 Acrobat 打開行為 |
new Chunk("text", font)phrase.add(chunk)。可設置行距 setLeading(16f)。para.setAlignment(Element.ALIGN_CENTER) (1=居中, 2=右對齊, 0=左對齊)。itext-asian.jar (含 Adobe 亞洲字體包映射)。BaseFont bfChinese = BaseFont.createFont(
"STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); // 不嵌入字體,依賴閱讀器
Font chineseFont = new Font(bfChinese, 12, Font.NORMAL);
Paragraph p = new Paragraph("中文報表標題", chineseFont);
注意:NOT_EMBEDDED 體積小但要求客戶端系統安裝對應字體 (Windows 通常有宋體/微軟雅黑);嵌入字體 (BaseFont.EMBEDDED) 文件大增但跨平台顯示一致。
推薦使用 com.lowagie.text.pdf.PdfPTable (在 com.lowagie.text.pdf 包下),功能完整、支持跨頁、單元格合併、邊框精細控制。舊 com.lowagie.text.Table 已棄用。
PdfPTable table = new PdfPTable(3); // 3 列
table.setWidthPercentage(100); // 佔頁面寬度 100%
table.setSpacingBefore(10f); table.setSpacingAfter(10f);
table.setWidths(new float[]{1, 2, 3}); // 相對列寬比例
// 表頭
PdfPCell header = new PdfPCell(new Phrase("報表標題", headerFont));
header.setColspan(3); header.setHorizontalAlignment(Element.ALIGN_CENTER);
header.setBackgroundColor(BaseColor.LIGHT_GRAY);
header.setBorderWidth(1);
table.addCell(header); // addCell 自動換行填充
table.completeRow(); // 可選:強制結束當前行
// 數據行
table.addCell(new PdfPCell(new Phrase("列1", cellFont)));
table.addCell(new PdfPCell(new Phrase("列2", cellFont)));
table.addCell(new PdfPCell(new Phrase("列3", cellFont)));
// 循環添加數據...
document.add(table);
cell.setRowspan(2); cell.setColspan(2);cell.setBorder(Rectangle.NO_BORDER) 或組合 Rectangle.TOP | Rectangle.BOTTOM,setBorderColor()、setBorderWidth()。cell.setPadding(5) / setPaddingLeft/Right/Top/Bottom。cell.setVerticalAlignment(Element.ALIGN_MIDDLE)。table.setSplitLate(false) (盡量不拆分行);cell.setNoWrap(true) (單元格內不換行)。Image img = Image.getInstance("chart.png"); // 自動識別格式
img.setAlignment(Image.MIDDLE | Image.TEXTWRAP); // 居中 + 文字環繞
img.scalePercent(50); // 縮放 50%
img.setRotationDegrees(30); // 旋轉 30 度
document.add(img);
支持格式:JPEG, PNG, GIF, WMF, BMP, TIFF (需 JAI)。
@WebServlet("/pdf/report")
public class ReportServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
resp.setContentType("application/pdf");
// 內聯顯示: inline; 下載: attachment
resp.setHeader("Content-Disposition", "inline; filename=report.pdf");
try {
Document doc = new Document(PageSize.A4);
PdfWriter.getInstance(doc, resp.getOutputStream());
doc.open();
// ... 構建報表內容 ...
doc.close(); // 關鍵:必須 close 才能輸出完整 PDF
} catch (DocumentException | IOException e) {
throw new ServletException(e);
}
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 中文顯示為 □/亂碼 | 未註冊中文字體 / 字體未嵌入且客戶端無字體 | 引入 itext-asian,使用 STSong-Light/UniGB-UCS2-H,或嵌入 TTF 字體 |
| 表格跨頁表頭不重複 | 未設置 Header 行 | table.setHeaderRows(1) (前 N 行作為表頭自動重複) |
| 生成的 PDF 打開報錯「文件損壞」 | document.close() 未調用 / 輸出流被提前關閉 / Servlet 又寫了其他內容 | 確保 close() 在 finally 執行,Response 只輸出 PDF 流 |
| 大報表生成 OOM | 一次性構建巨大 Document 對象樹 | 分頁生成、使用 PdfPTable 流式寫入、或升級 iText 7 (更高效) |
| 圖片不顯示 | 相對路徑錯誤 / 圖片流已關閉 | 用 Image.getInstance(byte[]) 或 InputStream,確保流在 doc.close() 前有效 |