引入依赖
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
或者
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
java-web 生成word-doc样例
@RequestMapping(path="/test",produces="application/msword;charset=UTF-8")
public void test(HttpServletRequest request, HttpServletResponse resp) {
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
Map<String,Object> map = Maps.newHashMap();
map.put("prjName","N999-测试");
try {
// 调用工具类WordGenerator的createDoc方法生成Word文档
file = FreeMarkerGenerator.createDoc(map, "");
fin = new FileInputStream(file);
//resp.setCharacterEncoding("utf-8");
//resp.setContentType("application/msword");
// 设置浏览器以下载的方式处理该文件默认名为resume.doc
resp.addHeader("Content-Disposition", "attachment;filename=resume.doc");
out = resp.getOutputStream();
byte[] buffer = new byte[512]; // 缓冲区
int bytesToRead = -1;
// 通过循环将读入的Word文件的内容输出到浏览器中
while((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
if (fin != null){
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
if(file != null){
// 删除临时文件
file.delete();
}
}
}
private String fileNameHandle(HttpServletRequest request, String fileName) throws IOException{
String userAgent = request.getHeader("User-Agent");
byte[] bytes = userAgent.contains("MSIE") ? fileName.getBytes() : fileName.getBytes("UTF-8");
// 各浏览器基本都支持ISO编码
String name = new String(bytes, "ISO-8859-1");
return name;
}
}
public class FreeMarkerGenerator {
private static Configuration configuration = null;
private static Map<String, Template> allTemplates = null;
static {
configuration = new Configuration(Configuration.VERSION_2_3_30);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(FreeMarkerGenerator.class, "/template/");
allTemplates = new HashMap<>();
try {
allTemplates.put("资管四部保险金信托信托管理报告", configuration.getTemplate("资管四部保险金信托信托管理报告.ftl"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private FreeMarkerGenerator() {
throw new AssertionError();
}
/**
* 生成docx
* @param dataMap
* @param type
* @return
*/
public static File createDoc(Map<?, ?> dataMap, String type) {
String name = "temp" + (int) (Math.random() * 100000) + ".docx";
File f = new File(name);
Template t = allTemplates.get(type);
try {
// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
t.process(dataMap, w);
w.close();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return f;
}
}
根据模板doc 制作生成目标doc:
doc模板填充 ${} -->另存为 open2003xml -> 格式化xml,修改${}处的错乱格式 -->修改后缀为ftl
生成docx
package com.ct.wms.util;
/**
* Copyright Citic Trust, 2021 中信信托有限公司,版权所有 2021
* tae5Le2Choh5see2rieshaiQuooGhe7eeth0yahg3ud6eeb1ahsha6eloh2aiYai
*
* @date: 2021/7/1
* @author: liuqiang
*/
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.io.*;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Snowflake;
import lombok.extern.slf4j.Slf4j;
/**
* https://blog.csdn.net/yuchenff/article/details/103660953
* 生成docx后缀的文档
*/
@Slf4j
public class Xml2DocxUtil {
private static Snowflake snowflake = new Snowflake(1,1);
/**
* @param outFile 输出文件
* @param dataMap 数据
* @param document 模板文件
* @param documentXmlRels 模板关联文件
* @param originalTemplate 模板原始docx文件
* @return 是否成功 true :success & false:fail ;
*/
public static boolean Xml2Docx(File outFile, Map<String, Object> dataMap, String document, String documentXmlRels, File originalTemplate) {
ZipOutputStream zipout = null;
OutputStream outputStream = FileUtil.getOutputStream(outFile);
try {
//图片配置文件模板
ByteArrayInputStream documentXmlRelsInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, documentXmlRels);
//内容模板
ByteArrayInputStream documentInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, document);
ZipFile zipFile = new ZipFile(originalTemplate);
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);
zipout.putNextEntry(new ZipEntry(next.getName()));
if (next.getName().indexOf("document.xml.rels") > 0) { //如果是document.xml.rels由我们输入
if (documentXmlRelsInput != null) {
while ((len = documentXmlRelsInput.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
documentXmlRelsInput.close();
}
} else if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入
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) {
e.getStackTrace();
return false;
} finally {
if (zipout != null) {
try {
zipout.close();
} catch (IOException e) {
e.getStackTrace();
return false;
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.getStackTrace();
return false;
}
}
}
return true;
}
/**
* @param dataModel 数据
* @return 文件
*/
public static File Xml2Docx(Object dataModel, String templateName) {
String dataModelStr = JSON.toJSONString(dataModel, SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullListAsEmpty);
log.info("dateModelJsonStr:{}",dataModelStr);
//字符串转map
JSONObject jsonObject = JSONObject.parseObject(dataModelStr);
Map<String,Object> dataMap = (Map<String,Object>)jsonObject;
String name = "temp" + snowflake.nextId() + ".doc";
File outFile = new File(name);
ZipOutputStream zipout = null;
OutputStream outputStream = FileUtil.getOutputStream(outFile);
try {
//图片配置文件模板
ByteArrayInputStream documentXmlRelsInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, templateName + ".xml.rels");
//内容模板
ByteArrayInputStream documentInput = FreeMarkerGenerator.getFreemarkerContentInputStream(dataMap, templateName + ".xml");
ClassLoader classLoader = Xml2DocxUtil.class.getClassLoader();
URL url = classLoader.getResource("template/" + templateName + ".docx");
/**
* url.getFile() 得到这个文件的绝对路径
*/
File originalTemplate = new File(url.getFile());
ZipFile zipFile = new ZipFile(originalTemplate);
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);
zipout.putNextEntry(new ZipEntry(next.getName()));
if (next.getName().indexOf("document.xml.rels") > 0) { //如果是document.xml.rels由我们输入
if (documentXmlRelsInput != null) {
while ((len = documentXmlRelsInput.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
documentXmlRelsInput.close();
}
} else if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入
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) {
e.getStackTrace();
return outFile;
} finally {
if (zipout != null) {
try {
zipout.close();
} catch (IOException e) {
e.getStackTrace();
return outFile;
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.getStackTrace();
return outFile;
}
}
}
return outFile;
}
}