当前位置: 代码网 > it编程>编程语言>Java > java使用freemarker模板生成html再转为pdf

java使用freemarker模板生成html再转为pdf

2025年04月07日 Java 我要评论
1.freemarker模板生成html添加maven依赖在pom.xml文件中添加以下依赖:<dependency> <groupid>org.springframew

1.freemarker模板生成html

添加maven依赖

在pom.xml文件中添加以下依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-freemarker</artifactid>
</dependency>

创建freemarker模板

新建一个html文件,例如table.ftl,然后在其中编写html模板,包括表格的头部、内容和尾部等部分。具体可以参考下面这个例子:

<table border="1">
    <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>age</th>
        </tr>
    </thead>
    <tbody>
    <#list users as user>
        <tr>
            <td>${user.id}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
        </tr>
    </#list>
    </tbody>
</table>

上面的模板中使用了freemarker的指令语法来实现动态生成表格内容,包括使用<#list>标签来遍历用户列表,并使用${}语法来输出用户信息。

创建controller方法

在controller中编写一个方法来获取用户列表,然后渲染上面的模板并返回html内容。示例代码如下:

@controller
public class usercontroller {
    @getmapping("/users")
    public string userlist(model model) {
        list<user> users = new arraylist<>();
        users.add(new user(1, "tom", 18));
        users.add(new user(2, "jerry", 20));
        users.add(new user(3, "john", 22));
        model.addattribute("users", users);
        return "table";
    }
}

上面的方法使用@getmapping注解来处理请求,然后创建一个用户列表,并将其添加到模型中。最后返回table字符串,代表要使用的html模板文件。

运行项目

运行spring boot应用程序,然后使用浏览器访问http://localhost:8080/users,即可看到动态生成的html表格。

注意:上面的例子仅供参考,实际应用中需要根据自己的需求进行修改扩展。

2.利用itext将生成的html转换为pdf文件

理解了freemarker生成html的步骤以后,就可以利用itext把html生成pdf文件了。

1.编写转换代码

添加maven依赖

在pom.xml文件中添加以下依赖:

<dependency>
<groupid>com.itextpdf.tool</groupid>
    <artifactid>xmlworker</artifactid>
    <version>5.5.1</version>
</dependency>

<dependency>
    <groupid>com.itextpdf</groupid>
    <artifactid>itext-asian</artifactid>
    <version>5.2.0</version>
</dependency>

<!-- 支持css样式渲染 -->
<dependency>
    <groupid>org.xhtmlrenderer</groupid>
    <artifactid>flying-saucer-pdf-itext5</artifactid>
    <version>9.0.9</version>
</dependency>

2.编写转换代码

在springboot应用程序中创建一个service或者controller类,然后编写html转pdf的代码。

freemarker转换为html的方法:

public class htmlgenerator {

​​​​​​​    public static string generate(string template, map<string, object> variables) throws ioexception, templateexception, ioexception {
     
        configuration config = new configuration(configuration.default_incompatible_improvements);
        // 指定freemarker模板文件的位置
        config.setclassfortemplateloading(htmlgenerator.class, "/filepath");
        //读取模板文件地址
        config.setdefaultencoding("utf-8");
        //获取模板文件
        template tp = config.gettemplate(template);
        stringwriter stringwriter = new stringwriter();
        bufferedwriter writer = new bufferedwriter(stringwriter);
        tp.setencoding("utf-8");
        //把map数据写入
        tp.process(variables, writer);
        string htmlstr = stringwriter.tostring();
        writer.flush();
        writer.close();
        return htmlstr;
    }
}

/filepath为项目中的ftl文件相对路径。

html生成pdf的方法:

public class pdfdocumentgenerator {
    private static final logger logger = loggerfactory.getlogger(pdfdocumentgenerator.class);

    /**
     * output a pdf to the specified outputstream
     * 
     * @param htmlstr
     *            the htmlstr
     * @param out
     *            the specified outputstream
     * @throws exception
     */
    public static void generate(string htmlstr, outputstream out)
            throws exception {
        documentbuilderfactory df = documentbuilderfactory.newinstance();
        df.setattribute(xmlconstants.access_external_dtd, ""); // compliant
        df.setattribute(xmlconstants.access_external_schema, ""); // compliant
        documentbuilder builder = df.newdocumentbuilder();
        org.w3c.dom.document doc = builder.parse(new bytearrayinputstream(htmlstr
                .getbytes()));
        itextrenderer renderer = new itextrenderer();
        renderer.setdocument(doc, null);
        renderer.layout();
        renderer.createpdf(out);
        out.close();
    }
    
    public static void generateplus(string htmlstr, outputstream out) throws ioexception, documentexception {
        final string charsetname = "utf-8";
        
        document document = new document(pagesize.a4, 30, 30, 30, 30);
        document.setmargins(30, 30, 30, 30);
        pdfwriter writer = pdfwriter.getinstance(document, out);
        document.open();
        
        // html内容解析
        htmlpipelinecontext htmlcontext = new htmlpipelinecontext(
                new cssappliersimpl(new xmlworkerfontprovider() {
                    @override
                    public font getfont(string fontname, string encoding,
                                        float size, final int style) {
                        if (fontname == null) {
                       
                            fontname = getchinesefont();      
                        }
                        return super.getfont(fontname, encoding, size,
                                style);
                    }
                })) {
            @override
            public htmlpipelinecontext clone()
                    throws clonenotsupportedexception {
                htmlpipelinecontext context = super.clone();
                try {
                    imageprovider imageprovider = this.getimageprovider();
                    context.setimageprovider(imageprovider);
                } catch (noimageproviderexception e) {
                }
                return context;
            }
        };
        
        // 图片解析
        htmlcontext.setimageprovider(new abstractimageprovider() {
            
            string rootpath = pdfdocumentgenerator.class.getresource("/").getpath();
            
            @override
            public string getimagerootpath() {
                return rootpath;
            }

            @override
            public image retrieve(string src) {
                if (stringutils.isempty(src)) {
                    return null;
                }
                try {
                    image image = image.getinstance(new file(rootpath, src).touri().tostring());
                    // 图片显示位置
                    image.setabsoluteposition(400, 400);        
                    if (image != null) {
                        store(src, image);
                        return image;
                    }
                } catch (throwable e) {
                    e.printstacktrace();
                }
                return super.retrieve(src);
            }
        });
        htmlcontext.setacceptunknown(true).autobookmark(true).settagfactory(tags.gethtmltagprocessorfactory());
        
        // css解析
        cssresolver cssresolver = xmlworkerhelper.getinstance().getdefaultcssresolver(true);
        cssresolver.setfileretrieve(new fileretrieve() {
            @override
            public void processfromstream(inputstream in,
                                          readingprocessor processor) throws ioexception {
                try (
                        inputstreamreader reader = new inputstreamreader(in, charsetname)) {
                    int i = -1;
                    while (-1 != (i = reader.read())) {
                        processor.process(i);
                    }
                } catch (throwable e) {
                }
            }

            // 解析href
            @override
            public void processfromhref(string href, readingprocessor processor) throws ioexception {
                inputstream is = pdfdocumentgenerator.class.getresourceasstream("/" + href);
                try (inputstreamreader reader = new inputstreamreader(is,charsetname)) {
                    int i = -1;
                    while (-1 != (i = reader.read())) {
                        processor.process(i);
                    }
                } catch (throwable e) {
                    e.printstacktrace();
                }
            }
        });

        htmlpipeline htmlpipeline = new htmlpipeline(htmlcontext, new pdfwriterpipeline(document, writer));
        pipeline<?> pipeline = new cssresolverpipeline(cssresolver, htmlpipeline);
        xmlworker worker = null;
        worker = new xmlworker(pipeline, true);
        xmlparser parser = new xmlparser(true, worker, charset.forname(charsetname));
        try (inputstream inputstream = new bytearrayinputstream(htmlstr.getbytes())) {
            parser.parse(inputstream, charset.forname(charsetname));
        }
        document.close();
    }

    /**
     * 获取中文字体位置 
     * @return
     */
    public static string getchinesefont() {
        string chinesefont = null;
        chinesefont = object.class.getresource("/").getpath() + "font/simsun.ttc";
        if(!new file(chinesefont).exists()){
            throw new runtimeexception("字体文件不存在!"+chinesefont);
        }

        return chinesefont;
    }
}

运行测试方法:

public class pdfdest {
    public static void main(string[] args) throws exception {
        string outputfile = "d:/test1.pdf";
        map<string, object> map = new hashmap<>();
        map.put("xxx", "测试");
        //生成工具,下面有代码
        string htmlstr = htmlgenerator.generate("test.ftl", map);
        //生成工具,下面有代码
        outputstream out = new fileoutputstream(outputfile);
        pdfdocumentgenerator.generateplus(htmlstr,out);
    }
}

准备一个test.ftl放到resource/filepath下,当然字体最好也放到resource/font下,运行时需要使用。

test.ftl的代码如下:

<!doctype html>
<html>
<head>
    <meta charset="utf-8"></meta>
    <style>

        @page {
            @top-center { content: element(header) }
        }
        @page {
            @bottom-center { content: element(footer) }
        }
        .apply {
            margin: 0 auto;
            padding: 0 30px;
        }
        .title {
            margin-top: 40px ;
            text-align: center;
            font-weight: bold;
        //字体需要和后台对应上
        font-family: simsun;
            font-weight: bold;
            font-size: 20px;
            color: #333333;
            letter-spacing: 0;
        }
        .table {
            border-collapse: collapse;
            width: 100%;
            margin-top: 30px;
            font-family: simsun;
            font-size: 14px;
            color: #111111;
            letter-spacing: 0.54px;
        }
        .label {
            background-color: #e6e6e6;
            width: 20%;
        }
        .normaltd {
            padding: 10px 0;
        }
        .maxtd {
            height: 250px;
        }
        .value {
            width: 30%;
            padding-left: 10px;
        }
        .apply {
            margin: 0 auto;
            padding: 0 30px;
        }
        .title {
            margin-top: 40px ;
            text-align: center;
            font-weight: bold;
        //字体需要和后台对应上
        font-family: simsun;
            font-weight: bold;
            font-size: 20px;
            color: #333333;
            letter-spacing: 0;
        }
        .table {
            width: 100%;
            margin-top: 30px;
            font-family: simsun;
            font-size: 14px;
            color: #111111;
            letter-spacing: 0.54px;
        }
        .label {
            background-color: #e6e6e6;
            width: 20%;
        }
        .normaltd {
            padding: 10px 0;
        }
        .maxtd {
            height: 250px;
        }
        .value {
            width: 30%;
            padding-left: 10px;
        }

        tr {
            page-break-inside: avoid;
            page-break-after: auto;
        }
    </style>
</head>

<body style="font-family: simsun">
<div class="apply">
    <p class="title">申请单</p>
    <table border="1" cellspacing="0" class="table">
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">xxx</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr >
            <td valign="middle" colspan="1" class="label maxtd" align="center">xxx</td>
            <td valign="middle" colspan="3" class="maxtd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">xxx</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr >
            <td valign="middle" colspan="1" class="label maxtd" align="center">xxx</td>
            <td valign="middle" colspan="3" class="maxtd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td colspan="1" class="label normaltd" align="center">xxx</td>
            <td colspan="3" class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">xxx</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
        <tr>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
            <td class="label normaltd" align="center">xxx</td>
            <td class="normaltd value">${xxx}</td>
        </tr>
    </table>
</div>
</body>
</html>

执行就可以看到生成的pdf文件了,文件路径在d:/test1.pdf。

到此这篇关于java使用freemarker模板生成html再转为pdf的文章就介绍到这了,更多相关java freemarker生成html内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com