ftl模板创建
使用word软件创建带图片和表格的doc
注意:这里表格中的值暂时不要写成 形式,防止保存模板为 x m l 格式后,解析出错,等到保存为 x m l 格式后,在 x m l 文件中替换成 {}形式,防止保存模板为xml格式后,解析出错,等到保存为xml格式后,在xml文件中替换成 形式,防止保存模板为xml格式后,解析出错,等到保存为xml格式后,在xml文件中替换成{}形式即可。
将word模板转换为xml格式
使用在线工具格式化xml,方便查看xml
https://www.bejson.com/
处理表格
在xml中找到你填入表格中的值,将值替换成${}形式,如下图:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
处理图片
如果是单张图片
直接搜索<pkg:binaryData>
标签,将其中的base64图片编码替换成${img}
注意,创建word文件时,建议先不要放大图片,否则base64编码会很长,不好替换
如果是多张图片,比较麻烦点,需要替换三个地方
1. <pkg:binaryData>标签中的base64编码替换
2. Relationship标签
,xml文件中搜索relationships/image
注意:此处的Target属性值要和
<pkg:binaryData>
标签中pkg:name属性值中的图片名称一致;
3. 搜索关键词<v:imagedata
注意,此处的
r:id
属性值要和Relationship
标签中的Rid
属性值一致;这里多张图片是会横向排列在一起的,想要换行需要使用
<w:p w:rsidR="00A82B52" w:rsidRPr="00CB725B" w:rsidRDefault="00CC1725" w:rsidP="00CB725B"><w:pPr><w:pStyle w:val="a5"/></w:pPr></w:p>
图片尺寸设置
此处图片单位为pt,可以在代码中获取到图片的宽高之后,这里使用
${width}
和${height}
替换即可。
搞完之后,将xml文件后缀改为ftl
后端代码(这里暂时没做文件下载,只是生成到指定文件夹,想要做成文件下载可以自己修改)
注意:我这里的需求是循环创建表格和图片
package com.cmx.freemarker;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.*;
/**
* 使用Freemarker自动生成Word文档
*
* @author CMX
* @version 1.2.1
* @date 2024-05-24
**/
public class WordGenerateUtils {
/**
* 使用Freemarker自动生成Word文档
*
* @param dataMap 保存Word文档中所需要的数据
* @param templatePath 模板文件的绝对路径
* @param templateFile 模板文件的名称
* @param generateFile 生成文件的路径+名称
*/
public static void generateWord(Map<String, Object> dataMap, String templatePath, String templateFile, String generateFile) {
// 设置FreeMarker的版本
Configuration configuration = new Configuration(new Version("2.3.7"));
// 设置Freemarker的编码格式
configuration.setDefaultEncoding("UTF-8");
Writer out = null;
try {
// 设置FreeMarker生成Word文档所需要的模板的路径
configuration.setDirectoryForTemplateLoading(new File(templatePath));
// 设置FreeMarker生成Word文档所需要的模板名称
Template t = configuration.getTemplate(templateFile, "UTF-8");
// 创建一个Word文档的输出流
File file = new File(generateFile);
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
//FreeMarker使用Word模板和数据生成Word文档
t.process(dataMap, out);
} catch (Exception e) {
e.printStackTrace();
}
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//获取导出文件路径
//获取当前项目resource绝对路径
String resourcePath = getResourcePath();
String resourceGenerateFileName = resourcePath + "\\word\\生成word.docx";
//获取模板文件的绝对路径
//注意:通过ClassLoader获取模板文件的绝对路径,获取的是target目录下的template文件夹下的文件,不是src目录下的template文件夹下的文件
ClassLoader classLoader = WordGenerateUtils.class.getClassLoader();
URL resource = classLoader.getResource("template/带表格图片freemarker模板.ftl");
assert resource != null;
String path = resource.getPath();
String templatePath = path.substring(0, path.lastIndexOf("/"));
String templateFile = "带表格图片freemarker模板.ftl";
generateWord(getTextData(), templatePath, templateFile, resourceGenerateFileName);
}
private static Map<String, Object> getTextData() {
/*
* 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
*/
List<Map<String, Object>> dataList = new ArrayList<>();
String imgPath = WordGenerateUtils.class.getClassLoader().getResource("image/3.jpg").getPath();
String imageBase64 = getImageBase64(imgPath);
Map<String, Object> dataMap1 = new HashMap<>();
dataMap1.put("name", "卢本伟");
dataMap1.put("age", "20");
dataMap1.put("img", imageBase64);
dataMap1.put("imageName", "img1");
dataMap1.put("title", "5.1 表格1");
Map<String, Object> dataMap2 = new HashMap<>();
dataMap2.put("name", "pdd");
dataMap2.put("age", "20");
dataMap2.put("img", imageBase64);
dataMap2.put("imageName", "img2");
dataMap2.put("title", "5.1 表格2");
dataList.add(dataMap1);
dataList.add(dataMap2);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("dataList", dataList);
return resultMap;
}
public static String getImageBase64(String imagePath) {
try (InputStream inputStream = new FileInputStream(imagePath)) {
byte[] imageBytes = toByteArray(inputStream);
return Base64.getEncoder().encodeToString(imageBytes);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static byte[] toByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
}
public static String getResourcePath() {
// 获取当前项目的根目录
String projectRootPath = Paths.get(System.getProperty("user.dir")).toAbsolutePath().toString();
//这里获取到的根目录是项目目录,也就是others目录,子模块other需要手动加上
return Paths.get(projectRootPath, "other", "src", "main", "resources").toString();
}
}
注意我项目结构(有父模块和子模块)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传