需要用到jar包:freemarker.jar
准备工作:准备一个合同的word文档,将需要填充数据的地方用表达式填充好(例:${map.key}),然后将准备好的模板按XML格式保存,这是会形成一个xml文件,将后缀名改为.ftl之后就是可以使用的模板了
后台代码:
创建一个将ftl文件转换成word的类
package gov.wzzj.utils;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import sun.misc.BASE64Encoder;
public class DocumentHandler {
private Configuration configuration = null;
public DocumentHandler() {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
}
public String createDoc(Map dataMap,String templeName) {
//生成文件名
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("application.properties");
long now=System.currentTimeMillis();
java.util.Random random=new java.util.Random();// 定义随机类
int result=random.nextInt(100);// 返回[0,10)集合中的整数,注意不包括10
String name=""+now+result;//生成文件名
Properties p = new Properties();
try{
p.load(inputStream);
} catch (IOException e1){
e1.printStackTrace();
}
String path=p.getProperty("DOWNLOAD_PATH");
// 要填入模本的数据文件
/* Map dataMap = new HashMap();
getData(dataMap);*/
// getTest(dataMap);
// 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
// 这里我们的模板是放在com.template包下面
configuration.setClassForTemplateLoading(this.getClass(),
"/temple");
Template t = null;
try {
// test.ftl为要装载的模板
t = configuration.getTemplate(templeName);
t.setEncoding("utf-8");
} catch (IOException e) {
e.printStackTrace();
}
// 输出文档路径及名称
File outFile = new File(path+name+".doc");
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(outFile), "utf-8"));
} catch (Exception e1) {
e1.printStackTrace();
}
try {
t.process(dataMap, out);
out.close();
} catch (TemplateException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return name+".doc";
}
}
为了方便我将文件名和数据通过service层获取后传入该方法
serivce:
public String ht_download(Map areaMap){
Map dateMap =new HashMap();
Map XmMap=getXmsbById(areaMap);
Map HtMap=getHtshById(areaMap);
Map YQCG=getYqcgById(areaMap);
Map jfysMap=getJfysById(areaMap);
List HzdwList=getHzdwList(areaMap);
List XmzyList=getXmzcyById(areaMap);
List JdapList=getJdapList(areaMap);
List JfbkList=getJfjfList(areaMap);
List YfbkList=getYfjfList(areaMap);
List yqsbList=getYqsbById(areaMap);
List dzfjList=getDzfjById(areaMap);
int hzdwzs=getHzdwCount(areaMap);
areaMap.put("ZZ", "0");
int cdzs=getHzdwZz(areaMap);
areaMap.put("ZZ", "1");
int cyzs=getHzdwZz(areaMap);
int jfbzCount=getJfbzCount(areaMap);
int yfbzCount=getYfbzCount(areaMap);
dateMap.put("jfbzCount", jfbzCount);
dateMap.put("yfbzCount", yfbzCount);
dateMap.put("XmMap", XmMap);
dateMap.put("HtMap", HtMap);
dateMap.put("YQCG", YQCG);
dateMap.put("jfysMap", jfysMap);
dateMap.put("HzdwList", HzdwList);
dateMap.put("XmzyList", XmzyList);
dateMap.put("JdapList", JdapList);
dateMap.put("JfbkList", JfbkList);
dateMap.put("YfbkList", YfbkList);
dateMap.put("yqsbList", yqsbList);
dateMap.put("dzfjList", dzfjList);
dateMap.put("hzdwzs", hzdwzs);
dateMap.put("cdzs", cdzs);
dateMap.put("cyzs", cyzs);
DocumentHandler dh=new DocumentHandler();
String fileName=dh.createDoc(dateMap,"htTemple.ftl");
System.out.println("end");
return fileName;
}
将所有需要的map,list,int等值统统放在一个map中传给createDoc方法
接下来将保存好的文件名传给前台执行下载就可以了
这块最麻烦的是模板的生成,在转换成ftl格式后,我们需要自己对该文件进行一些调整修改,比如列表循环生成,非空判断等,由于没有格式错误的提示,所以需要自己一行行的查下去,比较麻烦
本次功能有用到的一些标签记录一下:
<w:tbl></w:tbl>就是jsp里的<table></table>,表示表格
<w:tr></w:tr>就是jsp里的<tr></tr>,表示表格的一行
<w:tc></w:tc>就是jsp里的<td></td>,表示表格的一格
<w:t></w:t>类似jsp里的<span></span>,表示文本内容,
一般在wrod里设置好的参数都在这个里面已<w:t>${map.key}</w:t>的形式出现
<w:gridSpan w:val="3"/>表示横向的单元格合并,类似于jsp里的colspan="3"
目前已知的横向合并需要自己传值,但是纵向的是自动根据表格长度增长的
for循环list生成表格:
<#list listName as newListName>
</#list>
这就是一个for循环的标签,将需要循环生成的内容放入里面就可循环生成
例:
<#list listName as newListName>
<w:tr>
<w:tc>
<w:t>${newListName_index}</w:t>//这个是list的序列值,从0开始
<w:t>${newListName?size}</w:t>//这个是list的长度
<w:t>${newListName.name}</w:t>
<w:t>${newListName.age}</w:t>
</w:tc>
</w:tr>
</#list>
还有种根据指定长度循环生成
<#list 0..2 as t>//类似于for(int i=0;i<=2;i++)
</#list>
if判断操作:
<#if newListName?size<5 >
</#if>
可以对所需要的条件进行判断,来决定是否执行里面的代码
例:(当list的长度小于5的时候循环生成list)
<#if newListName?size<5 >
<#list listName as newListName>
<w:tr>
<w:tc>
<w:t>${newListName.name}</w:t>
<w:t>${newListName.age}</w:t>
</w:tc>
</w:tr>
</#list>
</#if>
if..else用法:
<#if >
<#else>
</#if>
非空判断:
对于每个值都需要做一下非空判断,不然一旦读取数据为null就直接报错
${(map.key)!''},当值为空时,会显示!后的数据,现在就是当值为空时显示''
${value!''}单个值直接这么写
ftl里面注释和mybatis一样<!-- 注释 -->