要实现的效果是这样的:给定一个对象列表,对于列表中的每一个对象使用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
写的不好,望大家批评指正