itextpdf结合jfinal模版生成pdf文件

1.pom依赖

        <!--pdf生成 start-->
        <!-- jfianl 依赖 -->
        <!-- https://mvnrepository.com/artifact/com.jfinal/jfinal -->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>3.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker   5.iText-Html-Freemarker渲染-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.itextpdf.tool/xmlworker iText-Html渲染-->
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf 6.Flying Saucer-CSS高级特性支持-->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf-itext5 6.Flying Saucer-CSS高级特性支持-->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf-itext5</artifactId>
            <version>9.1.5</version>
        </dependency>

        <!--pdf生成 end-->

2,接口文件

package com.rjj.wlqq.pdf;

import java.io.OutputStream;
import java.util.Map;

/**
 * 生成pdf的接口
 * 生成pdf都需要把一个字符串写成pdf文件输出到指定的地方
 */
public interface PDF {

    /**
     *
     * @param data 输入到模板的数据
     * @param htmlTmp  模版的地址
     * @param out 输出【这里可以是输出到文件中,也可以输出到响应中】
     * @return 输出成功失败
     */
    boolean writeToPDF(Map<String, Object> data, String htmlTmp, OutputStream out);
}

3,基本实现类

package com.rjj.wlqq.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 java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public abstract class BasePDF implements PDF{
    /*字体*/
    private static String FONT = "static/pdf/font/simhei.ttf";

    /**
     * 字体这里设置了默认的,如果使用其他字体需要倒入字体,然后通过这个方法设定字体
     * @param FONT
     */
    public static void setFont(String FONT) {
        BasePDF.FONT = FONT;
    }


    @Override
    public boolean writeToPDF(Map<String, Object> data, String htmlTmp, OutputStream out) {
        String content = templateToString(data, htmlTmp);
        return write(content,out);
    }

    /**
     * 准备生成pdf
     */
    private boolean write(String content, OutputStream out){
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = null;
        try {
            writer = PdfWriter.getInstance(document, out);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        try {
            XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                    new ByteArrayInputStream(content.getBytes()), null, StandardCharsets.UTF_8, fontImp);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        // step 5
        document.close();
        return true;
    }

    /**
     * 要输出的字符串模板
     */
    public abstract String templateToString(Map<String, Object> data, String htmlTmp);
}

4,代理

package com.rjj.wlqq.pdf;

import java.lang.reflect.Proxy;

/**
 *  return Proxy.newProxyInstance(target.getClass().getClassLoader(),
 *                target.getClass().getSuperclass().getInterfaces(),
 *                new InvocationHandler() {
 *                    @Override
 *                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 *                            Object invoke = method.invoke(target, args);
 *                            return invoke;
 *                    }
 *                });
 * @param <T>
 */
public class PDFProxy<T> {
    private T target;

    PDFProxy(T target){
        this.target = target;
    }

    /**
     *   target.getClass().getSuperclass().getInterfaces()这个输出pdf的方法在父类中
     * @return
     */
    public Object getInstance(){
       return Proxy.newProxyInstance(target.getClass().getClassLoader(),
               target.getClass().getSuperclass().getInterfaces(),
               (proxy, method, args) -> method.invoke(target, args));
    }
}

5,工厂方法

package com.rjj.wlqq.pdf;

public class PDFFactory {

    public static PDF getPDF(Class<?> p){
        PDF pdf = null;
        try {
            pdf = (PDF)p.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        PDFProxy<PDF> pdfProxy = new PDFProxy<>(pdf);
        return (PDF)pdfProxy.getInstance();
    }
}

6,jfinal模版实现类

package com.rjj.wlqq.pdf;

import com.jfinal.template.Engine;
import com.jfinal.template.Template;
import org.springframework.util.ResourceUtils;

import java.io.FileNotFoundException;
import java.util.Map;

public class TemplateToPDFJfinal extends BasePDF{
    private static String path;
    private static Engine myEngine;

    /**
     * 这里在加载配置文件的时候就加载就好了,项目中启动时候就设置这个,那么,就会一只存在,直到项目停止
     * @param myEngine 模版引擎
     */
    public static void setEngine(Engine myEngine) {
        TemplateToPDFJfinal.myEngine = myEngine;
    }

    static {
        try {
            path = ResourceUtils.getURL("classpath:templates/pdf/").getPath();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    @Override
    public String templateToString(Map<String, Object> data, String htmlTmp) {
        //这里需要改动,因为创建了,下次可以直接获取
        //Engine myEngine = Engine.create("myEngine");

        if(myEngine == null){
            //自动使用jfinal默认模版引擎
            myEngine = Engine.use();
            System.out.println("模版引擎 == 【 null 】,使用默认的!");
            //throw new RuntimeException("Did not setEngine(Engine myEngine), You must setEngine(Engine myEngine) after start program !!!");
        }

        myEngine.setDevMode(true);
        myEngine.setEncoding("UTF-8");
        //设置模板所在路径
        myEngine.setBaseTemplatePath(path);
        Template template = myEngine.getTemplate(htmlTmp);
        return template.renderToString(data);
    }
}

7,freemarker实模版现类

package com.rjj.wlqq.pdf;

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.util.ResourceUtils;

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

public class TemplateToPDFFreemarker extends BasePDF{
    private static Configuration freemarkerCfg = null;
    private static String path;
    static {
        freemarkerCfg =new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        try {
            path = ResourceUtils.getURL("classpath:templates/pdf/").getPath();
            //freemarker的模板目录,下边两个设置路径方式都可以
            freemarkerCfg.setDirectoryForTemplateLoading(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //path = "/templates/pdf";
        //freemarkerCfg.setClassForTemplateLoading(TemplateToPDFFreemarker.class,"/templates/pdf");
    }

    @Override
    public String templateToString(Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp,"UTF-8");
            //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 "";
    }
}

8,velocity模版实现类

package com.rjj.wlqq.pdf;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

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

public class TemplateToPDFVelocity extends BasePDF{
    private static String path = "templates/pdf/";
    private static VelocityEngine ve = new VelocityEngine();

    static {
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();
    }

    @Override
    public String templateToString(Map<String, Object> data, String htmlTmp) {
        Template t = ve.getTemplate(path + htmlTmp);
        VelocityContext ctx = new VelocityContext(data);
        StringWriter sw = new StringWriter();
        t.merge(ctx, sw);
        return sw.toString();
    }
}

9,测试类

    private static final String DESTJfinal = "target/pdfJfinal.pdf";
    private static final String DESTFreemarker = "target/pdfFreemarker.pdf";
    private static final String DESTVelocity = "target/pdfVelocity.pdf";


    public static void main(String[] args) throws FileNotFoundException {
        Engine myEngine = Engine.create("myEngine");
        TemplateToPDFJfinal.setEngine(myEngine);
        test("templateJfinal2.html", TemplateToPDFJfinal.class,new FileOutputStream(new File(DESTJfinal)));
        //test("templateFreemarker.html",TemplateToPDFFreemarker.class,new FileOutputStream(new File(DESTFreemarker)));
        //test("templateVelocity.html",TemplateToPDFVelocity.class,new FileOutputStream(new File(DESTVelocity)));
    }

    /**
     * 简单写个方法测试 生成pdf
     *
     * @param templateName 模板名称
     * @param pdfClass     使用的是哪个实现类
     */
    private static void test(String templateName, Class<?> pdfClass, OutputStream outputStream) {
        String FONT = "static/pdf/font/simhei.ttf";
        BasePDF.setFont(FONT);
        PDF pdf = PDFFactory.getPDF(pdfClass);
        Map<String, Object> map = new HashMap<>();
        map.put("name", "中国社会主义价值核心观");
        map.put("imgUrl", "/Users/renjianjun/Downloads/我的/斗图/mao.jpg");
        boolean b = pdf.writeToPDF(map, templateName, outputStream);
        System.out.println("输出结果:" + b);
    }

10,java目录结构

 11,所需要的静态文件【字体】需要自己下载

链接: https://pan.baidu.com/s/17Y_h-pSP1HuLK-8-tAskQA  密码: 0n67

 12,html模版文件

 jfinal

<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 /   比如:<meta charset="UTF-8" /> -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>jfinal模板使用</title>
    <style>
        body {
            /*如果使用的字体没有,那么中文不会显示*/
            font-family: SimHei,serif;
        }

        .pos {
            position: absolute;
            left: 200px;
            top: 5px;
            width: 200px;
            font-size: 10px;
        }

        .table-one {
            width: 700px;
            text-align: center;
            border-collapse: collapse;
        }

        /*细调试*/
        .title-big{
            font-size: 20px;
        }
        .title-middle{
            font-size: 16px;
        }
        .title-small{
            font-size: 13.33px;
        }
        .red{
            background-color: #E11B22;
        }
        .black{
            background-color: black;
            color: white;
        }
    </style>
</head>
<body>
<div class="pos">
    <!--图片-->
    <table class="table-one">
        <tr>
            <td colspan="5">
                <img alt="tp" style=" 153px;margin-left: 300px" src="#(imgUrl)"/> <!--图片路径自己写,根据自己的实际路径写-->
            </td>
        </tr>
        <tr>
            <td colspan="5">
                jfinal模版使用#取值   #(name)
            </td>
        </tr>
    </table>

    <table border="1" class="table-one">
        <tr>
            <td colspan="5" class="title-big black">20px标题</td>
        </tr>
        <tr class="title-middle">
            <td class="red" rowspan="3">
                <table>
                    <tr><td>红色</td></tr>
                    <tr><td>红色</td></tr>
                    <tr><td>红色</td></tr>
                </table>
            </td>
            <td colspan="4">数据</td>
        </tr>
        <tr class="title-middle">
            <!-- <td class="red">红色</td>-->
            <td colspan="4">数据</td>
        </tr>
        <tr class="title-middle">
            <!-- <td class="red">红色</td>-->
            <td colspan="4">数据</td>
        </tr>
        <tr class="title-middle black">
            <td colspan="5">16px二级标题</td>
        </tr>
        <tr class="title-small">
            <td>13px标题</td>
            <td>13px数据</td>
            <td>13px数据</td>
            <td>13px数据</td>
            <td>13px数据</td>
        </tr>
        <tr class="title-small">
            <td>13px标题</td>
            <td>13px数据</td>
            <td>13px数据</td>
            <td>13px数据</td>
            <td>13px数据</td>
        </tr>
        <tr class="title-small">
            <td>13px标题</td>
            <td>13px数据</td>
            <td colspan="2">13px数据</td>
            <td>13px数据</td>
        </tr>
        <tr>
            <td class="title-middle">16px标题</td>
            <td colspan="4" class="title-small">13px数据</td>
        </tr>
        <tr>
            <td class="title-middle">16px标题</td>
            <td colspan="4" class="title-small">13px数据</td>
        </tr>
        <tr>
            <td class="title-middle">16px标题</td>
            <td colspan="4" class="title-small">13px数据</td>
        </tr>
        <tr>
            <td class="title-middle">16px标题</td>
            <td colspan="4" class="title-small">13px数据</td>
        </tr>
        <tr>
            <td class="title-middle">16px标题</td>
            <td colspan="4" class="title-small">13px数据</td>
        </tr>
    </table>
</div>
</body>
</html>

freemarker

<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 /   比如:<meta charset="UTF-8" /> -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>jfinal模板使用</title>
    <style>
    body{
    font-family:SimHei;
    }
    .color{
    color: green;
    }
    .pos{
    position:absolute;
    left:200px;
    top:5px;
    width: 200px;
    font-size: 10px;
    }
    </style>
</head>
<body>
<div class="blue pos">
    你好,${name} freemarker
</div>
</body>
</html>

volecity

<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 /   比如:<meta charset="UTF-8" /> -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>jfinal模板使用</title>
    <style>
    body{
    font-family:SimHei;
    }
    .color{
    color: green;
    }
    .pos{
    position:absolute;
    left:200px;
    top:5px;
    width: 200px;
    font-size: 14px;
    }
    </style>
</head>
<body>
<div class="blue pos">
    你好,${name} velocity
</div>
</body>
</html>

13,jfinal的文件输出展示

 

原文地址:https://www.cnblogs.com/renjianjun/p/10939623.html