首先我们要了解doc和docx两种word文件的相同点和不同点,为什么ftl可以直接生成doc而生成docx就会报错。
1.doc和docx文件构成
2.为什么ftl能直接转成doc而不能直接转成docx
3.docx文件格式解析
选一个word文件作为输出模板,然后java代码输出需要提取word压缩包里两个文件:
1.word路径下的document.xml
2.word路径下_rels下的document.xml.rels
将docx文件的后缀改为.zip之后,把word路径下的document.xml作为模板,可通过格式化工具把xml文件里的数据格式化,点开后编写word的xml内容,下图以一个段落为例,其他类型请自行参考openxml语法或自己在word中对应
编写完xml模板之后,进入代码开发阶段,
1.同ftl生成doc一样,第一步要先封装数据到一个map中
2.指定输出docx的文件路径
3.指定两个从word压缩包中提取的文件路径
4.执行输出
代码示例如下:
//封装数据Map<String,Object> dataMap=new HashMap<>();dataMap.put("title","示例");//key名对应xml模板里的freemaker标签//输出docx的模板String originalTemplate = tempPath+ File.separator+"needsOriginalTemplate.docx";//word中提取的两个文件,代码中可以根据实际情况更改名字String documentXmlRels = "document.xml.rels";String document = "document.xml";//执行输出Xml2DocxUtil.Xml2Docx(outFile,dataMap,document,documentXmlRels,originalTemplate);
下方附上 Xml2DocxUtil.java 以及FreeMarkUtils.java
Xml2DocxUtil.java
import cn.hutool.core.io.FileUtil;import java.io.*;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;public class Xml2DocxUtil {/**** @param outFile 输出文件* @param dataMap 数据* @param document 模板文件* @param documentXmlRels 模板关联文件* @param originalTemplate 模板原始docx文件* @return retMap succ 是否成功 true & false ; msg返回异常信息*/public static Map<String,Object> Xml2Docx(File outFile, Map<String,Object> dataMap, String document, String documentXmlRels, String originalTemplate){Map<String,Object> retMap = new HashMap<>();retMap.put("succ",true);ZipOutputStream zipout = null;OutputStream outputStream = FileUtil.getOutputStream(outFile);try {//图片配置文件模板ByteArrayInputStream documentXmlRelsInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, documentXmlRels);//内容模板ByteArrayInputStream documentInput = FreeMarkUtils.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);if (next.toString().indexOf("media") < 0) {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();retMap.put("succ",false);retMap.put("msg",e.getMessage());}finally {if(zipout!=null){try {zipout.close();} catch (IOException e) {e.getStackTrace();retMap.put("succ",false);retMap.put("msg",e.getMessage());}}if(outputStream!=null){try {outputStream.close();} catch (IOException e) {e.getStackTrace();retMap.put("succ",false);retMap.put("msg",e.getMessage());}}}return retMap;}
}
FreeMarkUtils.java
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;import java.util.Map;public class FreeMarkUtils {private static Logger logger = LoggerFactory.getLogger(FreeMarkUtils.class);public static Configuration getConfiguration(){//创建配置实例Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);//设置编码configuration.setDefaultEncoding("utf-8");configuration.setClassForTemplateLoading(FreeMarkUtils.class, "/templates/needsFileTemplates/");return configuration;}/*** 获取模板字符串输入流* @param dataMap 参数* @param templateName 模板名称* @return*/public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap, String templateName) {ByteArrayInputStream in = null;try {//获取模板Template template = getConfiguration().getTemplate(templateName);StringWriter swriter = new StringWriter();//生成文件template.process(dataMap, swriter);in = new ByteArrayInputStream(swriter.toString().getBytes(StandardCharsets.UTF_8));//这里一定要设置utf-8编码 否则导出的word中中文会是乱码} catch (Exception e) {e.printStackTrace();logger.error("模板生成错误!");}return in;}
}
欢迎大家评论区进行交流,之后会发表一篇如何通过java在docx的word文件中插入一个docx格式的word文件的文章。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态