itextpdf匯出

凛冬雪夜發表於2024-08-29
   <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
import com.itextpdf.text.Anchor;
		import com.itextpdf.text.Chunk;
		import com.itextpdf.text.Document;
		import com.itextpdf.text.Element;
		import com.itextpdf.text.Font;
		import com.itextpdf.text.Image;
		import com.itextpdf.text.PageSize;
		import com.itextpdf.text.Paragraph;
		import com.itextpdf.text.Phrase;
		import com.itextpdf.text.pdf.BaseFont;
		import com.itextpdf.text.pdf.PdfPCell;
		import com.itextpdf.text.pdf.PdfPTable;
		import com.itextpdf.text.pdf.PdfWriter;
		import com.itextpdf.text.pdf.draw.DottedLineSeparator;
		import com.itextpdf.text.pdf.draw.LineSeparator;

		import java.io.File;
		import java.io.FileOutputStream;

		/**
		 * 生成pdf
		 * <p>
		 * 參考: https://blog.csdn.net/weixin_37848710/article/details/89522862?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase
		 * https://blog.csdn.net/qq_39207908/article/details/82423388
		 */
		public class PdfExport {

			public static void main(String[] args) {
				try {
					// document
					Document document = new Document(PageSize.A4);

					// OutputStream
					File file = new File("D:\\Test.pdf");
					file.createNewFile();
					FileOutputStream fos = new FileOutputStream(file);

					PdfWriter writer = PdfWriter.getInstance(document, fos);

					// 水印
					writer.setPageEvent(new Watermark("HELLO ITEXTPDF"));

					// 頁首 和 頁尾
					writer.setPageEvent(new MyHeaderFooter());

					// 開啟 pdf
					document.open();

					/** 向 pdf 中寫入內容 *** start ******************************************************/
					// 1. 段落
					Paragraph paragraph_1 = new Paragraph("HELLO PDF!", titlefont);
					// 文字位置(靠左,居中,靠右 等)
					paragraph_1.setAlignment(Element.ALIGN_CENTER);
					// 左縮排
					paragraph_1.setIndentationLeft(12);
					// 右縮排
					paragraph_1.setIndentationRight(12);
					// 首行縮排
					paragraph_1.setFirstLineIndent(24);
					// 行間距
					paragraph_1.setLeading(20f);
					// 段落上空白
					paragraph_1.setSpacingBefore(5f);
					// 段落下空白
					paragraph_1.setSpacingAfter(10f);

					// 2. 直線
					Paragraph paragraph_2 = new Paragraph();
					paragraph_2.add(new Chunk(new LineSeparator()));

					// 3. 點線
					Paragraph paragraph_3 = new Paragraph();
					paragraph_3.add(new Chunk(new DottedLineSeparator()));

					// 4. 超連結
					Anchor link = new Anchor("baidu");
					link.setReference("www.baidu.com");

					// 5. 定位,如: 跳轉到文件頭部位置(測試發現: 使用瀏覽器時可以正常跳轉,使用 wps 時不可以)
					Anchor goTop = new Anchor("goTop");
					goTop.setReference("#top");

					// 6. 圖片(圖片地址若是以 http 開頭而非 https 開頭,可能會報錯)
					Image image = Image.getInstance("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1200524016,3386333024&fm=26&gp=0.jpg");
					image.setAlignment(Image.ALIGN_CENTER);
					image.scalePercent(40);

					// 表格
					PdfPTable table_1 = createTable(new float[]{50, 50});

					table_1.addCell(createCell("TEST", textfont, Element.ALIGN_LEFT));
					table_1.addCell(createCell("TEST", textfont, Element.ALIGN_LEFT));

					table_1.addCell(createCell("測試", textfont, Element.ALIGN_LEFT));
					table_1.addCell(createCell("測試", textfont, Element.ALIGN_LEFT));

					PdfPTable table_2 = createTable(new float[]{100});

					table_2.addCell(createCell("TEST", textfont, Element.ALIGN_LEFT));

					table_2.addCell(createCell("測試", textfont, Element.ALIGN_LEFT));


					// 直線
					Paragraph paragraph_4 = new Paragraph();
					paragraph_4.add(new Chunk(new LineSeparator()));
					// 行間距
					paragraph_4.setLeading(20f);
					// 段落上空白
					paragraph_4.setSpacingBefore(50f);
					// 段落下空白
					paragraph_4.setSpacingAfter(50f);

					// 合併單元格
					PdfPTable table_3 = createTable(new float[]{50, 50, 50, 50});

					table_3.addCell(createCellWithSpan("HEAD", textfont, Element.ALIGN_CENTER, 1, 4));

					table_3.addCell(createCell("AA", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("AA", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("AA", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("AA", textfont, Element.ALIGN_LEFT));

					table_3.addCell(createCellWithSpan("SPAN", textfont, Element.ALIGN_LEFT, 2, 2));
					table_3.addCell(createCell("BB", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("BB", textfont, Element.ALIGN_LEFT));

					table_3.addCell(createCell("CC", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("CC", textfont, Element.ALIGN_LEFT));

					table_3.addCell(createCell("EE", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("EE", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("EE", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("EE", textfont, Element.ALIGN_LEFT));

					table_3.addCell(createCell("FF", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCellForImage(image, textfont, Element.ALIGN_LEFT, 2, 2));
					table_3.addCell(createCell("FF", textfont, Element.ALIGN_LEFT));

					table_3.addCell(createCell("GG", textfont, Element.ALIGN_LEFT));
					table_3.addCell(createCell("GG", textfont, Element.ALIGN_LEFT));
					
					// 補充: table.setHeaderRows(2); 指定前 2 行作為標題行,作用: 使得當 table 由於分頁被分割時,可以在每頁都顯示標題行

					document.add(paragraph_1);
					document.add(paragraph_2);
					document.add(paragraph_3);
					document.add(link);
					document.add(image);
					document.add(table_1);
					document.add(table_2);
					document.add(paragraph_4);
					document.add(table_3);
					document.add(goTop);

					/** 向 pdf 中寫入內容 *** end ******************************************************/

					// 關閉 pdf
					document.close();

				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			// 定義全域性的字型靜態變數
			private static Font titlefont;
			private static Font headfont;
			private static Font keyfont;
			private static Font textfont;

			// 最大寬度
			private static int maxWidth = 520;

			// 字型
			static {
				try {
					BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
					titlefont = new Font(bfChinese, 16, Font.BOLD);
					headfont = new Font(bfChinese, 14, Font.BOLD);
					keyfont = new Font(bfChinese, 10, Font.BOLD);
					textfont = new Font(bfChinese, 10, Font.NORMAL);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}


			/**
			 * 建立指定 列寬、列數 的表格
			 *
			 * @param widths (列數: 陣列元素的個數)
			 * @return
			 */
			public static PdfPTable createTable(float[] widths) {
				PdfPTable table = new PdfPTable(widths);
				try {
					table.setTotalWidth(maxWidth);
					table.setLockedWidth(true);
					table.setHorizontalAlignment(Element.ALIGN_CENTER);
					table.getDefaultCell().setBorder(1);
				} catch (Exception e) {
					e.printStackTrace();
				}
				return table;
			}

			/**
			 * 建立單元格
			 *
			 * @param value               值
			 * @param font                字型
			 * @param horizontalAlignment 水平位置
			 * @return
			 */
			public static PdfPCell createCell(String value, Font font, int horizontalAlignment) {
				PdfPCell cell = new PdfPCell();
				cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
				cell.setHorizontalAlignment(horizontalAlignment);
				// 建議不設定單元格固定高度,因為這會導致單元格中的內容超出單元格的所能容納的字數時,使得部分內容丟失
				//cell.setFixedHeight(30);
				cell.setPhrase(new Phrase(value, font));
				return cell;
			}

			/**
			 * 建立單元格
			 *
			 * @param value               值
			 * @param font                字型
			 * @param horizontalAlignment 水平位置
			 * @param rowspan             合併行數
			 * @param colspan             合併列數
			 * @return
			 */
			public static PdfPCell createCellWithSpan(String value, Font font, int horizontalAlignment, int rowspan, int colspan) {
				PdfPCell cell = new PdfPCell();
				cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
				cell.setHorizontalAlignment(horizontalAlignment);
				cell.setRowspan(rowspan);
				cell.setColspan(colspan);
				cell.setPhrase(new Phrase(value, font));
				return cell;
			}

			/**
			 * 建立單元格(含圖片)
			 *
			 * @param image
			 * @param font
			 * @param horizontalAlignment
			 * @param colspan
			 * @param rowspan
			 * @return
			 */
			public static PdfPCell createCellForImage(Image image, Font font, int horizontalAlignment, int colspan, int rowspan) {
				PdfPCell cell = new PdfPCell();
				cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
				cell.setHorizontalAlignment(horizontalAlignment);
				cell.setColspan(colspan);
				cell.setRowspan(rowspan);
				cell.setImage(image);
				return cell;
			}

		}
點選檢視程式碼
import com.itextpdf.text.*;
		import com.itextpdf.text.pdf.*;

		import java.io.IOException;

		public class MyHeaderFooter extends PdfPageEventHelper {
			/**
			 * 總頁數
			 */
			PdfTemplate totalPage;
			Font hfFont;

			{
				try {
					hfFont = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), 8, Font.NORMAL);
				} catch (DocumentException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			/**
			 * 開啟文件時,建立一個總頁數的模版
			 */
			@Override
			public void onOpenDocument(PdfWriter writer, Document document) {
				PdfContentByte cb = writer.getDirectContent();
				totalPage = cb.createTemplate(30, 15);
			}

			/**
			 * 一頁載入完成觸發,寫入頁首或頁尾
			 */
			@Override
			public void onEndPage(PdfWriter writer, Document document) {
				PdfPTable table = new PdfPTable(2);
				try {
					table.setTotalWidth(PageSize.A4.getWidth());
					table.setWidths(new int[]{(int) (PageSize.A4.getWidth() / 2), (int) (PageSize.A4.getWidth() / 2)});
					table.setLockedWidth(true);

					// 第幾頁
					PdfPCell cell_1 = new PdfPCell(new Paragraph("第" + writer.getPageNumber() + "頁/", hfFont));
					cell_1.setHorizontalAlignment(Element.ALIGN_RIGHT);
					cell_1.setBorder(Rectangle.NO_BORDER);
					table.addCell(cell_1);

					// 總頁數
					PdfPCell cell_2 = new PdfPCell(Image.getInstance(totalPage));
					cell_2.setBorder(Rectangle.NO_BORDER);
					table.addCell(cell_2);

					// 將 頁首/頁尾 寫到指定位置,指定到上面就是頁首,指定到下面就是頁尾
					table.writeSelectedRows(0, -1, 0, 20, writer.getDirectContent());

				} catch (Exception de) {
					throw new ExceptionConverter(de);
				}
			}

			/**
			 * 全部完成後,將總頁數的 pdf 模版寫到指定位置
			 */
			@Override
			public void onCloseDocument(PdfWriter writer, Document document) {
				String text = "總" + (writer.getPageNumber()) + "頁";
				ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text, hfFont), 0, 5, 0);
			}

		}
點選檢視程式碼
import com.itextpdf.text.Document;
		import com.itextpdf.text.PageSize;
		import com.itextpdf.text.Paragraph;
		import com.itextpdf.text.pdf.PdfWriter;
		import org.springframework.stereotype.Controller;
		import org.springframework.web.bind.annotation.GetMapping;

		import javax.servlet.http.HttpServletResponse;
		import java.io.ByteArrayOutputStream;
		import java.io.OutputStream;

		/**
		 * pdf 下載
		 */
		@Controller
		public class PdfController {

			@GetMapping("/downloadPdf")
			public void downloadPdf(HttpServletResponse response) {
				try {
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					Document document = new Document(PageSize.A4);

					PdfWriter.getInstance(document, baos);

					// 開啟 pdf
					document.open();

					// 向 pdf 寫入內容
					Paragraph paragraph = new Paragraph("hello world");
					document.add(paragraph);

					// 關閉 pdf
					document.close();

					String fileName = "MyPdfTest";
					response.setContentType("application/pdf");
					response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".pdf");
					response.setContentLength(baos.size());
					OutputStream out = response.getOutputStream();
					baos.writeTo(out);
					out.flush();
					out.close();

				} catch (Exception e) {
					e.printStackTrace();
				}
			}

		}
點選檢視程式碼

			^
			|
			|
			Y
			|
			+----------+
			|          |
			|   pdf    |
			|          |
			|  文 件   |
			|          |
			|          |
		 ---+----------+----X-->
		   O|
			|
			|

		// 測試
			public static void main(String[] args) {
			
				Document document = new Document(PageSize.A4);

				System.err.println("rectangle:" + document.getPageSize());
				// 頂部 y 座標
				System.err.println("top:" + document.getPageSize().getTop());
				// 底部 y 座標
				System.err.println("bottom:" + document.getPageSize().getBottom());
				// 最左側 x 座標
				System.err.println("left:" + document.getPageSize().getLeft());
				// 最右側 x 座標
				System.err.println("right:" + document.getPageSize().getRight());
			}

相關文章