The Apache POI Project's mission is to create and maintain Java APIs for manipulating various file formats based upon the Office Open XML standards (OOXML) and Microsoft's OLE 2 Compound Document format (OLE2).
POI是一个基于xml标准的JAVA 框架,相信很多人会用来处理office。这篇文章的主旨不是介绍POI,而是讲一下复杂的word。
首先,poi的介绍网上很多,包括demo代码。大部分都是采用渲染range的方式,填充word body。这种方式很直观,也只要做简单的replace就能做出demo,但是真实业务中基本不会那么简单。
FileInputStream fis = new FileInputStream(new File(templateFile));
HWPFDocument doc = new HWPFDocument(fis);
Range bodyRange = doc.getRange();
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
PropertyDescriptor proDescriptor = new PropertyDescriptor(field.getName(), obj.getClass());
if (proDescriptor != null) {
Method readMethod = proDescriptor.getReadMethod();
bodyRange.replaceText("${" + field.getName() + "}", readMethod.invoke(obj) == null ? "" : readMethod.invoke(obj).toString());
}
}
return doc;
上面是最简单的replaceText方式。查看 Range API可以发现有各种replace的方式。
Merge Word 这里有简单的text合并,stack overflow上也有些提问,都是实现了简单的字体,text合并。如果你的需求只是这么简单,那么够了。
下面来介绍一种 poi + freemarker 方式来制作复杂的word。
public static void converWord(String templateFile, String targetFile, List<?> objs){
Configuration configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
Map<String, List<?>> dataMap = new HashMap<String, List<?>>();
dataMap.put("data", objs);
Template tmpl = null;
try {
configuration.setDirectoryForTemplateLoading(new File(templateFile));
tmpl = configuration.getTemplate("template.ftl");
} catch (Exception e) {
e.printStackTrace();
}
File outFile = new File(targetFile);
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(outFile), "UTF-8"));
tmpl.process(dataMap, out);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out.flush();
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
看上面代码可以发现,首先需要一个 template.ftl 的xml文件,然后采用el表达式来替换xml中的 ${xxx} 参数。xml文件可以采用word自带的导出word xml方式获得。
相比于range方式,这里提供了xml,但是xml的维护时同同时带出的一个问题。
word的xml都是 <w:**> 的标签,比如<w:sectPr>等等。
这时再联系poi本身,不难发现,如果我们撇开range这种烂播的方式(各种无脑复制、粘贴占据搜索榜),我们也采用word本身的标签来处理,其实跟第二种的本质是一样的,但是我们需要些很多java代码。freemarker只是提供了一种xml的配置而已。
/*20140930*/