Java使用freemark生成word

一、做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>、<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已经被替换过啦:

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值