Java使用FreeMarker自动生成word文档(可遍历生成多张图片)
- 前言:最近项目中后台需要自动生成word文档,我以前也没做过,就百度了下,发现还是用freemarker生成word文档最快,但是试了网上的一些方法,都没成功,最后参考着多篇文章慢慢摸索最终成功了。在这记录一下。
- 需要实现的效果图

- 首先,导入Jar包依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
- 制定模板

注意:这一步图片都先别用占位符,因为用占位符就不知道这是图片了(我这种方式我认为是这样的,因为我试过用图片先用占位符,发现一直生成不了图片)
- 将模板另存为xml

生成xml时,图片全部被转成base64了,这时候需要删除掉,用占位符${user.photo}


- 然后直接重命名,将文件格式改为ftl
- 接下来需要修改ftl,因为我需要遍历循环生成标题和图片(重点)



8.至此,模板已经制作完成,下面写代码
package com.chinobot.util.util;
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.setClassForTemplateLoading(WordUtil.class, "/templates/code");
// 设置FreeMarker生成Word文档所需要的模板
Template t = configuration.getTemplate("zs.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();
}
}
package com.chinobot.util.util;
import org.springframework.util.StringUtils;
import org.apache.commons.codec.binary.Base64;
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();
}
return Base64.encodeBase64String(data);
}
}
package com.chinobot.util.util;
import com.chinobot.util.util.WordUtil;
import com.chinobot.wordxml.entity.FileXml;
import com.chinobot.wordxml.entity.RecordXml;
import com.chinobot.wordxml.entity.UserXml;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Java使用FreeMarker生成Word文档主程序
*/
public class WordApplication {
public static void main(String[] args) throws Exception {
/**
* 自动生成Word文档
* 注意:生成的文档的后缀名需要为doc,而不能为docx,否则生成的Word文档会出错
*/
WordUtil.generateWord(getDate(), "d:\\home\\tem\\user3.doc");
}
private static Map<String, Object> getDate(){
Map<String, Object> dataMap = new HashMap<>();
UserXml user = new UserXml();
user.setRealName("李红");
user.setPhoto(ImageUtil.getImageBase64String("d:\\home\\tem\\1.jpg"));
user.setDateOfBirth("2020-05-11");
user.setAge("44");
user.setNation("汉族");
user.setGender("女");
user.setIdNumber("362532199812171215");
user.setInboundTime("2020-25-12");
user.setInboundWay("康宁医院");
user.setInBeds("5号床位");
user.setPhysicalConditions("健康");
user.setMentalState("正常");
user.setAddress("广东省深圳市宝安区西乡街道");
user.setCensusMessage("广东省深圳市");
user.setMessageCollect("指纹");
user.setPushChannel("让爱回家 | i深圳");
dataMap.put("user",user);
RecordXml record = new RecordXml();
record.setTitle("线索记录");
List<String> messagelist = new ArrayList();
messagelist.add("第一行");
messagelist.add("第二行");
record.setMessageList(messagelist);
RecordXml record2 = new RecordXml();
record2.setTitle("回复记录");
List<String> messagelist2 = new ArrayList();
messagelist2.add("第三行");
messagelist2.add("第四行");
record2.setMessageList(messagelist2);
List<RecordXml> recordList = new ArrayList<>();
recordList.add(record);
recordList.add(record2);
dataMap.put("messList",recordList);
FileXml file = new FileXml();
file.setTitle("图1 测试标题");
file.setPic(ImageUtil.getImageBase64String("d:\\home\\tem\\4.png"));
FileXml file2 = new FileXml();
file2.setTitle("图2 测试标题2");
file2.setPic(ImageUtil.getImageBase64String("d:\\home\\tem\\3.jpg"));
List<FileXml> fileList = new ArrayList<>();
fileList.add(file);
fileList.add(file2);
dataMap.put("fileList",fileList);
return dataMap;
}
}
- 至此,就已经结束了,当然以上实体类中的属性必须全部不能为空,否者就会报错。
解决方案:给为空的一个默认值 ${(user.inStationNumber)!’’}
集合也需要做判断
结束!

本文档介绍了如何使用Java结合FreeMarker模板引擎来动态生成包含多张图片的Word文档。通过设置模板,将图片转为base64编码并替换占位符,实现了遍历循环生成标题和图片的功能。文章详细讲解了每个步骤,包括模板的创建、XML到FTL的转换,以及代码实现过程。
1790

被折叠的 条评论
为什么被折叠?



