SpringBoot+Freemark根据html模板动态导出PDF

1、引入maven

导出pdf的一些必要jar包
		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
 		<dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <version>2.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

2、两个工具类

GeneratePDF.java

注意1:工具类中的变量templates 表示在resource建个templates目录, test.html表示生成pdf的模板,water.png表示pdf的水印,这里我没加水印,如果要加水印,只用把下面我注释的三行代码放开就行。
注意2: test.html和water.png都放在templates目录
package cn.yx.zg.utils.pdf;

import cn.hutool.core.io.resource.ClassPathResource;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfPageEvent;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;

import java.io.*;
import java.nio.charset.Charset;

public class GeneratePDF {
    public final static String TEMPLATE_DIRECTORY_INSPECTION = "/templates/";
    public final static String TEMPLATE_NAME_INSPECTION = "test.html";
    public final static String TEMPLATE_WATER_INSPECTION = "water.png";

    /**
     * HTML 转 PDF
     *
     * @param content html内容
     * @param outPath 输出pdf路径
     * @return 是否创建成功
     */
    public static boolean html2Pdf(String content, String outPath) throws FileNotFoundException {
        return html2Pdf(content, new FileOutputStream(outPath));
    }

    public static boolean html2Pdf(String content, OutputStream out) {
        try {
            Document document = new Document(); //创建一个标准的A4纸文档
            PdfWriter writer = PdfWriter.getInstance(document, out);//书写器与ducument文档关联
            document.open();//打开文档
//            addWaterMark(writer);
            writer.setPageEvent(new PdfPageEvent() {
                @Override
                public void onOpenDocument(PdfWriter pdfWriter, Document document) {

                }

                @Override
                public void onStartPage(PdfWriter pdfWriter, Document document) {
//                    addWaterMark(pdfWriter);
                }

                @Override
                public void onEndPage(PdfWriter pdfWriter, Document document) {

                }

                @Override
                public void onCloseDocument(PdfWriter pdfWriter, Document document) {

                }

                @Override
                public void onParagraph(PdfWriter pdfWriter, Document document, float v) {

                }

                @Override
                public void onParagraphEnd(PdfWriter pdfWriter, Document document, float v) {

                }

                @Override
                public void onChapter(PdfWriter pdfWriter, Document document, float v, Paragraph paragraph) {

                }

                @Override
                public void onChapterEnd(PdfWriter pdfWriter, Document document, float v) {

                }

                @Override
                public void onSection(PdfWriter pdfWriter, Document document, float v, int i, Paragraph paragraph) {

                }

                @Override
                public void onSectionEnd(PdfWriter pdfWriter, Document document, float v) {

                }

                @Override
                public void onGenericTag(PdfWriter pdfWriter, Document document, Rectangle rectangle, String s) {

                }
            });

            XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"));

            document.close();//关闭文档
        } catch (Exception e) {
            System.out.println("生成模板内容失败" + e.fillInStackTrace());
            return false;
        }
        return true;
    }

    /**
     * HTML 转 PDF
     *
     * @param content html内容
     * @return PDF字节数组
     */
    public static byte[] html2Pdf(String content) {
        ByteArrayOutputStream outputStream = null;
        try {
            Document document = new Document();
            outputStream = new ByteArrayOutputStream();
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);
            document.open();
            XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"));
            document.close();
        } catch (Exception e) {
            System.out.println("------生成pdf失败-------");
        }
        return outputStream.toByteArray();
    }

    public static void addWaterMark(PdfWriter writer) {
        Image image = null;
        try {
            ClassPathResource resource = new ClassPathResource(TEMPLATE_DIRECTORY_INSPECTION + TEMPLATE_WATER_INSPECTION);
            image = Image.getInstance(resource.getUrl());
            // 加入水印
            PdfContentByte waterMar = writer.getDirectContentUnder();
            // 开始设置水印
            waterMar.beginText();
            // 设置水印透明度
            PdfGState gs = new PdfGState();
            // 设置笔触字体不透明度为0.4f
            gs.setStrokeOpacity(0.2f);
            gs.setFillOpacity(0.2f);
            // 设置等比缩放
            image.scalePercent(25);// 依照比例缩放
            // image.scaleAbsolute(200,100);//自定义大小
            image.setRotation(45f);
            // 设置透明度
            waterMar.setGState(gs);
            // 添加水印图片
//                waterMar.addImage(image);
            image.setAbsolutePosition(110f, 130f);

            //结束设置
            waterMar.endText();
            waterMar.stroke();
            try {
                waterMar.addImage(image);
            } catch (DocumentException e) {
                e.printStackTrace();
            } finally {
                waterMar = null;
                gs = null;
            }
        } catch (BadElementException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

GetHtmlContent.java

package cn.yx.zg.utils.pdf;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;

public class GetHtmlContent {
    /**
     * 获取模板内容
     *
     * @param templateDirectory 模板文件夹
     * @param templateName      模板文件名
     * @param paramMap          模板参数
     * @return
     * @throws Exception
     */
    public static String getTemplateContent(String templateDirectory, String templateName, Map<String, Object> paramMap) throws Exception {
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);//不兼容配置
        try {
            configuration.setTemplateLoader(new ClassTemplateLoader(GetHtmlContent.class, templateDirectory));
//            configuration.setDirectoryForTemplateLoading(new File(templateDirectory));//加载模板
        } catch (Exception e) {
            e.printStackTrace();
        }

        Writer out = new StringWriter();
        Template template = configuration.getTemplate(templateName, "UTF-8");//缓存
        template.process(paramMap, out);
        out.flush();
        out.close();
        return out.toString();
    }

}

2.1 test.html模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>测试表单</title>
    <style>
      body {
        font-family: SimSun;
      }

      .f-s-1 {
        font-size: 12px;
      }

      .table-main {
        width: 100%;
        border-collapse: collapse;
        border-right: 1px solid rgba(0, 0, 0, 0.7);
        border-bottom: 1px solid rgba(0, 0, 0, 0.7);
        margin-bottom: 30px;
      }

      .table-main td {
        border-left: 1px solid rgba(0, 0, 0, 0.7);
        border-top: 1px solid rgba(0, 0, 0, 0.7);
        padding: 4px;
      }

      .th1 {
        font-weight: bold;
        background-color: #d7d7d7;
      }

      .th2 {
        background-color: #f1f1f1;
      }
      .text-center{
        text-align: center;
      }
    </style>
</head>
<body>


<h5 style="margin-top: 30px">学生列表</h5>
<table class="table-main f-s-1">
    <thead>
    <tr>
        <td class="th1" style="width: 28%">姓名</td>
        <td class="th1 text-center" style="width: 12%">性别</td>
        <td class="th1 text-center" style="width: 12%">年龄</td>
        <td class="th1 text-center" style="width: 12%">地址</td>
    </tr>
    </thead>
    <tbody>
    <#list resultItems as item>
    <tr>
        <td class="text-center">${item.name}</td>
        <td class="text-center">${item.sex}</td>
        <td class="text-center">${item.age}</td>
        <td class="text-center">${item.address}</td>
    </tr>
    </#list>
    </tbody>
</table>


</body>
</html>

2.2 test.html模板中的Freemark语法

1、 <#list resultItems as item> 表示遍历后台返回的resultItems
2、下面判断age字段是否为空。
<#if age?? >
    存在
    <#else >
        不存在
</#if>
<#--判断数据是否存在,存在则则遍历-->
<#if resultItems??>
    <#list resultItems as item>
        ${item}
    </#list>
</#if>

3、controller导出pdf

注意: 代码中设置的变量要和html模板中的变量一致。
package cn.yx.zg.controller;

import cn.yx.zg.utils.pdf.GeneratePDF;
import cn.yx.zg.utils.pdf.GetHtmlContent;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class TestExportPdfController {
    @RequestMapping("/test")
    public void test(HttpServletResponse response) throws Exception {
        Map<String, Object> paramMap = new HashMap<>();

        List<Map<String, Object>> resultItems = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Map<String, Object> items = new HashMap<>();
            items.put("name", "张三" + i);
            items.put("age", "18" + i);
            items.put("sex", "男" + i);
            items.put("address", "河南" + i);
            resultItems.add(items);
        }
        paramMap.put("resultItems", resultItems);

        String destFileName = "测试表单.pdf";
        destFileName = new String(destFileName.getBytes(), StandardCharsets.ISO_8859_1);
        OutputStream out;
        //设置响应
        response.setHeader("Content-Disposition", "attachment;filename=" + destFileName);
        response.setContentType("application/pdf");
        out = response.getOutputStream();

        String templateContent = GetHtmlContent.getTemplateContent(GeneratePDF.TEMPLATE_DIRECTORY_INSPECTION, GeneratePDF.TEMPLATE_NAME_INSPECTION, paramMap);
        GeneratePDF.html2Pdf(templateContent, out);
        out.flush();
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北漂IT民工_程序员_ZG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值