springboot+itextpdf 使用html模板打印PDF 有水印效果

首先是引入POM文件:

<dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>


        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

        <!-- flying saucer,支持对CSS高级特性的解析 -->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.6</version>
        </dependency>

编写PDF工具类:

package com.example.test222;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Component
public class PdfUtil {

    /**
     * 打印pdf方法
     *
     * @param data         模板中需要填充的数据
     * @param templateName 模板名称
     * @param response     响应对象 通过流直接返回到前端进行展示
     * @throws Exception 这个异常可以自己处理
     */
    public void freeMarkerRender(Map<String, Object> data, String templateName, HttpServletResponse response) throws Exception {
        // 设置返回字符集、contentType
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/pdf");
        ServletOutputStream outputStream = response.getOutputStream();
        // 获取模板文件
        Configuration configuration = new Configuration(Configuration.getVersion());
        configuration.setClassForTemplateLoading(this.getClass(), "/static/pdf");
        Template template = configuration.getTemplate(templateName);
        StringWriter out = new StringWriter();
        // 合并模板跟数据
        template.process(data, out);
        // htmlData 模板字符流
        String htmlData = out.toString();
        // 设置文档格式,数字边距
        Document document = new Document(PageSize.A4);
        PdfWriter writer = PdfWriter.getInstance(document, outputStream);
        // 添加页码
        writer.setPageEvent(new PdfReportM1HeaderFooter());
        writer.setPageEvent(new PdfPageHelper());
        // 打开文档
        document.open();
        // HTML 转成pdf
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(htmlData.getBytes()), StandardCharsets.UTF_8, new MyFontsProvider(12));
        // 关闭文档
        document.close();
        outputStream.flush();
    }


    static class PdfPageHelper extends PdfPageEventHelper {
        @Override
        public void onOpenDocument(PdfWriter writer, Document document) {
            super.onOpenDocument(writer, document);
            writer.getDirectContent().createTemplate(30, 16);
        }

        @Override
        public void onStartPage(PdfWriter writer, Document document) {
            super.onStartPage(writer, document);
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            BaseFont bf = null;
            try {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            } catch (Exception e) {
                e.printStackTrace();
            }
//            extracted(writer, document, bf);
            // 添加水印
            addWaterMark(writer, bf);
        }

//        private void extracted(PdfWriter writer, Document document, BaseFont bf) {
//            PdfContentByte cb = writer.getDirectContent();
//            cb.saveState();
//            cb.beginText();
//
//            cb.setFontAndSize(bf, 10);
//            float x = document.top(-20);
//            // 左
//            cb.showTextAligned(PdfContentByte.ALIGN_LEFT, "顶部-左", document.left(), x, 0);
//            // 中
//            cb.showTextAligned(PdfContentByte.ALIGN_CENTER, writer.getPageNumber() + " page", (document.right() + document.left()) / 2, x, 0);
//            // 右
//            cb.showTextAligned(PdfContentByte.ALIGN_RIGHT, "顶部-右", document.right(), x, 0);
//            // Footer
//            float y = document.bottom(-20);
//            // 左
//            cb.showTextAligned(PdfContentByte.ALIGN_LEFT, "底部-左", document.left(), y, 0);
//            // 中
//            cb.showTextAligned(PdfContentByte.ALIGN_CENTER, writer.getPageNumber() + " page", (document.right() + document.left()) / 2, y, 0);
//            // 右
//            cb.showTextAligned(PdfContentByte.ALIGN_RIGHT, "底部-右", document.right(), y, 0);
//            cb.endText();
//            cb.restoreState();
//        }

        /**
         * 添加水印
         */
        private void addWaterMark(PdfWriter writer, BaseFont bf) {
            PdfContentByte cb = writer.getDirectContent();
            cb.saveState();
            cb.beginText();
            cb.setColorFill(BaseColor.GRAY);
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.3f);
            cb.setGState(gs);
            cb.setFontAndSize(bf, 100);
            // rotation指倾斜度 可以根据自己的需求做调整 不需要倾斜的话可以调整为0
            cb.showTextAligned(Element.ALIGN_MIDDLE, "总装一线", 100, 450, 0);
            cb.endText();
            cb.restoreState();
        }
    }

    static class MyFontsProvider extends XMLWorkerFontProvider {

        private int fontSize;

        public MyFontsProvider(int fontSize) {
            this.fontSize = fontSize;
        }

        @Override
        public Font getFont(final String fontName, final String encoding, final boolean embedded, final float size, final int style, final BaseColor color) {
            BaseFont bf = null;
            try {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            } catch (DocumentException | IOException e) {
                e.printStackTrace();
            }
            Font font = null;
            if (fontSize != 0) {
                font = new Font(bf, fontSize, style, color);
            } else {
                font = new Font(bf, size, style, color);
            }
            font.setColor(color);
            return font;
        }

        public int getFontSize() {
            return fontSize;
        }

        public void setFontSize(int fontSize) {
            this.fontSize = fontSize;
        }

    }

    static class PdfReportM1HeaderFooter extends PdfPageEventHelper {

        /**
         * 页眉
         */
        public String header = "页眉";

        /**
         * 文档字体大小,页脚页眉最好和文本大小一致
         */
        public int presentFontSize = 12;

        // 模板
        public PdfTemplate total;

        private BaseFont bf = null;

        public PdfReportM1HeaderFooter() {

        }

        /**
         * 文档打开时创建模板
         */
        public void onOpenDocument(PdfWriter writer, Document document) {
            total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
        }

        /**
         * 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
         *
         * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
         */
        public void onEndPage(PdfWriter writer, Document document) {
            Font fontDetail = null;
            try {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
                fontDetail = new Font(bf, presentFontSize, Font.NORMAL);
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 1.写入页眉
//            ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0);
            // 2.写入前半部分的 第 X页/共
            int pageS = writer.getPageNumber();
            String foot1 = "第 " + pageS + " 页 /共";
            Phrase footer = new Phrase(foot1, fontDetail);
            // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
            float len = bf.getWidthPoint(foot1, presentFontSize);
            // 4.拿到当前的PdfContentByte
            PdfContentByte cb = writer.getDirectContent();
            // 5.写入页脚
            ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);

            cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20);

        }

        /**
         * 关闭文档时,替换模板,完成整个页眉页脚组件
         */
        public void onCloseDocument(PdfWriter writer, Document document) {
            // 关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
            total.beginText();
            total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
            String foot2 = " " + (writer.getPageNumber()) + " 页";
            total.showText(foot2);// 模版显示的内容
            total.endText();
            total.closePath();
        }
    }

}

编写一个html模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{font-family:SimSun;}
        .title{align-content: center;text-align: center;}
        .signature{float:right }
        .myDiv{
            opacity: 0.5%;
        }

    </style>
</head>
<body>
<div>
    <h1 class="title">pdfTest</h1>
    <h4 class="title"> </h4>
    <div class="myDiv" style="height: 800px;">
        <span>当前时间: ${date_time} </span>
    </div>
    <div class="signature">日期:${date}</div>
    <div class="myDiv" style="height: 800px;">
        <span>当前时间: ${date_time} </span>
    </div>
    <div class="signature">日期:${date}</div>
</div>
</body>
</html>

资源路径:
在这里插入图片描述

编写接口前端访问,直接弹出pdf页面:

package com.example.test222;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/test")
public class TestController {

    @Autowired
    private PdfUtil pdfUtil;

    @RequestMapping("/print")
    public void print(HttpServletResponse response) throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("date_time", "tiem");
        map.put("date", "123");
        pdfUtil.freeMarkerRender(map, "test.html", response);
    }

}

打印效果如下:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值