Java使用freemark生成word
2016-06-12 15:00
411 查看
一、做web项目的开发,难免需要跟各种文档打交道,像excel、word等,前阵子工作中就遇到需要导出word文档,上网找了一些资料,在word导出这方便有很多的工具可以使用,jacob、poi、java2word、itext,最后选定了用itext来导出word,网上一些资料说itext导出word功能太简单,不过通过使用之后,封装工具类,使用起来也挺方便的,导出的word文档看起来也不错,总体来说达到要求,但是在某些细节方面很难达到一致,比如:字体、行距、字体间距、首行缩进等。
二、鉴于itext导出的word有一些小问题,需要另找其他的方式,通过一个同事的知道了可用freemark模板来导出word,其效果能与要求的demo word文档达到惊人的一致,而且使用也很方面。总的来说就是制作模板(动态的数据用占位符${string}表示),用真实数据代理模板中的占位符,最后生成word。下面看例子:
1、制作模板
先用office word做一个模板word文档,${usrName}、${nowDate}占位符
2、用office word将模板word另存为xml
如有勾选仅保存数据(D),后面会有一个确认选择框,点击保持WordML(K)
3、讲xml文件的后缀改为.ftl
4、编辑.ftl文件
a、用${string}替换需要动态生成的数据,这一步我们在制作模板的时候就已经编写好了,这里不需要再编辑,需要主意的是在装换成xml文件的时候,占位符可能会被分成多个,如上面的${userName}可能会被分开成${userNam和e},这时需要把e}合到${userNam标签里面,并删除掉e}相关的标签。
b、表格循环用标签<#list table1
as object> </#list>(类似for (String[] object:
table1 ){}),详细语法请百度搜索。
首先介绍几个标签,<w:tbl>表格标签类似HTML的<table>,<w:tr>类似HTML的<tr>。<w:tc></w:tc>每一个单元格,下面以表1为例子:
通过关键搜索找到表1的<w:tbl>,在<w:tbl>会有一些子标签,<w:tblPr></w:tblPr>定义表格的一些格式,<w:tblGrid></w:tblGrid>每一列的长度,我们不需要去修改标签的任何内容和格式,因为在制作模板的时候,我们已经设计好了。
<w:tbl>的子标签还有<w:tr></w:tr>,表示每一行的数据,我们所要做的是找到第二个<w:tr>(第一个是表格标题,固定的,不需要循环),然后删除掉第二个后面的<w:tr>,接下来将第二个<w:tr>包裹在我们的循环标签<#list table1
as object> </#list>内就行。
再接下来取出数据填充。依次找到<w:tr>、<w:tc>、<w:p>、<w:r&g
4000
t;、<w:t>(由于设计模板的时候,第四列里面的数据为空的,生成XML的时候是没有<w:r></w:r>和<w:t></w:t>,需要我们自己添加,建议设计模板的时候不要留空数据,避免这种情况出现),填充<w:t>1</w:t>(<w:t>广州</w:t>
|| <w:t>37390379</w:t>等)里面的数据,即将<w:t>1</w:t>改为<w:t>${object[0]}</w:t>,object数组对象(<#list table1
as object> </#list>中的object),0下标,很容易理解。
依照次方法修改其他的表格标签,至此模板已写完,接下来是编程部分。
三、程序
相对来说,程序比较简单!
导出结果:
与原始文档对比,可以看到用户名、日期和表1已经被替换过啦:
源码:http://download.csdn.net/detail/op635915376/9547101
二、鉴于itext导出的word有一些小问题,需要另找其他的方式,通过一个同事的知道了可用freemark模板来导出word,其效果能与要求的demo word文档达到惊人的一致,而且使用也很方面。总的来说就是制作模板(动态的数据用占位符${string}表示),用真实数据代理模板中的占位符,最后生成word。下面看例子:
1、制作模板
先用office word做一个模板word文档,${usrName}、${nowDate}占位符
2、用office word将模板word另存为xml
如有勾选仅保存数据(D),后面会有一个确认选择框,点击保持WordML(K)
3、讲xml文件的后缀改为.ftl
4、编辑.ftl文件
a、用${string}替换需要动态生成的数据,这一步我们在制作模板的时候就已经编写好了,这里不需要再编辑,需要主意的是在装换成xml文件的时候,占位符可能会被分成多个,如上面的${userName}可能会被分开成${userNam和e},这时需要把e}合到${userNam标签里面,并删除掉e}相关的标签。
b、表格循环用标签<#list table1
as object> </#list>(类似for (String[] object:
table1 ){}),详细语法请百度搜索。
首先介绍几个标签,<w:tbl>表格标签类似HTML的<table>,<w:tr>类似HTML的<tr>。<w:tc></w:tc>每一个单元格,下面以表1为例子:
通过关键搜索找到表1的<w:tbl>,在<w:tbl>会有一些子标签,<w:tblPr></w:tblPr>定义表格的一些格式,<w:tblGrid></w:tblGrid>每一列的长度,我们不需要去修改标签的任何内容和格式,因为在制作模板的时候,我们已经设计好了。
<w:tbl>的子标签还有<w:tr></w:tr>,表示每一行的数据,我们所要做的是找到第二个<w:tr>(第一个是表格标题,固定的,不需要循环),然后删除掉第二个后面的<w:tr>,接下来将第二个<w:tr>包裹在我们的循环标签<#list table1
as object> </#list>内就行。
再接下来取出数据填充。依次找到<w:tr>、<w:tc>、<w:p>、<w:r&g
4000
t;、<w:t>(由于设计模板的时候,第四列里面的数据为空的,生成XML的时候是没有<w:r></w:r>和<w:t></w:t>,需要我们自己添加,建议设计模板的时候不要留空数据,避免这种情况出现),填充<w:t>1</w:t>(<w:t>广州</w:t>
|| <w:t>37390379</w:t>等)里面的数据,即将<w:t>1</w:t>改为<w:t>${object[0]}</w:t>,object数组对象(<#list table1
as object> </#list>中的object),0下标,很容易理解。
依照次方法修改其他的表格标签,至此模板已写完,接下来是编程部分。
三、程序
相对来说,程序比较简单!
package test.word; import java.awt.Desktop; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.Template; public class Test { /** * 获取数据 * @return * @throws Exception */ private static Map<String, Object> getData() throws Exception { Map<String, Object> map = new HashMap<String, Object>(); map.put("userName", "admin");//对应模板中的${userName} map.put("nowDate", new Date().toString());//对应模板中的${nowDate} List<String[]> tablt1 = new ArrayList<String[]>(); tablt1.add(new String[]{"1","广州","838973","--"}); tablt1.add(new String[]{"2","佛山","115542","--"}); tablt1.add(new String[]{"3","合计","955845","--"}); map.put("table1", tablt1);//<#list table1 as object></#list> //其他数据 return map; } public static void main(String[] args) throws Exception { createWord(getData(), "test.ftl", "F:/test/", "test"+System.currentTimeMillis()+".doc"); } /** * * @param dataMap 数据 * @param templateName 模板名称 * @param filePath 保存文件路劲 * @param fileName 保存文件名 */ public static void createWord(Map<?, ?> dataMap, String templateName, String filePath, String fileName) { try { Configuration configuration = new Configuration(); configuration.setDefaultEncoding("UTF-8"); // ftl模板文件统一放至 test.ftl包下面 configuration.setClassForTemplateLoading(Test.class, "/test/word/"); // 获取模板 Template template = configuration.getTemplate(templateName); File outFile = new File(filePath + File.separator + fileName); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } // 将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(outFile), "UTF-8")); // 生成文件 template.process(dataMap, out); out.flush(); out.close(); Desktop desktop = Desktop.getDesktop(); desktop.open(new File(filePath + File.separator + fileName)); } catch (Exception e) { e.printStackTrace(); } } }
导出结果:
与原始文档对比,可以看到用户名、日期和表1已经被替换过啦:
源码:http://download.csdn.net/detail/op635915376/9547101
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树