最近在做一个导出比较复杂的word的项目。通过poi的方式比较复杂,时间成本比较高,所以选择使用Freemarker的方式。
1.生成.ftl文档
首先做好word文档,需要填充的地方提前设置好${name}等,word里,需要图片的地方,也按照格式和尺寸放一张图片(占位置)。
另存为.xml格式文档。(Word XML 文档(*.xml))
打开xml文档:也可以调格式。
将$符号截切下来,放到{}前边,和word里一样,最好在手动敲一遍${name},(我也不知道为什么,有时候不敲就报错)。
图片的地方:
这是BASE64Encoder 的图片,将字符替换为${picture}:
保存xml,将文件重命名为.ftl格式的文件。
至此第一步完成。
2.第二步,代码部分。
导入需要的jar包
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
生成word的方法:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Map;
import freemarker.core.ParseException;
import freemarker.log.Logger;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;
import sun.misc.BASE64Encoder;
public class ExportMyWord {
/*
* 导出word
*/
private Logger log = Logger.getLogger(ExportMyWord.class.toString());
private Configuration config = null;
public ExportMyWord() {
config = new Configuration(Configuration.VERSION_2_3_28);
config.setDefaultEncoding("utf-8");
}
/*dataMap数据的map,在调用的地方组织。
* templateName 模板的名字,
* 生成的路径及名字
*/
public void createWord(Map<String, Object> dataMap, String templateName, String saveFilePath) throws Exception {
// 加载模板(路径)数据
config.setClassForTemplateLoading(this.getClass(), "");
// 设置异常处理器 这样的话 即使没有属性也不会出错 如:${list.name}...不会报错
config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
Template template = null;
if (templateName.endsWith(".ftl")) {
templateName = templateName.substring(0, templateName.indexOf(".ftl"));
}
try {
template = config.getTemplate(templateName + ".ftl");
} catch (TemplateNotFoundException e) {
System.out.println("模板文件未找到");
e.printStackTrace();
} catch (MalformedTemplateNameException e) {
System.out.println("模板类型不正确");
e.printStackTrace();
} catch (ParseException e) {
System.out.println("模板格式错误");
e.printStackTrace();
} catch (IOException e) {
System.out.println("IO读取失败");
e.printStackTrace();
}
File outFile = new File(saveFilePath);
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
Writer out = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
} catch (FileNotFoundException e) {
log.error("输出文件时未找到文件", e);
e.printStackTrace();
}
out = new BufferedWriter(new OutputStreamWriter(fos,"utf-8"));
// 将模板中的预先的代码替换为数据
try {
template.process(dataMap, out);
} catch (TemplateException e) {
log.error("填充模板时异常", e);
e.printStackTrace();
} catch (IOException e) {
log.error("IO读取时异常", e);
e.printStackTrace();
}
//log.info("由模板文件:" + templateName + ".ftl" + " 生成文件 :" + saveFilePath + " 成功!!");
try {
out.close();// web项目不可关闭
} catch (IOException e) {
//log.error("关闭Write对象出错", e);
e.printStackTrace();
}
}
/**
* 可以下载远程图片
* 获得图片的Base64编码,然后装入map中。
*/
public String getImageStr(String imgFile) {
InputStream in = null;
byte[] data = null;
try {
in = new FileInputStream(imgFile);
} catch (FileNotFoundException e) {
log.error("加载图片未找到", e);
e.printStackTrace();
}
try {
data = new byte[in.available()];
// 注:FileInputStream.available()方法可以从输入流中阻断由下一个方法调用这个输入流中读取的剩余字节数
in.read(data);
in.close();
} catch (IOException e) {
log.error("IO操作图片错误", e);
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);
}
}
上边的方法是一个工具方法,和项目业务分开,在业务需要的地方调用该方法即可:下面一个简单的调用。
package xxxx;
import java.util.HashMap;
import java.util.Map;
public class Main_word {
public static void main(String[] args) throws Exception {
ExportMyWord emw = new ExportMyWord();
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("name", "测试");
dataMap.put("age", 28);
dataMap.put("gender", "男");
dataMap.put("data", "1992-05-21");
dataMap.put("aaa","");
dataMap.put("picturea", emw.getImageStr("C:javafx\\1.jpg"));
dataMap.put("pictureb", emw.getImageStr("C:javafx\\3.jpg"));
emw.createWord(dataMap, "text.ftl", "C:poi\\测试.doc");
}
}
map可以根据实际情况再具体组织,调用即可。
环境等方面的不同,实际情况再具体调整代码,但整体思路差不多。