Java使用FreeMarker自动生成Word文档
在项目开发中有一需求要将采集的数据填入word表格中,效果如下。本文记录了使用freemaker完成此功能的过程。
1、创建word模板
使用word创建名为template.docx的文档,内容如下:
说明:
- 模板文档中${}是占位符,即生成Word文档时占位符会被真实的数据替换。例如${name}在生成文档时会被name这个属性的值替换 ,${info.title}在生成文档时会被info这个对象的title属性的值替换
- 如果要在word中包含图片,由于要在生成的Word文档中自动插入一张图片,因此,需要在模板文档中插入一张图片作为占位符。
2、转换为模板文档
使用Word将模板文档另存为Word XML 文档(*.xml)格式,转换后生成template.xml模板文档。使用文本编辑器打开,可以借助xml在线格式化工具(http://www.bejson.com/otherformat/xml/)进行格式化。
打开格式化后的.xml文档可以发现,Word在转换时会自动的将占位符分开,因此需要把占位符之间多余的部分删除掉。如下:
修改为如下:
模板文档在转换成xml格式时,图片的内容会被转换成很长的16进制的字符串。将《pkg:binaryData》《/pkg:binaryData》标签中16进制字符串形式的图片内容替换成${info.image}占位符。
如果需要循环遍历添加内容,则需要使用如下标签:<#list userList as user> </#list>
经过上述处理后,将.xml模板文档进行保存,并直接修改后缀名为ftl,即:template.ftl。
3、创建java程序
-
引入maven依赖
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency>
-
工具类如下:
import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.Version; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Map; /** * Word文档工具类 */ public class WordUtil { /** * 使用FreeMarker自动生成Word文档 * @param dataMap 生成Word文档所需要的数据 * @param fileName 生成Word文档的全路径名称 */ public static void generateWord(Map<String, Object> dataMap, String fileName) throws Exception { // 设置FreeMarker的版本和编码格式 Configuration configuration = new Configuration(new Version("2.3.28")); configuration.setDefaultEncoding("UTF-8"); // 设置FreeMarker生成Word文档所需要的模板的路径 configuration.setDirectoryForTemplateLoading(new File("E:/Word/Template/")); // 设置FreeMarker生成Word文档所需要的模板 Template t = configuration.getTemplate("WordTemplate.ftl", "UTF-8"); // 创建一个Word文档的输出流 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(fileName)), "UTF-8")); //FreeMarker使用Word模板和数据生成Word文档 t.process(dataMap, out); out.flush(); out.close(); } } import org.springframework.util.StringUtils; import sun.misc.BASE64Encoder; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 图片工具类 */ public class ImageUtil { /** * 将图片内容转换成Base64编码的字符串 * @param imageFile 图片文件的全路径名称 * @return 转换成Base64编码的图片内容字符串 */ public static String getImageBase64String(String imageFile) { if (StringUtils.isEmpty(imageFile)) { return ""; } File file = new File(imageFile); if (!file.exists()) { return ""; } InputStream is = null; byte[] data = null; try { is = new FileInputStream(file); data = new byte[is.available()]; is.read(data); is.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } }
-
启动类如下:
public static void main(String[] args) throws Exception { /** * 自动生成Word文档 * 注意:生成的文档的后缀名需要为doc,而不能为docx,否则生成的Word文档会出错 */ WordUtil1.generateWord(getWordData(), "E:/User44.doc"); } /** * 获取生成Word文档所需要的数据 */ private static Map<String, Object> getWordData() { /* * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中 */ Map<String, Object> dataMap = new HashMap<>(); DataInfo info = new DataInfo(); //..... info.setContent("心的儿子就是福气。\n"); infoList.add(info); DataInfo info2 = new DataInfo(); //.... infoList.add(info2); dataMap.put("infoList", infoList); return dataMap; }
4、参考文章
https://blog.csdn.net/weixin_44516305/article/details/88049964
https://blog.csdn.net/qq_39507330/article/details/80350596
注:暂未解决循环插入多张图片的问题。
既要仰望星空,又要脚踏实地