[关闭]
@hucheng91 2017-04-09T14:46:53.000000Z 字数 3744 阅读 1945

基于freemarker ,xdocreport生成word,pdf

最近公司有个业务,是要生成pdf形式的合约,合约模版是有十几页的word,根据不同的客户,模版有些地方填入不同的值,然后生成pdf格式的合约。最开始打算用JasperReports,先把这个模版画出来,但是由于模版页数太多,样式很复杂,JasperReports处理起来简直就是噩梦,果断放弃,随后我又调研了doc4j,openoffice;doc4j处理复杂文档也不是太好,加粗的字体都没有显示出来,对office2013不怎么支持,openoffice得单独装一个服务端,很是耗资源,也放弃了;最后我选择了先用freemarker将模版变量填入生成一个docx,在用xdocreport这个库来将docx转换成pdf,成功的实现了,支持office的2007,2013等,而且docx样式也完全保留下来,而且整个过程非常快,不怎么耗费资源,内存;

先介绍下freemarker,xdoxreport
- freemarker是java里一个模版框架,和velocity类似,不仅支持各种xml格式,freemarker地址
此处输入图片的描述
- xdoxreport是一个处理常见的文档转换成pdf的库,提供POI和Itext2种方式,简单说就是将POI,Itext封装起来,它其实也提供的封装了freemarker的一套模版,但我没有选择它的,觉得没必要,github介绍如下,github地址

XDocReport means XML Document reporting. It's Java API to merge XML document created with MS Office (docx) or OpenOffice (odt), LibreOffice (odt) with a Java model to generate report and convert it if you need to another format (PDF, XHTML...).


然后介绍下我整体的一个思路,MS-Office下的word在2007以后后缀基本是以.docx结尾,是用一种xml格式的在存储数据(.doc是用二进制存储数据),这就为使用freemarker提供的条件,如果把template.docx,重命名成template.zip,再用word一样是可以打开的,如果有WinRAR之类的压缩工具打开会发现如下目录结构

我们用office工具打开看到的内容其事就存放在在这个document.xml里面!,打开看看(document.xml默认是不换行的,我用Nodpad++打开,然后下载nodpad插件Xml-tool格式化后,具体安装可参考Nodepad 格式化xml)在这个xml就是以这种格式存储的数据,只需要将我们需要的内容变成一个变量,然后通过freemarker来解析这xml,让后用解析后的xml,把template.zip里面的document.xml替换掉,然后将这个template.zip解压成data.docx,那么这个data.docx,就包含了我们需要的数此处输入图片的描述

具体操作如下

  1. 处理模版对应的docx此处输入图片的描述
  2. 将test.docx重命名test.zip,将document.xml copy 出来 ,打开 document.xml,此处输入图片的描述
  3. java代码如下

    1. /** 初始化配置文件 **/
    2. Configuration
    3. configuration = new Configuration();
    4. /** 设置编码 **/
    5. /** 我的ftl文件是放在D盘的**/
    6. String fileDirectory = "D:/cache/qqChace/T1/xlsx";
    7. /** 加载文件 **/
    8. configuration.setDirectoryForTemplateLoading(new File(fileDirectory));
    9. /** 加载模板 **/
    10. Template template = configuration.getTemplate("document.xml");
    11. /** 准备数据 **/
    12. Map<String,String> dataMap = new HashMap<>();
    13. /** 在ftl文件中有${textDeal}这个标签**/
    14. dataMap.put("id","黄浦江吴彦祖");
    15. dataMap.put("number","20");
    16. dataMap.put("language","java,php,python,c++.......");
    17. dataMap.put("example","Hello World!");
    18. /** 指定输出word文件的路径 **/
    19. String outFilePath = "D:/cache/qqChace/T1/xlsx/data.xml";
    20. File docFile = new File(outFilePath);
    21. FileOutputStream fos = new FileOutputStream(docFile);
    22. OutputStreamWriter oWriter = new OutputStreamWriter(fos);
    23. Writer out = new BufferedWriter(new OutputStreamWriter(fos),10240);
    24. template.process(dataMap,out);
    25. if(out != null){
    26. out.close();
    27. }
    28. // ZipUtils 是一个工具类,主要用来替换具体可以看github工程
    29. ZipInputStream zipInputStream = ZipUtils.wrapZipInputStream(new FileInputStream(new File("D:/cache/qqChace/T1/xlsx/test.zip")));
    30. ZipOutputStream zipOutputStream = ZipUtils.wrapZipOutputStream(new FileOutputStream(new File("D:/cache/qqChace/T1/xlsx/test.docx")));
    31. String itemname = "word/document.xml";
    32. ZipUtils.replaceItem(zipInputStream, zipOutputStream, itemname, new FileInputStream(new File("D:/cache/qqChace/T1/xlsx/data.xml")));
    33. System.out.println("success");
  4. 生成test.docx如下此处输入图片的描述,这样我通过freeemark生成docx这件事就搞定了


接下来就简单,通过xdocreport生成pdf,maven引用,java代码就不记录具体看github项目地址

  1. <properties>
  2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3. <xdocreport.version>1.0.5</xdocreport.version>
  4. </properties>
  5. <dependency>
  6. <groupId>fr.opensagres.xdocreport</groupId>
  7. <artifactId>org.apache.poi.xwpf.converter.core</artifactId>
  8. <version>${xdocreport.version}</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>fr.opensagres.xdocreport</groupId>
  12. <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
  13. <version>${xdocreport.version}</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>fr.opensagres.xdocreport</groupId>
  17. <artifactId>fr.opensagres.xdocreport.itext.extension</artifactId>
  18. <version>${xdocreport.version}</version>
  19. </dependency>

注意:docx内容字体需要是宋体,我用的office是2013版本的,我在2007版本上也测试过,是可以生成的,其他会乱码,不过xdocreport支持扩展字体 github的issue

总结:通过freemarkder+xdocreport生成pdf是一个比较简便,适合复杂的docx文档,而且freemarker语法并不难,处理list数据和很好处理,图片也有很好的支持;而且速度快, 在处理word转pdf上很方便。

把整个打包成一个工程 ,放到github上了,github地址

参考:

用FreeMarker生成Word文档
使用Notepad++的XML Tools插件格式化XML文件
freemarker官网
xdocxreport对应github地址

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注