使用xmlworker通過html生成pdf
xmlworker是一個基于iText的xml生成pdf工具。使用xmlworker是非常簡單的,思路也很清晰。獲取模板->拼裝模板->生成pdf。但是在過程中還是有一些小問題需要注意下。
首先中文的問題,xmlworker默認是不支持中文的,需要修改源代碼重新打包才能支持亞洲字體(修改詳情)。
也可以下載我已經編好的包:
修改com.itextpdf.tool.xml.css.apply.ChunkCssApplier.java 中的 public Chunk apply(final Chunk c, final Tag t) :
Font f = applyFontStyles(t);
// for chinese charater display @www.micmiu.com
if (null != HTMLUtils.bfCN && HTMLUtils.isChinese(c.getContent())) {
f = new Font(HTMLUtils.bfCN, f.getSize(), f.getStyle(),
f.getColor());
}
float size = f.getSize();
......
在com.itextpdf.tool.xml.html.HTMLUtils.java 中 增加下面用于中文字符判斷的方法:
public static BaseFont bfCN = null;
static {
try {
bfCN = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
}
}
// add by Michael more see:http://www.micmiu.com
private static final boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
return true;
}
return false;
}
// add by Michael more see:http://www.micmiu.com
public static final boolean isChinese(String strName) {
char[] ch = strName.toCharArray();
for (int i = 0; i < ch.length; i++) {
char c = ch[i];
if (isChinese(c)) {
return true;
}
}
return false;
} 其次,在寫html模板的時候,因為xmlworker支持的CSS樣式極少,所以模板內容要盡量簡單。對于DOCTYPE和html標簽的約束頁比較嚴格。我使用的是
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <br /><html xmlns="http://www.w3.org/1999/xhtml">。
對于一個標簽中含有中文、數字或英文的時候,很可能會出現字體變形。這是因為xmlworker在渲染PDF的時候是以html的標簽為單位的。只要把中文和英文分隔在不同的標簽就可以了。
最后貼上代碼作為參考:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class PDFOperation {
public static void main(String[] args) throws Exception {
// 獲取html內容
String html = getHtml();
// 生成pdf
createPdf(html);
}
public static void createPdf(String html)throws DocumentException, IOException {
String file = "E:/detail.pdf";
Document doc = new Document();
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(file));
doc.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, doc,new StringReader(html));
doc.close();
}
public static String getHtml() throws IOException, TemplateException{
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File("E:/templatedir/"));
cfg.setObjectWrapper(new DefaultObjectWrapper());
Template t = cfg.getTemplate("test.ftl");
Writer out = new StringWriter();
Map<String,Object> map = new HashMap<String,Object>();
Map<String,Object> req = new HashMap<String,Object>();
req.put("title","XXX");
req.put("ctime", "2014.05.06");
req.put("province", "北京");
List<Map<String,Object>> files = new ArrayList<Map<String,Object>>();
Map<String,Object> file1 = new HashMap<String,Object>();
Map<String,Object> file2 = new HashMap<String,Object>();
file1.put("url", "http://xxx");
file1.put("name", "FreeMarker_Manual_zh_CN.pdf");
file1.put("ext","pdf");
file2.put("url", "http://xxx");
file2.put("name", "OReilly.Redis.Cookbook.2011.pdf");
file2.put("ext","pdf");
files.add(file1);
files.add(file2);
map.put("files", files);
map.put("map",map);
t.process(map, out);
out.flush();
return out.toString();
}
} ftl模板:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<div style="padding:24px;color:#3a3b3b;background-color:#f4f4f4;line-height:28px;">
<h1 style="color:#98989a;font-weight:bold;font-size:24px;text-align:left;">DO NOT COPY</h1>
<div style="background-color:#fff;padding:16px 24px;width:100%;">
<h1>${map.title}</h1>
<h5 style="color:#848484;font-weight:normal;"><span>${map.ctime}</span></h5>
</div>
<div style="height:24px;"> </div>
<div style="background-color:#fff;padding:16px 24px;width:100%;">
<h2>說明</h2>
<div style="height:1px;background-color:#dbdbdb;width:100%;"> </div>
<div style="height:16px;width:100%;"> </div>
<ul style="list-style-type:none;margin:0px;padding:0px;padding-left:24px;">
<li><span style="color:#848484">地區</span> ${map.province?default('')}</li>
</ul>
<#if files ?exists >
<h3>附件</h3>
<div style="background-color:#eee;width:100%;padding:12px;padding-left:24px;">文件</div>
<ul style="list-style-type:none;margin:0px;padding:0px;padding-left:24px;padding-right:24px;">
<#list files as f>
<li style="margin:0px;padding:12px 0;"><a href="${f.url}"><span>${f.name}</span>.<span>${f.ext}</span></a></li>
</#list>
</ul>
</#if>
</div>
<h1 style="color:#98989a;font-weight:bold;font-size:24px;text-align:right;">DO NOT COPY</h1>
</div>
</body>
</html>
以下是可能提供幫助的資料:
支持的樣式表
HTML生成PDF在線測試
itextpdf in action中的源碼樣例
編譯好的xmlworker-cn.jar,如果使用maven并有私庫,需要部署到私庫。version=5.5.0,groupId=com.itextpdf.tool,artifactId=xmlworker-cn