SpringBoot使用iText7實現將HTML轉成PDF并添加頁眉頁腳水印
更新時間:2024年03月26日 10:06:45 作者:從烏托邦醒來
這篇文章主要為大家詳細介紹了SpringBoot使用iText7實現將HTML轉成PDF并添加頁眉頁腳水印的相關知識,感興趣的小伙伴可以跟隨小編一起學習一下
一、依賴
<!-- itext7 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>kernel</artifactId> <version>7.2.4</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>io</artifactId> <version>7.2.4</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>forms</artifactId> <version>7.2.4</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>layout</artifactId> <version>7.2.4</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>svg</artifactId> <version>7.2.4</version> </dependency> <!-- font-asian 用于itext使用東亞字體 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>font-asian</artifactId> <version>7.2.4</version> </dependency> <!-- html2pdf 用于轉換html為pdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>4.0.1</version> </dependency>
二、代碼
2.1、通用方法
/** * * @param pdf_path PDF文件保存路徑 * @param pdf_name PDF文件名 * @param cookie 用戶信息 * @param waterContent 水印內容 * @return * @throws AppException */ public PmsLXPDF createHtmlToPDF(String pdf_path, String pdf_name, String cookie, String waterContent) throws AppException { logger.info("開始createPDF"); PmsLXPDF pdf = new PmsLXPDF(); String pdfViewUrl = "這里是接口路徑,生成jsp模板"; String url = Config.getMeurl(); logger.info("createPDF方法獲取meurl[{}]",url); ItextHtmlToPdf.convert(url + pdfViewUrl, pdf_path, cookie, waterContent); File file = new File(pdf_path); if (file == null || !file.exists()) { throw new AppException("立項報告生成pdf失??!"); } try { //可以做一些保存的操作 } catch (Exception e) { logger.error("Exception happened", e); } //pdf.setSuccess(StringUtils.isNotBlank(id)); logger.info("createPDF結束"); return pdf; } /** * html轉pdf * * @param srcPath html路徑,可以是硬盤上的路徑,也可以是網絡路徑 * @param destPath pdf保存路徑 * @return 轉換成功返回true */ public static boolean convert(String srcPath, String destPath, String cookie, String waterContent) { if (!FileUtils.createFile(destPath)) { LOGGER.error("目標路徑PDF文件已存在,生成PDF失?。? + destPath); return false; } LOGGER.info("convert方法傳入的srcPath[{}],cookie[{}]",srcPath,cookie); InputStream in = null; OutputStream out = null; HttpURLConnection connection = null; try { if (srcPath.startsWith("http")) { LOGGER.info("convert方法傳入的srcPath[{}],進入了需要cookie的分支",srcPath); URL url = new URL(srcPath); int connectTimeout = Integer.parseInt(ConfigUtil.getConfig("xxx", "30000")); int readTimeout = Integer.parseInt(ConfigUtil.getConfig("xxx", "30000")); connection = (HttpURLConnection) url.openConnection(); // 設置連接主機服務器的超時時間 connection.setConnectTimeout(connectTimeout); // 設置讀取遠程返回的數據時間 connection.setReadTimeout(readTimeout); if (StringUtils.isNotBlank(cookie)) { // 設置Cookie String cookies = "SESSION=".concat(cookie); connection.setRequestProperty("Cookie", cookies); } // 連接和獲取響應 connection.connect(); in = connection.getInputStream(); } else { LOGGER.info("convert方法傳入的srcPath[{}],進入了不需要登錄的分支",srcPath); in = new FileInputStream(srcPath); } out = new ByteArrayOutputStream(); HtmlPrittifier.fixHtml(in, out); } catch (Throwable t) { LOGGER.error("讀取該文件失?。? + srcPath, t); return false; } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); if (connection != null) { connection.disconnect();// 關閉遠程連接 } } String html = out.toString(); converCreatPdf(destPath, cookie, html, waterContent); return true; } private static boolean converCreatPdf(String destPath, String cookie, String html, String waterContent) { try (OutputStream fos = new FileOutputStream(destPath)) { //將html轉換成pdf PdfWriter pdfWriter = new PdfWriter(fos); PdfDocument pdfDoc = new PdfDocument(pdfWriter); // 統(tǒng)一設置頁眉 String header = "我是頁眉"; Header headerHandler = new Header(header); pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler); // 統(tǒng)一設置頁腳 Footer footerHandler = new Footer(); pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, footerHandler); if (StringUtils.isNotBlank(waterContent)) { // 添加水印 PdfWaterMarker pdfWaterMarker = new PdfWaterMarker(waterContent); pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, pdfWaterMarker); } // 需要先生成document,而不是直接生成pdf文件(因直接生成pdf文件會關閉流) ConverterProperties converterProperties = getConverterProperties(cookie); Document document = HtmlConverter.convertToDocument(html, pdfDoc, converterProperties); // flush觸發(fā)寫操作,此時才會觸發(fā)已經注冊的事件處理器 document.flush(); // 待document對象寫完后,才能開始寫入總頁碼 LOGGER.debug("PDF總頁數:" + document.getPdfDocument().getNumberOfPages()); footerHandler.writeTotal(pdfDoc); document.close(); } catch (Throwable t) { LOGGER.error("生成PDF失敗:" + destPath, t); return false; } return true; } public static ConverterProperties getConverterProperties(String cookie) { ConverterProperties converterProperties = new ConverterProperties(); FontProvider fontProvider = getFontProvider(); converterProperties.setFontProvider(fontProvider); CookieResourceRetriever myResourceRetriever = new CookieResourceRetriever(cookie); converterProperties.setResourceRetriever(myResourceRetriever); return converterProperties; } public void writeTotal(PdfDocument pdf) { Canvas canvas = new Canvas(placeholder, pdf); canvas.setFontSize(8); if (font != null) { // 設置支持中文 canvas.setFont(this.font); // 在占位符寫入總頁數 canvas.showTextAligned(String.format("/共[%d]頁", pdf.getNumberOfPages()), 0, descent, TextAlignment.LEFT); } canvas.close(); }
2.2、工具類
public class HtmlPrittifier { /** * 將HTML標準化,補全缺失的閉標簽 * * @param in * @param out */ public static void fixHtml(InputStream in, OutputStream out) { // obtain a new Tidy instance Tidy tidy = new Tidy(); // set desired config options using tidy setters tidy.setXHTML(true); tidy.setInputEncoding("utf8"); tidy.setShowWarnings(true); tidy.setWraplen(1024); tidy.setSmartIndent(true); tidy.setQuiet(true); tidy.setPrintBodyOnly(false); tidy.setOutputEncoding("utf8"); tidy.setTidyMark(false); // output document even if errors were found. 防止有些自定義tag匹配不上導致pdf不輸出 tidy.setForceOutput(true); // 不轉換uri,防止uri中有中文,會將非ascii碼轉為十六進制,導致找不到中文圖片鏈接。 tidy.setFixUri(false); tidy.parse(in, out); } /** * 將HTML標準化,補全缺失的閉標簽 * * @param htmlString */ @SneakyThrows public static String fixHtml(String htmlString) { ByteArrayInputStream in = new ByteArrayInputStream(htmlString.getBytes("UTF-8")); ByteArrayOutputStream out = new ByteArrayOutputStream(); fixHtml(in, out); return out.toString(); } }
2.3、水印實現方法
private static PdfFont createDefaultFont() throws IOException { return PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); } protected static class PdfWaterMarker implements IEventHandler { private PdfFont font; private String waterContent; public PdfWaterMarker(String waterContent) { this.waterContent = waterContent; try { this.font = createDefaultFont(); } catch (IOException e) { LOGGER.error("PDF Header設置中文字體失敗", e); } } @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent) event; PdfDocument pdfDoc = docEvent.getDocument(); PdfPage page = docEvent.getPage(); Rectangle pageSize = page.getPageSize(); PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), pdfDoc); Canvas canvas = new Canvas(pdfCanvas, pageSize); // 設置水印文字內容 Paragraph waterMarker = new Paragraph(waterContent) .setFont(font) .setOpacity(0.15f)// 設置透明度 .setFontSize(16);// 文字大小 /*for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { canvas.showTextAligned(waterMarker, (150 + i * 300), (160 + j * 150), pdfDoc.getNumberOfPages(), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0.3f); } }*/ // 計算水印的起始位置和間隔 float xStart = 1; float yStart = 1; float stepX = 150; float stepY = 150; // 在頁面上循環(huán)繪制水印文字 for (float x = xStart; x < pageSize.getWidth(); x += stepX) { for (float y = yStart; y < pageSize.getHeight(); y += stepY) { // 繪制水印文字 canvas.showTextAligned(waterMarker, x, y, pdfDoc.getNumberOfPages(), TextAlignment.LEFT, VerticalAlignment.MIDDLE, 0.6f); } } // 關閉流 canvas.close(); } }
2.4、頁眉實現方法
private static PdfFont createDefaultFont() throws IOException { return PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); } protected static class Header implements IEventHandler { private String header; private PdfFont font; public Header(String header) { this.header = header; try { this.font = createDefaultFont(); } catch (IOException e) { LOGGER.error("PDF Header設置中文字體失敗", e); } } @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent)event; PdfDocument pdf = docEvent.getDocument(); PdfPage page = docEvent.getPage(); Rectangle pageSize = page.getPageSize(); Document doc = new Document(pdf); float leftMargin = doc.getLeftMargin(); float rightMargin = doc.getRightMargin(); float bottomMargin = doc.getBottomMargin(); float topMargin = doc.getTopMargin(); float height = pageSize.getHeight(); float width = pageSize.getWidth(); Canvas canvas = new Canvas(new PdfCanvas(page), pageSize); if (font != null) { // 設置支持中文 canvas.setFont(this.font); } canvas.setFontSize(8); // Creates drawing canvas PdfCanvas pdfCanvas = new PdfCanvas(page); pdfCanvas.setLineWidth(0.1f); pdfCanvas.moveTo(leftMargin, height - topMargin + 3).lineTo(width - rightMargin, height - topMargin + 3) .stroke(); // Write text at position canvas.showTextAligned(header, width / 2, height - 30, TextAlignment.CENTER); canvas.close(); } }
2.5、頁腳實現方法
protected static class Footer implements IEventHandler { // 寫總頁碼的占位符 protected PdfFormXObject placeholder; // 頁腳占位符大小 private float side = 36; // 頁腳占位符位置向右調整移動1,向下調整移動3 private float space = 1; private float descent = 3; private PdfFont font; public Footer() { this.placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side)); try { this.font = createDefaultFont(); } catch (IOException e) { LOGGER.error("PDF Footer設置中文字體失敗", e); } } @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent)event; PdfDocument pdf = docEvent.getDocument(); PdfPage page = docEvent.getPage(); int pageNumber = pdf.getPageNumber(page); Rectangle pageSize = page.getPageSize(); LOGGER.debug(String.format("當前處理第[%d]頁", pageNumber)); Document doc = new Document(pdf); float leftMargin = doc.getLeftMargin(); float rightMargin = doc.getRightMargin(); float bottomMargin = doc.getBottomMargin(); float height = page.getPageSize().getHeight(); float width = page.getPageSize().getWidth(); // 頁腳的位置 float x = width / 2; float y = bottomMargin / 2; // Creates drawing canvas PdfCanvas pdfCanvas = new PdfCanvas(page); Canvas canvas = new Canvas(pdfCanvas, pageSize); if (font != null) { // 設置支持中文 canvas.setFont(this.font); } canvas.setFontSize(8); // 設置支持橫線 // canvas.setStrokeWidth(0.1f); pdfCanvas.setLineWidth(0.1f); pdfCanvas.moveTo(leftMargin, bottomMargin - 3).lineTo(width - rightMargin, bottomMargin - 3).stroke(); // 設置支持頁碼 Paragraph p = new Paragraph().add(String.format("第[%d]頁", pageNumber)); canvas.showTextAligned(p, x, y, TextAlignment.RIGHT); canvas.close(); // 添加占位符,用于寫入總頁碼 pdfCanvas.addXObjectAt(placeholder, x + space, y - descent); pdfCanvas.release(); }
三、jsp實現水印
不影響之前已經生成模板的代碼
<style> #watermark div { /* color: rgba(255, 0, 0, .1); */ color: rgba(0, 0, 255, .1); position: absolute; font-size: 24px; white-space: nowrap; transform: rotate(-30deg); -ms-transform: rotate(-30deg); /* IE 9 */ -moz-transform: rotate(-30deg); /* Firefox */ -webkit-transform: rotate(-30deg); /* Safari 和 Chrome */ -o-transform: rotate(-30deg); /* Opera */ } </style> <div id="watermark" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: transparent; pointer-events: none; z-index: 99999999;"> </div> <script> var operatorName = '${requestScope.xx.xxx}'; var erpId = '${requestScope.xx.xxx}'; (function() { var w = screen.width; var h = screen.height; var r = Math.sqrt(w * w + h * h); var i = 0; var j = 0; var watermark = document.querySelector('#watermark'); var div; var top, left; for (var i = 0; i < 10; ++i) { for (var j = 0; j < 10; ++j) { div = document.createElement('div'); div.innerText = '禁止外傳:' + operatorName + '(' + erpId + ')'; top = i * 100 + 'px'; left = 500 * j - 50 - (i % 2 == 0 ? 250 : 0) + 'px'; div.style.setProperty('top', top); div.style.setProperty('left', left); watermark.appendChild(div); } } })(); </script>
以上就是SpringBoot使用iText7實現將HTML轉成PDF并添加頁眉頁腳水印的詳細內容,更多關于SpringBoot HTML轉PDF的資料請關注腳本之家其它相關文章!