优化原因:
使用ftl模板生成doc文档后,发现无法使用Microsoft Edge在线查看生成的文档,应客户需求实施优化措施:使用ftl模板生成docx文档。
参考文档:
使用FreeMarker导出docx格式word文档全过程(使用template模板)-CSDN博客
一、处理docx模板
1、修改模板后缀修改为zip,打开zip包,拿到word文件夹下的document.xml,修改为flt文件,并将文件放在src/main/resources/wordTemplate/document.ftl
2、使用Ctrl+Alt+L进行格式化,将【insert】使用${}填充
参考文档:字符串内建函数 - FreeMarker 中文官方参考手册 (foofun.cn)
3、将zip包下的所有文件放在src/main/resources/wordTemplate/模板下,后续会与新生成的document.xml重新打包
本地环境使用src/main/resources/wordTemplate/模板,但是部署上线的路径就不是这个了,所以最好的解决办法是将模板文件夹放在服务器固定位置。
String docxFolderPath = "";
String os = System.getProperties().getProperty("os.name");
if (os.startsWith("win") || os.startsWith("Win")) {
docxFolderPath = "admin\\src\\main\\resources\\wordTemplate\\模板";
} else if (os.startsWith("mac") || os.startsWith("Mac")) {
docxFolderPath = "admin/src/main/resources/wordTemplate/模板";
} else {
docxFolderPath = "/opt/admin/file/模板";
}
4、代码
public class WordUtil {
public static void createDocxWord(Map<String, Object> dataMap, String templateName, File file) {
try {
// 1. 配置 FreeMarker 模板引擎
Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
cfg.setClassForTemplateLoading(WordUtil.class, "/wordTemplate");
Template template = cfg.getTemplate(templateName);
// 2. 数据模型
// 3. 渲染模板生成 document.xml
StringWriter writer = new StringWriter();
template.process(dataMap, writer);
String xmlContent = writer.toString();
// 4. 将生成的 XML 和其他文件打包成 docx
ZipOutputStream zos = null;
String docxFolderPath = "admin\\src\\main\\resources\\wordTemplate\\模板";
try {
zos = new ZipOutputStream(new FileOutputStream(file));
// 添加渲染后的 document.xml 文件
zos.putNextEntry(new ZipEntry("word/document.xml"));
IOUtils.write(xmlContent, zos, "UTF-8");
zos.closeEntry();
// 添加其他必需的 DOCX 文件
addStaticFilesToZip(zos, docxFolderPath);
} catch (Exception e) {
throw new RRException("错误");
} finally {
if (null != zos) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void addStaticFilesToZip(ZipOutputStream zos, String docxFolderPath) throws IOException {
File folder = new File(docxFolderPath);
for (File file : folder.listFiles()) {
// 递归遍历目录,确保所有子目录的文件也被压缩进来
if (file.isDirectory()) {
addFolderToZip(file, zos, file.getName());
} else {
zos.putNextEntry(new ZipEntry(file.getName()));
try (FileInputStream fis = new FileInputStream(file)) {
IOUtils.copy(fis, zos);
}
zos.closeEntry();
}
}
}
// 递归方法:将目录及其子文件夹的内容压缩进 ZIP 文件
private static void addFolderToZip(File folder, ZipOutputStream zos, String parentFolder) throws IOException {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
addFolderToZip(file, zos, parentFolder + "/" + file.getName());
} else if (!file.getName().equals("document.xml")) {
zos.putNextEntry(new ZipEntry(parentFolder + "/" + file.getName()));
try (FileInputStream fis = new FileInputStream(file)) {
IOUtils.copy(fis, zos);
}
zos.closeEntry();
}
}
}
}
service调用
String fileName = "文档.docx";
try {
File tempFile = File.createTempFile("文档", ".docx");
WordUtil.createDocxWord(dataMap, "ducument.ftl", tempFile);
// 上传至OSS
String url = OSSFactory.build().uploadSuffix(FileUtils.openInputStream(tempFile), fileName);
//保存OSS文件信息
return ossEntity.getId();
} catch (Exception e) {
e.printStackTrace();
}