首页 > 软件编程 > java > SpringBoot HTML转PDF

SpringBoot使用iText7实现将HTML转成PDF并添加页眉页脚水印

作者:从乌托邦醒来

这篇文章主要为大家详细介绍了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; * @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); // 统一设置页眉 String header = "我是页眉"; Header headerHandler = new Header(header); pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler); // 统一设置页脚 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触发写操作,此时才会触发已经注册的事件处理器 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;
            // 在页面上循环绘制水印文字
            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;">
<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的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
  • 盘点SpringBoot中@Async注解的遇到的坑点及解决办法
    盘点SpringBoot中@Async注解的遇到的坑点及解决办法
    2024-03-03
  • SpringBoot使用RestTemplate实现HTTP请求详解
    SpringBoot使用RestTemplate实现HTTP请求详解
    2024-03-03
  • Mybatisplus实现JSON处理器的示例代码
    Mybatisplus实现JSON处理器的示例代码
    2024-03-03
  • 哈希表在算法题目中的实际应用详解(Java)
    哈希表在算法题目中的实际应用详解(Java)
    2024-03-03
  • 全方位解读JDK和JRE的区别及联系
    全方位解读JDK和JRE的区别及联系
    2024-03-03
  • 你知道Tomcat安装之前为什么要安装JDK
    你知道Tomcat安装之前为什么要安装JDK
    2024-03-03
  • SpringBoot集成Solr实现全文检索功能
    SpringBoot集成Solr实现全文检索功能
    2024-03-03
  • JAVA 拷贝文件的几种方式小结
    JAVA 拷贝文件的几种方式小结
    2024-03-03
  • 美国设下计谋,用娘炮文化重塑日本,已影响至中国
    美国设下计谋,用娘炮文化重塑日本,已影响至中国
    2021-11-19
  • 时空伴随者是什么意思?时空伴随者介绍
    时空伴随者是什么意思?时空伴随者介绍
    2021-11-09
  • 工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    2021-11-05
  • 2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2021-10-26
  • 电脑版 - 返回首页

    2006-2024 脚本之家 JB51.Net , All Rights Reserved.
    苏ICP备14036222号