java利用Freemarker模板生成docx格式的word文档
利用Freemarker模板生成docx
思路
1.把docx文档修改为ZIP格式(修改.docx后缀名为.zip) 2.获取zip里的document.xml文档以及_rels文件夹下的document.xml.rels文档 3.把内容填充到document.xml里 4.在输入docx文档的时候把填充过内容的的 document.xml用流的方式写入zip(详见下面代码)。 5.输出docx文档 docx模板修改成zip格式后的信息如下(因为word文档本身就是ZIP格式实现的)
- document.xml里存放主要数据
处理流程
1.准备好docx模板
2.把docx文档修改为ZIP格式(修改.docx后缀名为.zip)
3.获取zip文件里的word文件夹下的document.xml文件作为模板。
4.填充模板信息。
5.输出word测试
代码
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.WordUtils;
import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
@Slf4j
public class DocUtils {
public static void main(String[] args) {
OutputStream outputStream = null;
try {
outputStream= new FileOutputStream("e:/test.docx");
Map dataMap = new HashMap();
dataMap.put("ah","1231231");
dataMap.put("dsrmc","456");
createDocx(dataMap,outputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
}
}
//outputStream 输出流可以自己定义 浏览器或者文件输出流
public static void createDocx(Map dataMap, OutputStream outputStream) {
ZipOutputStream zipout = null;
try {
//内容模板
ByteArrayInputStream documentInput = getFreemarkerContentInputStream(dataMap);
//最初设计的模板
File docxFile = new File("E:\\template.docx");
if (!docxFile.exists()) {
docxFile.createNewFile();
}
ZipFile zipFile = new ZipFile(docxFile);
Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
zipout = new ZipOutputStream(outputStream);
//开始覆盖文档------------------
int len = -1;
byte[] buffer = new byte[1024];
while (zipEntrys.hasMoreElements()) {
ZipEntry next = zipEntrys.nextElement();
InputStream is = zipFile.getInputStream(next);
if (next.toString().indexOf("media") < 0) {
zipout.putNextEntry(new ZipEntry(next.getName()));
//如果是word/document.xml由我们输入
if ("word/document.xml".equals(next.getName())) {
if (documentInput != null) {
while ((len = documentInput.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
documentInput.close();
}
} else {
while ((len = is.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
is.close();
}
}
}
} catch (Exception e) {
log.error("word导出失败:",e);
}finally {
if(zipout!=null){
try {
zipout.close();
} catch (IOException e) {
log.error("io异常");
}
}
if(outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
log.error("io异常");
}
}
}
}
/**
* 获取模板字符串输入流
* @param dataMap 参数
* @return
*/
public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap) {
ByteArrayInputStream in = null;
try {
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());
String templateStr= FileUtil.readString(new File("E:\\document.xml"),"utf-8");
Template template = engine.getTemplate(templateStr);
String result = template.render(dataMap);
//这里一定要设置utf-8编码 否则导出的word中中文会是乱码
in = new ByteArrayInputStream(result.getBytes("utf-8"));
} catch (Exception e) {
log.error("模板生成错误!");
}
return in;
}
}