使用freemarker和itext导出pdf文件

原创
2018/09/27 11:18
阅读数 1.9K

要实现的效果是这样的:给定一个对象列表,对于列表中的每一个对象使用pdf中的一页进行呈现,同时需要使用一些图片。

首先,引入maven依赖

<properties>
    <itextpdf.version>5.5.13</itextpdf.version>
    <freemarker.version>2.3.28</freemarker.version>
    <slf4j.version>1.7.25</slf4j.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>${itextpdf.version}</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf.tool</groupId>
        <artifactId>xmlworker</artifactId>
        <version>${itextpdf.version}</version>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>${freemarker.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-nop</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
</dependencies>

使用用户信息来作为演示,其实体模型类

public class User {

    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    getter/setter

}

生成pdf分为两个步骤:使用freemarker生成出文字内容(xhtml);使用itext的xml转换器生成pdf文件。

测试样例类

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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 cn.songxinqiang.example.model.User;
import cn.songxinqiang.example.util.PathUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 *
 * @author 阿信sxq
 *
 */
public class JavaToPdfHtmlFreeMarker {

    private static final Logger logger = LoggerFactory.getLogger(JavaToPdfHtmlFreeMarker.class);

    private static final String DEST = "/tmp/itext_target.pdf";
    private static final String HTML = "freemarker-template.html";
    private static final String FONT = "simhei.ttf";

    private static Configuration freemarkerCfg = null;
    private static String classPath;

    static {
        freemarkerCfg = new Configuration(Configuration.VERSION_2_3_28);
        // freemarker的模板目录
        try {
            //XXX 工具类获取类文件的当前路径,也可以使用文件系统绝对路径
            classPath = PathUtil.getCurrentPath();
            freemarkerCfg.setDirectoryForTemplateLoading(new File(classPath));
//            freemarkerCfg.setDirectoryForTemplateLoading(new File("/opt/chaos"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException, DocumentException {
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            userList.add(new User("name " + i, "passwd " + i));
        }

        JavaToPdfHtmlFreeMarker render = new JavaToPdfHtmlFreeMarker();
        String content = render.freeMarkerRender(userList, HTML);
        logger.info("content:{}", content);
        render.createPdf(content, DEST);
    }

    public 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 String freeMarkerRender(List<?> list, String htmlTmp) {
        Map<String, Object> data = new HashMap<>();
        data.put("list", list);
        data.put("locationPath", classPath);
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            // 合并数据模型与模板
            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;
    }

}

freemarker模板

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<style>
body {
    font-family: SimHei;
}
.pageNext{
    page-break-after: always;
}
</style>
</head>
<body>
    <#list list as user>
        用户名:${user.username}<br/>
        密码:${user.password}<br/>
        插入图片:<br/>
        <img width="100px" src="file://${locationPath}/github.png"/>
        <span class="pageNext"></span>
    </#list>
</body>
</html>

这里需要使用xhtml的语法,所有标签都需要闭合,因为经过处理得到的内容会使用itext的xml处理器去处理。

而且对于汉字需要指定汉字字体。

对于代码,已经托管到码云:https://gitee.com/songxinqiang/BlogExampleCode

写的不好,望大家批评指正

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
1
分享
返回顶部
顶部