Java html模板生成PDF

1、Maven依赖

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

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.0.3</version>
        </dependency>

2、pdfTemplate.ftl模板

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8"></meta>
    <style type="text/css">
        body {
            font-family: SimSun;
        }
        @page{size:A3 }
        .pianyi{
            display:block;
            font-family:SimSun;
            padding-left:15px;
            padding-right:15px;
            -webkit-margin-after:16px;
            -webkit-margin-before:16px;
            -webkit-margin-end:0px;
            -webkit-margin-start:0px;
        }
        .textSpan {
            padding-left: 15px;
            padding-right: 15px;
            line-height: 27px;
        }

    </style>
</head>
<body>
<h3 style="text-align: center;">电子授权书</h3>
<p class="pianyi">被授权人名称</p>
<span class="textSpan">授权人(申请人)姓名: ${name}</span><br></br>
<span class="textSpan">身份证号: ${idCardNo}</span><br></br>
<span class="textSpan">授权协议生效日期: ${dateD} </span><br></br>
<br/>
<div style="word-wrap: break-word;word-break: break-all;overflow: hidden; ">
    ${content}
</div>
<div style="padding-left:15px;padding-right:15px;">签名处:</div>
</body>
</html>

3、创建GeneratePdf类

package com.wap.common;

import com.itextpdf.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 生成Pdf
 * Created by dgl on 2018/8/6.
 */
public class GeneratePdf implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(GeneratePdf.class);

    private String webPath; //= PathUtil.getPath();//web根目录
    /**
     * 指定FreeMarker模板文件的位置
     */
    private String templatePath;

    /**
     * freeMarker模板文件名称
     */
    private static String templateFileName = "pdfTemplate.ftl";

    /**
     * 图片路径 —— 默认是classpath下面的images文件夹
     */
    private static String imagePath = "/upload/";

    /**
     * 指定编码
     */
    private static String encoding = "UTF-8";

    /**
     * 字体   [宋体][simsun.ttc]   [黑体][simhei.ttf]
     */
    private String font;

    /**
     * 需要传入的数据
     */
    private Map<String, Object> dateMap;

    /**
     * 申请单号
     */
    private String applyFromCode;

    //上传的目录
    /*private static String directory;*/

    public GeneratePdf() {
    }

    public GeneratePdf(Map<String, Object> dateMap, String applyFromCode, String webPath) {
        this.dateMap = dateMap;
        this.applyFromCode = applyFromCode;
        this.webPath = webPath;
        this.templatePath = webPath + "/uf/template/";
        this.font = templatePath + "/simsun/simsun.ttc";
    }


    /**
     * 创建pdf
     *
     * @param data          变量数据
     * @param applyFromCode 新pdf地址 (一个单号只能有一个PDF文件,所以就直接用申请单号来命名)
     * @throws Exception
     */
    public Map<String, Object> createPdf(Map<String, Object> data, String applyFromCode) {
        Map<String, Object> map = new HashMap<>();
        String message = "";
        String detail = "";
        Boolean status = true;
        String code = "200";
        try {
            //创建文件
            //生成的pdf文件路径
            String newPdfPath = webPath + imagePath + applyFromCode + ".pdf";
//            String newPdfPath = webPath + Setting.APPLY_FROM_PDF_PATH + "/" + applyFromCode + ".pdf";
            File file = new File(newPdfPath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            FileOutputStream out = new FileOutputStream(file);
            GeneratePdf pdf = new GeneratePdf();
            pdf.createPDF(data, out);
            message = "创建成功";
            //创建完成后的pdf文件所在地址
            detail = newPdfPath;
            logger.info("创建基础PDF完成");
            //线程休息
            Thread.sleep(1000);
            out.close();
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
            message = "创建pdf文件错误失败";
            status = false;
            code = "5005";
            detail = "";
            logger.error("创建pdf文件错误" + e.getMessage());
        }
        map.put("status", status);
        map.put("message", message);
        map.put("detail", detail);
        map.put("code", code);
        return map;
    }

    /**
     * 根据模板生成pdf
     *
     * @param data 传入到freemarker模板里的数据
     * @param out  生成的pdf文件流
     */
    public void createPDF(Object data, OutputStream out) throws Exception {
        // 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
        Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        // 指定FreeMarker模板文件的位置
        ITextRenderer renderer = new ITextRenderer();
        try {
            cfg.setDirectoryForTemplateLoading(new File(templatePath));

            // 设置 css中 的字体样式(暂时仅支持宋体和黑体)
            renderer.getFontResolver().addFont(font, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            // 设置模板的编码格式
            cfg.setEncoding(Locale.CHINA, encoding);
            // 获取模板文件 template.ftl
            Template template = cfg.getTemplate(templateFileName, encoding);
            StringWriter writer = new StringWriter();
            // 将数据输出到html中
            template.process(data, writer);
            writer.flush();
            String html = writer.toString();

            // 把html代码传入渲染器中
            renderer.setDocumentFromString(html);
            // 解决图片的相对路径问题 ##必须在设置document后再设置图片路径,不然不起作用
            // 如果使用绝对路径依然有问题,可以在路径前面加"file:/"
            renderer.layout();
            renderer.createPDF(out, false);
            renderer.finishPDF();
            out.close();
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }

    @Override
    public void run() {
        logger.info("开始异步生成PDF文件");
        createPdf(dateMap, applyFromCode);
        logger.info("异步生成PDF文件完成");
    }

    public String getApplyFromCode() {
        return applyFromCode;
    }

    public void setApplyFromCode(String applyFromCode) {
        this.applyFromCode = applyFromCode;
    }
}

4、方法调用

/***
     * Pdf sftp上传服务器
     * @param name 申请人名字
     * @param idCardNo 申请人身份证号
     * @param dateD 申请时间
     * @param content 内容说明
     * @param applyFromCode 申请单号
     * @paramdirectory 服务器存储路径
     */
    public static void printPdf(String webPath, String name, String idCardNo, String dateD, String content, String applyFromCode) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("name", name);
        map.put("idCardNo", idCardNo);
        map.put("dateD", dateD);
        map.put("content", content);

        GeneratePdf s = new GeneratePdf(map, applyFromCode, webPath);
        s.run();
    }
原文地址:https://www.cnblogs.com/hanmian4511/p/10876571.html