时效提示:本文写于 2020 年,部分 API、配置和工具版本可能已经变化,参考时请以官方最新文档为准。
需求场景
这个需求对于ERP或者银行项目还是比较常见的,用户需要下载word文件or在线预览 -> 打印合同,表格 文件等。
本次需求有 1.文档中的字符串替换 2.表格生成 3. 图片插入替换 4. 批量插入图片
技术方案
-
模板 + Word XML 文档(*.xml) -> 生成xml文件后修改后缀为
.doc -
docx4j 直接操作
*.docx:把 .docx(本质是 zip 包里的 OOXML)解析成 Java 对象树来读写,能精细控制样式、表格、页眉页脚,也支持导出 PDF。功能最全,但 API 比较底层,简单的占位符替换用它偏重。资料:docx4j 官网、GitHub plutext/docx4j。 -
XWPFTemplate(poi-tl):基于 Apache POI 的 Word 模板引擎,核心类就是
XWPFTemplate。在 .docx 模板里写{{name}}这样的标签,代码里传一个 Map 即可渲染,内置文本、图片、表格、列表、循环等能力,中文文档完善,“模板 + 数据”场景比方案一更省事,也直接生成 .docx。资料:poi-tl 中文文档、GitHub Sayi/poi-tl。
实现讲解
技术方案一:
模板 + Word XML 文档(*.xml) -> 生成xml文件后修改后缀为 .doc
技术准备
其中模板语言选用的是freemarker. 也可以使用jsp,velocity,thymeleaf等。 本文选用freemarker的原因在于文档较多,技术也比较老,大家都应该会一点点。
freemarker 语法简介: Freemarker 语法详解
如果需要用到输出转义 -> ${object?html}
步骤一
-
编辑word文档,将其中需要动态替换的字符串->
${xxx} -
需要动态替换的图片处理好(一个位置一个不同的图片哦,如果相同,word只会存储一份)
-
表格处理,需要for处理的表格,处理为两行,方便后期用模板语言处理
步骤二
将word文件另存为:

步骤三
编辑xml文件,查询${xxx}是否完整,没有错位
- 动态替换的图片的内存存储在 binarydata中,进行替换
public static String getImageStr(InputStream in) {
byte[] data = null;
try {
data = new byte[in.available()];
in.read(data);
in.close();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);
} catch (IOException e) {
log.error("获取图片Str失败", e);
}
return "";
}
其中批量插入图片 -> 使用freemarker导出word并动态插入多张图片
-
表格需要找到相关对称的地方,用freemarker
<#list>语法处理即可 -
文件处理完毕 输出为后缀为
.doc文件即可
项目中个人Freemarker配置
configuration.setDefaultEncoding("utf-8");
//允许对象不存在
configuration.setClassicCompatible(true);
//不对数字进行格式化
configuration.setNumberFormat("0");
注意点
- 比如你用到了 word 华文仿宋GB2312字体,一定要看自己电脑是否装了这个字体,否则符号 数字 等会分割开,
${xxx}在xml中会分隔开,达不到替换的目的

- 早期的WPS可能不支持 word.doc 升级下wps,而不是单纯的换技术
小结
方案一(Freemarker + Word XML):零额外依赖,适合格式固定的老项目;产物是 .doc,Word 打开时依赖本机字体,见上文注意点。
方案二(docx4j):需要程序化精细控制文档结构时选它。
方案三(poi-tl):新项目做“模板填充”时的首选,直接生成 .docx。