java利用freemarker导出含有list的数据到word,有demo可供下载
前言
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
java导出数据到文档的方式有很多,为什么选择freemarker?还不是人家免费呗,而且体积小,资源占用可忽略不计,使用也还算简单。
如何使用?
1.下载freemarker.jar包,官网有,但是资源很差,点击几十次都不一定能成功下载一次。
你可以点击我的下载资源,内含freemarker.jar和demo:点击下载
2.把freemarker.jar放到到java项目的lib文件夹中。
3.准备你需要导出word的模板,模板中需要植入数据的地方,都用${字段名}填充。然后转换成xml格式。这里切记注意word版本,只限于2007版本一下,否则wps用不了。当然,我用的office2010,没这限制。(因为2007版本以前,WPS都是抄office的,之后的版本wps才开始独立起来成为真正意义上的国产,版本高了别人用WPS打开就有问题了)
![处理word模板](https://www.icode9.com/i/ll/?i=20200304091958423.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTQ0MjUwNg==,size_16,color_FFFFFF,t_70)
4.把转换后的xml文档放到eclipse中,先Ctrl+SHIFT+F格式化一下,再处理模板。
**xml处理第一步**:删除多余格式内容,保证字段标记正常如${type},每个你需要的字段都得这样处理好。
![处理xml模板](https://www.icode9.com/i/ll/?i=2020030409224020.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTQ0MjUwNg==,size_16,color_FFFFFF,t_70)
**xml处理第二步**:有list数据的(即word中的子表),需要使用<#list list as list></#list>标签包括起来,只需要包括数据部分就行,表头不需要包括。至于怎么在xml中找到你的字表数据内容,只能用最笨的办法:先找到其中一个字段名,然后根据这个字段所在的标签<>一直往外找最大的标签<>,直到这个最大标签中只有你的字表字段时,这个位置就对了。你先拿demo练练手就知道了。
![开始标签<#list list as list>所在位置](https://www.icode9.com/i/ll/?i=20200304093625264.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTQ0MjUwNg==,size_16,color_FFFFFF,t_70)
![结束标签</#list>所在位置](https://www.icode9.com/i/ll/?i=20200304092922897.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTQ0MjUwNg==,size_16,color_FFFFFF,t_70)
5.xml文档处理好之后,修改文件后缀名为.ftl,放到你的java项目中的某个文件夹内。
![ftl文件放置位置](https://www.icode9.com/i/ll/?i=20200304093100721.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTQ0MjUwNg==,size_16,color_FFFFFF,t_70)
6.创建类并实现业务,这里简单写个demo。你根据自己业务情况嵌入到自己代码即可!
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
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;
import freemarker.template.TemplateException;
/**
* freemarker导出list多列数据到word文档
* @author 钟三
*/
public class ExportWord {
private Configuration configuration = null;
public ExportWord() {
configuration = new Configuration();
//设置编码
configuration.setDefaultEncoding("UTF-8");
}
//测试一下
public static void main(String[] args) {
String ftlName = "购销合同模板.ftl";
ExportWord test = new ExportWord();
test.createWord(getData(),ftlName);
}
/**
* 创建word文档,植入数据,并输出。(实际项目中应该输出到response*用户下载)
* @param dataMap 需要打印的数据
* @param ftlName 模板名称,实际业务肯定会有多个模板的,应该传入。地址就不需要那么麻烦传入了,直接名字就好
*/
public void createWord(Map<String, Object> dataMap,String ftlName) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
configuration.setClassForTemplateLoading(this.getClass(), ""); // FTL文件所存在的位置,这里我跟当前类ExportWord放在了同一目录下,所以是空
Template t = null;
try {
t = configuration.getTemplate(ftlName); // 模板文件名
} catch (IOException e) {
e.printStackTrace();
}
File outFile = new File("D:/测试打印多列到word-" + sdf.format(new Date()) + ".doc"); // 输出的word文档的存放位置
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
t.process(dataMap, out);
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//获取测试数据,这里应该调用自己的业务方法拿真实数据存放到Map<String, Object> dataMap对象中即可
private static Map<String, Object> getData(){
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("totalAmount", "100000.00");
dataMap.put("unitName", "湖南XX信息科技有限公司");
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("xh", "1");
map1.put("name", "货品名称1");
map1.put("type", "型号规格1");
map1.put("unitPrice", "单价1");
map1.put("num", "数量1");
map1.put("total", "合计金额1");
map1.put("remark", "备注1");
list.add(map1);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("xh", "2");
map2.put("name", "货品名称2");
map2.put("type", "型号规格2");
map2.put("unitPrice", "单价2");
map2.put("num", "数量2");
map2.put("total", "合计金额2");
map2.put("remark", "备注2");
list.add(map2);
dataMap.put("list", list);
System.out.println(dataMap.toString());
return dataMap;
}
}
7.测试成功展示