Java 实现 生成PDF -(电子凭证生成原理分析)

需求

实现:电子合同,电子回单、电子对账单等

需求插件(依赖)
1.基本插件
itextpdf
功能很强大,差不多可以实现PDF所有的功能。(如果你想实现有特殊需求的,如表单、PDF模板、水印等等都可以),需要特别注意的是它不支持中文,因此需要给它指定字体。
2.辅助插件(itextpdf 扩展插件)
为什么要用辅助插件呢,因为只需要itextpdf 基本功能就可以了,辅助插件可以帮你更少的代码实现功能。
2-1、xmlworker 根据XML生成PDF。
2-2、freemarker 根据XML 进行标记 进行填充。
2-3、flying-saucer-pdf 与 flying-saucer-pdf-itext5 根据XML里的图片等资源加载出来并生成PDF(场景:水印、印章等)

POM 文件

<dependencies>
        <!--        PDF操作插件-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>
        <!--        利用HTML 生成PDF-->
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>
        <!--        利用HTML 标记生成PDF-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.19</version>
        </dependency>
        <!--        利用HTML 支持带图片生成PDF-->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf-itext5</artifactId>
            <version>9.1.5</version>
        </dependency>
    </dependencies>

为了获取文件资源,先准备一个工具类

package util;

import java.io.File;

public class PathUtil {

    public static String getCurrentPath() {
        Class<?> caller = getCaller();
        if (caller == null) {
            caller = util.PathUtil.class;
        }
        return getCurrentPath(caller);
    }

    public static Class<?> getCaller() {
        StackTraceElement[] stack = (new Throwable()).getStackTrace();
        if (stack.length < 3) {
            return util.PathUtil.class;
        }
        String className = stack[2].getClassName();
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getCurrentPath(Class<?> cls) {
        String path = cls.getProtectionDomain().getCodeSource().getLocation().getPath();
        path = path.replaceFirst("file:/", "");
        path = path.replaceAll("!/", "");
        if (path.lastIndexOf(File.separator) >= 0) {
            path = path.substring(0, path.lastIndexOf(File.separator));
        }
        if ("/".equalsIgnoreCase(path.substring(0, 1))) {
            String osName = System.getProperty("os.name").toLowerCase();
            if (osName.contains("window")) {
                path = path.substring(1);
            }
        }
        return path;
    }

}

一、itextpdf 生成PDF

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class JavaToPdf {
    private static final String DEST = "target/Test.pdf";
    public static void main(String[] args) throws FileNotFoundException, DocumentException {
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
        document.open();
        Font f1 = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        document.add(new Paragraph("Test Create PDF", f1));
        document.close();
        writer.close();
    }
}

Java 实现 生成PDF  -(电子凭证生成原理分析)

Java 实现 生成PDF  -(电子凭证生成原理分析)
二、itextpdf 生成的PDF 支持中文

准备一个中文字体放到资源文件夹(resources)下
Java 实现 生成PDF  -(电子凭证生成原理分析)
代码

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class JavaToPdfCN {
    private static final String DEST = "target/Test.pdf";
    private static final String FONT = "simhei.ttf";

    public static void main(String[] args) throws FileNotFoundException, DocumentException {
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
        document.open();
        Font f1 = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        document.add(new Paragraph("Test Create PDF 支持中文", f1));
        document.close();
        writer.close();
    }
}

Java 实现 生成PDF  -(电子凭证生成原理分析)
三、通过HTML生成PDF
准备文件template.html 并放在资源目录下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family:SimHei;
        }
        .red{
            color: red;
        }
    </style>
</head>
<body>
<div class="red">
    这是通过HTML 生成的PDF
</div>
</body>
</html>

Java 实现 生成PDF  -(电子凭证生成原理分析)

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import util.PathUtil;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;

public class JavaToPdfHtml {
    private static final String DEST = "target/HTMLtoPdf.pdf";
    private static final String HTML = PathUtil.getCurrentPath()+"/template.html";
    private static final String FONT = "simhei.ttf";

    public static void main(String[] args) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new FileInputStream(HTML), null, Charset.forName("UTF-8"), fontImp);
        // step 5
        document.close();
    }
}

Java 实现 生成PDF  -(电子凭证生成原理分析)
Java 实现 生成PDF  -(电子凭证生成原理分析)

三、利用HTML作为生成PDF的模板 生成PDF
准备
在资源目录下创建HTML:template_freemarker.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family:SimHei;
        }
        .blue{
            color: blue;
        }
        .pos{
            position:absolute;
            left:100px;
            top:150px
        }
    </style>
</head>
<body>
<div class="blue pos">
    账户:${name}. 你的账款余额:${mm}
</div>
</body>
</html>

Java 实现 生成PDF  -(电子凭证生成原理分析)

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;

import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import freemarker.template.Template;
import util.PathUtil;

public class JavaToPdfHtmlFreeMarker {
    private static final String DEST = "target/HTMLModelToPdf.pdf";
    private static final String HTML = "template_freemarker.html";
    private static final String FONT = "simhei.ttf";

    private static Configuration freemarkerCfg = null;
    static {
        freemarkerCfg =new Configuration();
        //freemarker的模板目录
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(PathUtil.getCurrentPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void createPdf(String content,String dest) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
        // step 5
        document.close();

    }

    /**
     * freemarker渲染html
     */
    public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            template.setEncoding("UTF-8");
            // 合并数据模型与模板
            template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    public static void main(String[] args) throws IOException, DocumentException {
        Map<String,Object> data = new HashMap();
        data.put("name","张三");
        data.put("mm","100");
        String content = JavaToPdfHtmlFreeMarker.freeMarkerRender(data,HTML);
        JavaToPdfHtmlFreeMarker.createPdf(content,DEST);
    }
}

Java 实现 生成PDF  -(电子凭证生成原理分析)
Java 实现 生成PDF  -(电子凭证生成原理分析)
三、利用HTML作为生成PDF的模板 生成PDF (升级 支持HTML里的图片资源显示)
准备
Java 实现 生成PDF  -(电子凭证生成原理分析)
代码


import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;
import flyingsaucer.JavaToPdfHtmlFreeMarker;
import util.PathUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class JavaToPdfHtmlFreeMarkerForImage {
    private static final String DEST = "target/HTMLModelToPdfForImage.pdf";
    private static final String HTML = "template_freemarker_fs.html";
    private static final String FONT = "simhei.ttf";
    private static final String LOGO_PATH = "file://logo.png";

    private static Configuration freemarkerCfg = null;

    static {
        freemarkerCfg =new Configuration();
        //freemarker的模板目录
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(PathUtil.getCurrentPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * freemarker渲染html
     */
    public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            template.setEncoding("UTF-8");
            // 合并数据模型与模板
            template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    public static void createPdf(String content,String dest) throws IOException, DocumentException, com.lowagie.text.DocumentException {
        ITextRenderer render = new ITextRenderer();
        ITextFontResolver fontResolver = render.getFontResolver();
        fontResolver.addFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        // 解析html生成pdf
        render.setDocumentFromString(content);
        //解决图片相对路径的问题
        render.getSharedContext().setBaseURL(LOGO_PATH);
        render.layout();
        render.createPDF(new FileOutputStream(dest));
    }

    public static void main(String[] args) throws DocumentException, com.lowagie.text.DocumentException, IOException {
        Map<String,Object> data = new HashMap();
        data.put("name","显示图片测试");
        String content = JavaToPdfHtmlFreeMarker.freeMarkerRender(data,HTML);
        JavaToPdfHtmlFreeMarker.createPdf(content,DEST);
    }

参考实现

上一篇:java使用itextpdf插件生成pdf


下一篇:html模板结合itextpdf生成pdf文档--demo