word模板生成,基于freemarker
创建word模板文档
文档的格式为docx,如果不是另存为docx文档
注意是word文档(.docx)
提取需要替换的文件
docx文档其实是zip格式的,修改后缀就可以看到文档里的实际内容
用压缩软件打开
里面的内容符合微软officeopenxml规范
会用到的文件:
- [Content_Types].xml 文件格式的声明,如果加入新的图片格式,需要再这里添加
- word/media 图片存储的文件夹
- word/_rels/document.xml.rels 文档图片的声明
- word/document.xml 文档的内容
创建freemarker模板
将word/_rels/document.xml.rels和word/document.xml复制并修改后缀名
替换一个标题
在模板里找到标题
渲染图片列表
处理图片引用
渲染
ImageVo.class
public class ImageVo {
private String id;
private String path;
private String name;
public ImageVo(String id,String name,String file){
this.id = id;
this.name = name;
this.path = file;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
word工具类
public class WordUtil {
private static final Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
static {
//设置编码
configuration.setDefaultEncoding("utf-8");
//ftl模板文件
configuration.setClassForTemplateLoading(WordUtil.class, "/template/");
}
public static void createWord(Map<String,Object> dataMap, String templateName, OutputStream outputStream) throws Exception{
//获取模板
Template template = configuration.getTemplate(templateName);
//生成文件
template.process(dataMap, new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)));
}
}
代码逻辑
public class Main {
private static final String outFile = "out.docx";
private static final List<ImageVo> imageVos = new LinkedList<>();
static {
String absolutePath = new ClassPathResource("image3.jpeg").getAbsolutePath();
imageVos.add(new ImageVo("image1","image20.jpeg",absolutePath));
imageVos.add(new ImageVo("image2","image21.jpeg",absolutePath));
imageVos.add(new ImageVo("image3","image22.jpeg",absolutePath));
imageVos.add(new ImageVo("image4","image23.jpeg",absolutePath));
}
public static void main(String[] args) {
Map<String,Object> params = new HashMap<>();
params.put("title","填入的标题");//标题
params.put("imageList",imageVos);//图片列表
//创建Zip流
try (ZipInputStream zipInputStream = new ZipInputStream(new ClassPathResource("template/template.docx").getStream());
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outFile));
) {
ZipEntry entryIn;
while ((entryIn = zipInputStream.getNextEntry()) != null) {
String entryInName = entryIn.getName();
ZipEntry entryOut = new ZipEntry(entryIn.getName());
zipOutputStream.putNextEntry(entryOut);
if ("word/_rels/document.xml.rels".equals(entryInName)) {
//处理图片引用
WordUtil.createWord(params, "rels.ftl", zipOutputStream);
} else if ("word/document.xml".equals(entryInName)) {
//填充word模板
WordUtil.createWord(params, "document.ftl", zipOutputStream);
} else {
//拷贝原始的字节
IoUtil.copy(zipInputStream, zipOutputStream);
}
zipOutputStream.closeEntry();
}
//写入图片
for (ImageVo imageVo : imageVos) {
ZipEntry e = new ZipEntry("word/media/" + imageVo.getName());
zipOutputStream.putNextEntry(e);
try (InputStream openStream = new FileInputStream(imageVo.getPath())) {
IoUtil.copy(openStream, zipOutputStream);
}
zipInputStream.closeEntry();
}
} catch (Exception e) {
throw new RuntimeException("导出异常");
}
}
}
生成的效果图
表格也是有一定的逻辑,可以自己探索一下