Java通过Freemarker生成docx文件
一:doc和docx文件
首先我们要了解doc和docx两种word文件的相同点和不同点,为什么ftl可以直接生成doc而生成docx就会报错。
1.doc和docx文件构成
- 我们可以把doc格式的word文件当成是一个单独的xml文件,而docx当成一个zip压缩包。将一个docx文件的后缀名改成.zip,然后用压缩工具打开,显示的即为docx的目录结构。
2.为什么ftl能直接转成doc而不能直接转成docx
- ftl生成word文件的过程是通过java选定一个*.ftl模板文件(该ftl模板是通过doc文件另存为xml格式,然后把后缀改为ftl得到),加入map参数集合,调用freemaker组件,生成一个doc格式的word文件。
- 综合前边概念,我们可以得出结论,freemaker只能通过模板生成一个doc格式的独立文件,而无法得到docx所需要的zip格式,所以ftl无法直接生成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文件的文章。
Java通过Freemarker生成docx文件相关推荐
- Java使用freemarker生成word文件
首先声明我的项目是一个web项目,生成的word文件直接通过response响应发送给前端.如果不是web项目的话可以像网上的其他教程一样将生成的word保存在本地. 要利用freemarker生成w ...
- Java通过freemarker生成pdf文件并盖章
Java代码生成pdf回执文件,直接上代码: package com.pdf;import java.io.BufferedWriter; import java.io.File; import ja ...
- Java使用freemarker生成word文档并转pdf文档
Java使用freemarker生成word文档后转pdf 先来看看效果图 进入正题 项目需求: 为订单后生成对应的pdf文档,文档内包含图片. 方案一:使用freemarker和itext把html ...
- HTML生成PDF模板(Java iText+FreeMarker生成PDF(HTML转PDF))
Java iText+FreeMarker生成PDF(HTML转PDF) 1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打 ...
- 若依 springboot 使用freemarker生成word文件,并导出下载
目录 freemarker生成word文件并导出 一.环境准备 二.编写代码 1.实体类 2.mapper.xml文件 3.mapper.java文件 4.Service.java 5.Service ...
- eclipse编译java项目class文件_动态编译 Java 代码以及生成 Jar 文件
导读: 最近在看 Flink 源码的时候发现到一段实用的代码,该代码实现了 java 动态编译以及生成 jar 文件.将其进行改进后可以应用到我们的平台上,实现在平台页面上编写 java 代码语句,提 ...
- JAVA 根据模板生成doc文件
JAVA 根据模板生成doc文件 需求 根据模板生成对应的doc文档,文档内容动态填充. 实现 1.将doc模板转换为ftl文件,放入项目中 1.1 首先将模板另存为xml文件 1.2 更改xml文件 ...
- java使用poi生成Excel文件并合并单元格
java使用poi生成Excel文件并合并单元格 业务需要根据 分管部门 字段进行合并,现在提供一种思路. controller层 @Inject(target = "/inf ...
- Freemarker生成word文件,打开后页眉和页脚图片不显示
Freemarker生成word文件,打开后页眉和页脚图片不显示 在我们开发过程中通常会把模板文件Ctrl+Alt+L格式化,方便处理.这样就造成word的标签格式产生多余的换行或者空白,但是word ...
最新文章
- 安装旧版本插件_iOS 应用降级插件,支持任意版本升降
- 【定时任务】quartz表达式Cron Expression解析
- 云计算相关资料/博客/网上收集的关于OpenStack的一些资源
- Grafana Prometheus 服务安装部署(Linux服务器监控)
- 计算机有什么著名基金经理排名,百万年薪的基金经理,都是什么专业出身?!...
- hdoj--5621--KK's Point(简单数学)
- Install-Package Ninject -Project SportsStore.WebUI
- goods购物表MySQL的代码_python采用sqlachmy购物商城
- 移动端适配的理解——REM方案
- Python机器学习经典实例
- Linux 线程———详解
- baymax平台导入任务错误日志报错: Please login with USER and PASS.
- 12月大学计算机二级考试时间,2020年12月计算机二级考试报名时间及考试安排
- 用python还需要stata吗_极冷知识点——Stata/Python/R自带数据导入(附代码)
- OTA 差分升级包的制作
- alertmanager集群搭建
- 中国航空公司特点机型
- 计划的主体部分应有哪些内容_计划主体部分包含哪些内容
- 信号系统一些基本概念
- VMware CentOS6.5 安装VMware Tools