最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot使用iText7實(shí)現(xiàn)將HTML轉(zhuǎn)成PDF并添加頁(yè)眉頁(yè)腳水印

 更新時(shí)間:2024年03月26日 10:06:45   作者:從烏托邦醒來  
這篇文章主要為大家詳細(xì)介紹了SpringBoot使用iText7實(shí)現(xiàn)將HTML轉(zhuǎn)成PDF并添加頁(yè)眉頁(yè)腳水印的相關(guān)知識(shí),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

一、依賴

        <!-- 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 用于轉(zhuǎn)換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 水印內(nèi)容
     * @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("立項(xiàng)報(bào)告生成pdf失??!");
        }
        try {
            //可以做一些保存的操作
        } catch (Exception e) {
            logger.error("Exception happened", e);
        }
        //pdf.setSuccess(StringUtils.isNotBlank(id));
        logger.info("createPDF結(jié)束");
 
        return pdf;
    }
 
 
 
 
/**
     * html轉(zhuǎn)pdf
     *
     * @param srcPath html路徑,可以是硬盤上的路徑,也可以是網(wǎng)絡(luò)路徑
     * @param destPath pdf保存路徑
     * @return 轉(zhuǎn)換成功返回true
     */
    public static boolean convert(String srcPath, String destPath, String cookie, String waterContent) {
        if (!FileUtils.createFile(destPath)) {
            LOGGER.error("目標(biāo)路徑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[{}],進(jìn)入了需要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();
                // 設(shè)置連接主機(jī)服務(wù)器的超時(shí)時(shí)間
                connection.setConnectTimeout(connectTimeout);
                // 設(shè)置讀取遠(yuǎn)程返回的數(shù)據(jù)時(shí)間
                connection.setReadTimeout(readTimeout);
                if (StringUtils.isNotBlank(cookie)) {
                    // 設(shè)置Cookie
                    String cookies = "SESSION=".concat(cookie);
                    connection.setRequestProperty("Cookie", cookies);
                }
                // 連接和獲取響應(yīng)
                connection.connect();
                in = connection.getInputStream();
            } else {
                LOGGER.info("convert方法傳入的srcPath[{}],進(jìn)入了不需要登錄的分支",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();// 關(guān)閉遠(yuǎn)程連接
            }
        }
        
        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轉(zhuǎn)換成pdf
            PdfWriter pdfWriter = new PdfWriter(fos);
            PdfDocument pdfDoc = new PdfDocument(pdfWriter);
 
            // 統(tǒng)一設(shè)置頁(yè)眉
            String header = "我是頁(yè)眉";
            Header headerHandler = new Header(header);
            pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
 
            // 統(tǒng)一設(shè)置頁(yè)腳
            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文件會(huì)關(guān)閉流)
            ConverterProperties converterProperties = getConverterProperties(cookie);
            Document document = HtmlConverter.convertToDocument(html, pdfDoc, converterProperties);
 
            // flush觸發(fā)寫操作,此時(shí)才會(huì)觸發(fā)已經(jīng)注冊(cè)的事件處理器
            document.flush();
 
            // 待document對(duì)象寫完后,才能開始寫入總頁(yè)碼
            LOGGER.debug("PDF總頁(yè)數(shù):" + 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) {
                // 設(shè)置支持中文
                canvas.setFont(this.font);
                // 在占位符寫入總頁(yè)數(shù)
                canvas.showTextAligned(String.format("/共[%d]頁(yè)", pdf.getNumberOfPages()), 0, descent,
                    TextAlignment.LEFT);
            }
            canvas.close();
        }

2.2、工具類

public class HtmlPrittifier {
 
    /**
     * 將HTML標(biāo)準(zhǔn)化,補(bǔ)全缺失的閉標(biāo)簽
     *
     * @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匹配不上導(dǎo)致pdf不輸出
        tidy.setForceOutput(true);
 
        // 不轉(zhuǎn)換uri,防止uri中有中文,會(huì)將非ascii碼轉(zhuǎn)為十六進(jìn)制,導(dǎo)致找不到中文圖片鏈接。
        tidy.setFixUri(false);
 
        tidy.parse(in, out);
    }
 
    /**
     * 將HTML標(biāo)準(zhǔn)化,補(bǔ)全缺失的閉標(biāo)簽
     * 
     * @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、水印實(shí)現(xiàn)方法

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設(shè)置中文字體失敗", 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);
 
            // 設(shè)置水印文字內(nèi)容
            Paragraph waterMarker = new Paragraph(waterContent)
                    .setFont(font)
                    .setOpacity(0.15f)// 設(shè)置透明度
                    .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);
                }
            }*/
 
            // 計(jì)算水印的起始位置和間隔
            float xStart = 1;
            float yStart = 1;
            float stepX = 150;
            float stepY = 150;
 
            // 在頁(yè)面上循環(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);
                }
            }
            // 關(guān)閉流
            canvas.close();
        }
    }

2.4、頁(yè)眉實(shí)現(xiàn)方法

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設(shè)置中文字體失敗", 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) {
                // 設(shè)置支持中文
                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、頁(yè)腳實(shí)現(xiàn)方法

protected static class Footer implements IEventHandler {
 
        // 寫總頁(yè)碼的占位符
        protected PdfFormXObject placeholder;
 
        // 頁(yè)腳占位符大小
        private float side = 36;
 
        // 頁(yè)腳占位符位置向右調(diào)整移動(dòng)1,向下調(diào)整移動(dòng)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設(shè)置中文字體失敗", 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āng)前處理第[%d]頁(yè)", 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();
 
            // 頁(yè)腳的位置
            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) {
                // 設(shè)置支持中文
                canvas.setFont(this.font);
            }
            canvas.setFontSize(8);
 
            // 設(shè)置支持橫線
            // canvas.setStrokeWidth(0.1f);
            pdfCanvas.setLineWidth(0.1f);
            pdfCanvas.moveTo(leftMargin, bottomMargin - 3).lineTo(width - rightMargin, bottomMargin - 3).stroke();
 
            // 設(shè)置支持頁(yè)碼
            Paragraph p = new Paragraph().add(String.format("第[%d]頁(yè)", pageNumber));
            canvas.showTextAligned(p, x, y, TextAlignment.RIGHT);
            canvas.close();
 
            // 添加占位符,用于寫入總頁(yè)碼
            pdfCanvas.addXObjectAt(placeholder, x + space, y - descent);
            pdfCanvas.release();
 
        }

三、jsp實(shí)現(xiàn)水印

不影響之前已經(jīng)生成模板的代碼

<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實(shí)現(xiàn)將HTML轉(zhuǎn)成PDF并添加頁(yè)眉頁(yè)腳水印的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot HTML轉(zhuǎn)PDF的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java Spring Cloud Bus 實(shí)現(xiàn)配置實(shí)時(shí)更新詳解

    Java Spring Cloud Bus 實(shí)現(xiàn)配置實(shí)時(shí)更新詳解

    這篇文章主要介紹了SpringCloud Bus如何實(shí)現(xiàn)配置刷新,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-09-09
  • 用攔截器修改返回response,對(duì)特定的返回進(jìn)行修改操作

    用攔截器修改返回response,對(duì)特定的返回進(jìn)行修改操作

    這篇文章主要介紹了用攔截器修改返回response,對(duì)特定的返回進(jìn)行修改操作。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • SpringBoot集成免費(fèi)的EdgeTTS實(shí)現(xiàn)文本轉(zhuǎn)語(yǔ)音

    SpringBoot集成免費(fèi)的EdgeTTS實(shí)現(xiàn)文本轉(zhuǎn)語(yǔ)音

    在需要文本轉(zhuǎn)語(yǔ)音(TTS)的應(yīng)用場(chǎng)景中(如語(yǔ)音助手、語(yǔ)音通知、內(nèi)容播報(bào)等),Java生態(tài)缺少類似Python生態(tài)的Edge?TTS?客戶端庫(kù),不過沒關(guān)系,現(xiàn)在可以通過?UnifiedTTS?提供的?API?來調(diào)用免費(fèi)的?EdgeTTS?能力,本文給大家介紹了SpringBoot集成免費(fèi)的EdgeTTS實(shí)現(xiàn)文本轉(zhuǎn)語(yǔ)音
    2025-10-10
  • Spring @Scheduled注解及工作原理

    Spring @Scheduled注解及工作原理

    Spring的@Scheduled注解用于標(biāo)記定時(shí)任務(wù),無需額外庫(kù),需配置@EnableScheduling,設(shè)置fixedRate、fixedDelay或cron,基于TaskScheduler,默認(rèn)使用線程池,可自定義線程數(shù)及名稱以優(yōu)化性能,本文給大家介紹Spring @Scheduled注解的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2025-06-06
  • Java如何利用return結(jié)束方法調(diào)用

    Java如何利用return結(jié)束方法調(diào)用

    這篇文章主要介紹了Java如何利用return結(jié)束方法調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Spring實(shí)現(xiàn)在非controller中獲取request對(duì)象

    Spring實(shí)現(xiàn)在非controller中獲取request對(duì)象

    這篇文章主要介紹了Spring實(shí)現(xiàn)在非controller中獲取request對(duì)象方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java調(diào)用Web Service的技術(shù)流程實(shí)踐示例

    Java調(diào)用Web Service的技術(shù)流程實(shí)踐示例

    本文詳細(xì)介紹了Java通過JAX-WS調(diào)用Web Service的技術(shù)流程,包括Web Service基礎(chǔ)概念、客戶端調(diào)用流程、關(guān)鍵代碼分析、異常處理、SOAP消息構(gòu)造與解析、配置與部署、測(cè)試與調(diào)試等方面,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Java?properties?和?yml?的區(qū)別解析

    Java?properties?和?yml?的區(qū)別解析

    properties和yml都是Spring?Boot支持的兩種配置文件,它們可以看做Spring?Boot在不同時(shí)期的兩種“產(chǎn)品”,這篇文章主要介紹了Java?properties?和?yml?的區(qū)別,需要的朋友可以參考下
    2023-02-02
  • Spring?Boot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的解決方案

    Spring?Boot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的解決方案

    文章介紹了在SpringBoot中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的幾種方案,并詳細(xì)描述了一個(gè)使用AbstractRoutingDataSource的實(shí)現(xiàn)步驟,感興趣的朋友一起看看吧
    2025-01-01
  • SpringBoot HTTP服務(wù)開發(fā)從入門到部署完整流程

    SpringBoot HTTP服務(wù)開發(fā)從入門到部署完整流程

    本文將基于SpringBoot+Gradle技術(shù)棧,從零開始構(gòu)建一個(gè)簡(jiǎn)單的HTTP服務(wù),逐步實(shí)現(xiàn)從項(xiàng)目初始化、API開發(fā)、業(yè)務(wù)邏輯構(gòu)建到最終部署上線的全流程,感興趣的朋友跟隨小編一起看看吧
    2026-02-02

最新評(píng)論

凤翔县| 镇赉县| 民勤县| 剑川县| 织金县| 合阳县| 陇南市| 蒙阴县| 武川县| 弥渡县| 农安县| 普格县| 沛县| 白水县| 沂南县| 育儿| 重庆市| 绥棱县| 九龙坡区| 克山县| 金塔县| 绥滨县| 许昌县| 广河县| 综艺| 汝阳县| 合水县| 盘山县| 泰州市| 威海市| 菏泽市| 会同县| 电白县| 大埔县| 中江县| 惠东县| 中方县| 耒阳市| 崇义县| 镇江市| 科技|