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

     

  • 相关阅读:
    Web前端的状态管理(State Management)
    使用iScroll实现上拉或者下拉刷新
    实现checkbox组件化(Component)
    HTML5 文件异步上传 — h5uploader.js
    利用javascript和WebGL绘制地球 【翻译】
    利用JS跨域做一个简单的页面访问统计系统
    Java JSON、XML文件/字符串与Bean对象互转解析
    JS实现星级评价
    Spring中@Component注解,@Controller注解详解
    制作滑动条菜单,如何延时处理滑动效果,避免动画卡顿
  • 原文地址:https://www.cnblogs.com/renjianjun/p/10939623.html
Copyright © 2020-2023  润新知