本文主要记录FreeMarker生成wore文档并导出的操作。
FreeMarker简介
FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。
详情可以通过官网进行一个初步认识:
freemarker.apache.org/
1. 制作word样板
新建一个word,构建需要导出的内容,如下:
2.生成xml文件
word布局构建好后,将word另存为xml文件
3.格式化xml文件
模板xml文件生成后,可以通过一些xml工具进行格式化,我这里使用的时idea,将xml文件复制到idea中并打开
ctrl
+
alt
+
l
快捷键进行格式化。
4.编辑xml文件,添加占位符
doc转xml的格式不需要过于深入了解,我们只需要在
<w:body></w:body>
标签中找到需要动态加载数据添加占位符就行了。占位符写法为
${key}
,该
key
对应后端的key值。效果如下:
5.编辑xml文件格式ftl
直接修改文件后缀名即可。
后端代码实现
导出工具类
public class WordUtils {
private static Configuration configuration = null;
private final static String templateFolder = "";
static {
configuration = new Configuration(Configuration.VERSION_2_3_0);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(WordUtils.class, "/templates");
* 导出word
* @param request
* @param response
* @param title 导出的文件名称
public static void export(HttpServletRequest request, HttpServletResponse response, Map<?, ?> map, String title, String templateName) {
OutputStream out = null;
File file = null;
InputStream fin = null;
try {
Template freemarkerTemplate = configuration.getTemplate(templateName);
file = createDoc(map, freemarkerTemplate);
fin = new FileInputStream(file);
String userAgent = request.getHeader("USER-AGENT");
if (!StringUtils.contains(userAgent, "Mozilla")) {
title = URLUtil.encode(title, "UTF-8");
response.setContentType("application/msword");
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Content-Disposition", "attachment;filename=" + title + ".doc");
out = response.getOutputStream();
byte[] buffer = new byte[512];
int bytesToRead = -1;
while ((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
fin.close();
file.delete();
} catch (NullPointerException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
* 创建word文档
* @param dataMap
* @param template
* @return
public static File createDoc(Map<?, ?> dataMap, Template template) {
String name = System.currentTimeMillis() + ".doc";
File f = new File(name);
Template t = template;
try {
Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "utf-8"));
t.process(dataMap, w);
w.close();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
throw new RuntimeException(ex);
return f;
action
Map<String,Object> data = new HashMap<>();
data.put("text1","张三");
data.put("text2","男");
data.put("text3","18");
data.put("text4","广东");
data.put("text5","6级");
data.put("text6","3年");
data.put("text7","15215215201");
data.put("text8","hellow@word.com");
List<String> list = new ArrayList<>();
list.add(ImageUtils.getImageBase("E:\lsy_data\img\1.png"));
list.add(ImageUtils.getImageBase("E:\lsy_data\img\2.png"));
list.add(ImageUtils.getImageBase("E:\lsy_data\img\3.png"));
list.add(ImageUtils.getImageBase("E:\lsy_data\img\4.png"));
data.put("images",list);
WordUtils.export(request,response,data,"测试","test1.ftl");
带图片导出
word导出的过程中,图片是比较常见的元素,这里记录下自己通过freeMarker导出word带图片的踩坑的记录。
在模板中添加图片占位符,如上面的模板所示。此时的模板上会有一个base64的字符串,这个就是刚刚添加在模板中的图片占位。
上面的图片base64字符串替换成${key}
,${key}
后端获取的图片(base64格式),如果是多张图片的使用循环来遍历,如:<#list images as item>
,注意<pkg:part>
标签中的pkg:name
图片名称必须不一样,要不然会一直加载到第一张的图片。
动态添加公共资源,在xml模板中找到你<pkg:xmlData>
标签。注意,这里的id不能重复,且Tatget的属性的图片名称需保持跟第二步设置的一致
完成上面步骤后,我们只要找到图片占位符的区域,进行数据遍历即可。
![1SZZ@N2{8ONG7D4_UEVJ56.png
图片导出的时候如果是多张的,最后先排好版,避免导出word的时候图片位置错乱
遍历图片的时候如果只显示一张,应该是部分参数是必须唯一的,这种情况下可以拿之前的word导出来的xml对面下,我就是这么操作的。