• 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的文件输出展示

     

  • 相关阅读:
    Security 前端页面配置
    使用HttpSession获取用户信息
    开启使用Tonken记住我功能
    基于注解的方式发送和订阅消费消息
    通过Security提供的SecurityContextHolder获取登录用户信息
    RabbitMQ 基于API的方式发送和消费消息
    TypeScript declare Object Array Interface methods All In One
    js get Set the first item All In One
    macOS run VSCode from terminal All In One
    在线 Java 语言编程 All In One
  • 原文地址:https://www.cnblogs.com/renjianjun/p/10939623.html
Copyright © 2020-2023  润新知