前言
在这篇文章中,你将看生成一个 Word格式的目标文件 的所有代码。当然,本例只是一个很小的实现。如果你有更好的实现方法,欢迎在评论区留言分享。
一、需求解读
现在需要生成一个IT部信息文档(数据纯属编造,如有雷同,纯属巧合)
二、实现
1.准备模板文件
第一步
编辑需求所给出的Word文件,去除掉多余的部分,只保留最基础的内容,并将数据部分使用其他字符替代(任意字符,只要你自己能够轻松识别出来即可)
可以看到,我将数据部分换成了实体.属性
第二步
将word保存为xml格式,这里我另存为DeptInfoTemplate.xml
第三步
将xml格式的模板文件的后缀直接修改为vm,即DeptInfoTemplate.vm
第四步
这是最重要的一步哦
首先需要介绍两个Velocity的语法 ,那就是 #foreach
和 $
#foreach
用法为:
#foreach($item in $itemList)
targetTempliteContent
#end
意思是:遍历itemList中的每一个item,每一次遍历均生成一段目标文件类型的内容。targetTempliteContent 就是组成目标文件的一部分,即在本例中,目标文件是word,那么这一部分可以是
<!--
对于word的构成方式我也不是很懂,但是按我的理解,其实word也是跟html一样,使用类似于<tag></tag>的标签构成的
<w:p></w:p>就是代表word中的一个段落
-->
<w:p>
<w:pPr>
<w:rPr>
<w:rFonts w:hint="default"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
<w:t>合同编号:$item</w:t>
</w:r>
</w:p>
如果目标文件是html,那么 targetTempliteContent 可以是
<div>
<p>$item</p>
</div>
也就是说 targetTempliteContent 是目标文件中需要重复生成的那部分,比如本例需求中的员工花名册的【行hang】。
$
是的,你没看错,就是一个 符号:$,使用他可以访问velocity的上下文中的变量(业务数据)。
综合这两个语法
假设 itemList = [‘胖大海’,‘程序猿’,‘单身狗’,‘矮矬穷’]
运行
#foreach($item in $itemList)
<div>
<p>$item</p>
</div>
#end
那么最终生成的文件结构为:
<div>
<p>胖大海</p>
</div>
<div>
<p>程序猿</p>
</div>
<div>
<p>单身狗</p>
</div>
<div>
<p>矮矬穷</p>
</div>
看到这里,我想,你已经知道本例中的模板文件DeptInfoTemplate.vm需要怎么处理了。值得一提的是,如果item是一个对象,那么可以使用 $item.attrName
来获取item的属性。
2.组装数据
当模板文件构造好后,你就可以根据模板文件构造数据了。当然,你也可以先构造数据,然后根据数据的结构去调整模板。
你可以将要形成文件的数据封装在一个对象中,这个对象可以是你自己定义的数据模型,也可以直接使用java.util.Map
,这里我就不封装模型了,直接使用Map对象。
代码如下:
Map<String,Object> dept = new HashMap<String, Object>();//部门信息
List<Map<String,Object>> employeeList = new ArrayList<Map<String,Object>>();//员工列表
List<Map<String,Object>> projList = new ArrayList<Map<String,Object>>();//项目列表
employeeList = buildEmployeeList();
projList = buildProjList();
dept.put("name", "IT部");
dept.put("employeeList", employeeList);
dept.put("projList", projList);
3.目标文件生成
//根据你要形成目标文件的数据构建上下文
VelocityContext vc = new VelocityContext();
vc.put("dept", dept);
//初始化模板引擎
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
ve.init();
//初始化模板,
String templateFilePath = "template/DeptInfoTemplate.vm";//模板文件
Template docTemplate = ve.getTemplate(templateFilePath, "UTF-8");
File file = new File("D:"+File.separator+"demo"+File.separator+dept.get("name")+"信息.doc");
FileOutputStream outputStream = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
docTemplate.merge(vc, writer);
writer.flush();
运行后,如果一切正常,那么你会在你指定的文件夹下看到目标文件了。
实际上,本例中我只告诉你了 #foreach
和 $
的使用,实际上我还是用了另外一个语法,算是彩蛋吧,如果你找到了,欢迎在评论区留言哦。
另附:本例使用的Main.class以及DeptInfoTemplate.vm 文件。Main.class没有做很好的容错处理,因为我觉得你,需要有自己调试、找错误原因以及修复的能力。(好吧,实际上是我太懒了)