之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,生成的word占用的空间很大,几百页的word有将近100M了。所以,后面需求必须是生成的docx文档,结果导出后正常才几M,昨天花了一天的时间实现。

具体思路

1.把docx文档修改为ZIP格式(修改.docx后缀名为.zip)

2.获取zip里的document.xml文档以及_rels文件夹下的document.xml.rels文档

3.把内容填充到document.xml里,以及图片配置信息填充至document.xml.rels文档里

4.在输入docx文档的时候把填充过内容的的 document.xml、document.xml.rels用流的方式写入zip(详见下面代码)。

5.把图片写入zip文件下word/media文件夹中

6.输出docx文档

docx模板修改成zip格式后的信息如下(因为word文档本身就是ZIP格式实现的)

document.xml里存放主要数据

media存放图片信息

_rels里存放配置信息

注意:如果docx模板里的图片带有具体路径的话,则图片的格式不受限制。

如果docx模板里里图片信息不带路径,则模板仅支持和模板图片类型一致的图片。

处理流程

1.准备好docx模板

2.把docx文档修改为ZIP格式(修改.docx后缀名为.zip)

3.获取zip文件里的word文件夹下的document.xml以及_rels文件夹里的document.xml.rels文件作为模板。

注意:这里图片配置信息是根据 rId来获取的,为了避免重复,可以根据自己具体的业务规则来实现

4.填充模板信息、写入图片信息。

//outputStream 输出流可以自己定义 浏览器或者文件输出流

public static void createDocx(Map dataMap,OutputStream outputStream) {

ZipOutputStream zipout = null;

try {

//图片配置文件模板

ByteArrayInputStream documentXmlRelsInput =FreeMarkUtils.getFreemarkerContentInputStream(dataMap, documentXmlRels);

//内容模板

ByteArrayInputStream documentInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, document);

//最初设计的模板

File docxFile = new File(WordUtils.class.getClassLoader().getResource(template).getPath());

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()));

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();

}

}

}

//写入图片

List> picList = (List>) dataMap.get("picList");

for (Map pic : picList) {

ZipEntry next = new ZipEntry("word" + separator + "media" + separator + pic.get("name"));

zipout.putNextEntry(new ZipEntry(next.toString()));

InputStream in = (ByteArrayInputStream)pic.get("code");

while ((len = in.read(buffer)) != -1) {

zipout.write(buffer, 0, len);

}

in.close();

}

} catch (Exception e) {

logger.error("word导出失败:"+e.getStackTrace());

}finally {

if(zipout!=null){

try {

zipout.close();

} catch (IOException e) {

logger.error("io异常");

}

}

if(outputStream!=null){

try {

outputStream.close();

} catch (IOException e) {

logger.error("io异常");

}

}

}

}

/**

* 获取freemarker模板字符串

* @author lpf

*/

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, "/template");

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("utf-8"));//这里一定要设置utf-8编码 否则导出的word中中文会是乱码

} catch (Exception e) {

logger.error("模板生成错误!");

}

return in;

}

}

5.输出word测试

就是这么简单,比较麻烦的就是如果word比较复杂的话写freemarkr标签要仔细一些,还有word中的字符尽量对特殊字符有转义,否则会引起word打不开的现象。

总结

这里最重要的一个思想是把文件输出到ByteArrayOutputStream里,下载的时候把这个字节写出就行了。开发的时候注意编码问题,用这种方式导出还有一个好处就是,你会发现,同样一个word。导出doc格式的文件大小要比docx格式的文件大小大的多,所以还是推荐用这种;

java生成docx_java利用Freemarker模板生成docx格式的word文档相关推荐

  1. java利用Freemarker模板生成docx格式的word文档(全过程)

    参考汇总: wordexport: JAVA生成并导出Word文档技术论证 java利用Freemarker模板生成docx格式的word文档(全过程) - 旁光 - 博客园 # 参考资料 - 其他项 ...

  2. springboot结合Freemarker模板生成docx格式的word文档(附代码)

    首先参考的是这篇文章: java利用Freemarker模板生成docx格式的word文档(全过程) - 旁光 - 博客园参考:https://my.oschina.net/u/3737136/blo ...

  3. Django在线预览docx格式的word文档

    Django在线预览docx格式的word文档 第一步 明确功能是:预览word的docx文件. 具体实现是:在Django的模板文件中,定义预览方法:read_word2html from pydo ...

  4. java利用Freemarker模板生成格式友好的doc或者docx文档

    之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,不支持生成docx格式的文档.所以,这里补充一篇,生成docx或doc格式的文档以具体的docx模板或者doc模板为主. ...

  5. 利用Freemarker模板生成doc或者docx文档(转载整理)

    可以直接看主要代码实现 doc作为模板文件生成指定格式的doc文件 实现逻辑 1.把作为模板的doc文件另存为xml文件 2.凡是需要填充的数据用${xxxx}替代 3.利用Template类将数据填 ...

  6. freemarker 生成java_半自动化Java代码生成器[利用freemarker模板生成]

    rapid-generator 半自动化Java代码生成器[利用freemarker模板生成] 增加一些定制和扩展, 修改为基于MAVEN的格式. 整体架构保持不变. 增加的特性为: 支持表名前缀去除 ...

  7. Java项目中利用Freemarker模板引擎导出--生成Word文档

    应邀写的一篇文章:Java项目中利用Freemarker模板引擎导出--生成Word文档 资源下载:https://download.csdn.net/download/weixin_41367523 ...

  8. 利用 freemarker 模板生成 word 小结

    在企业级开发时,不可避免的会遇到生成 word 文档的需求,有两种常用的方案,1.使用 Apache POI 在后台通过代码生成 word 文档:2.使用模板生成 word 文档.第二种方法比较简单, ...

  9. Java 将xml模板动态填充数据转换为word文档

    需要用到的jar包: commons-codec-1.10.jar freemarker-2.3.21.jar jacob-1.6.jar 实现思路: 1.先将word文档另存为 : Word 200 ...

最新文章

  1. CloudStack 4.2 与CloudStack 4.1二级存储API发生变化
  2. nginx-1.13.x源码安装
  3. 运维小姐姐说这篇Consul集群和ACL配置超给力(保姆级)
  4. php 点对点,浅析点对点(End-to-End)的场景文字识别
  5. python中带附件发送电子邮件_python发送带附件邮件
  6. 中小企业集群ntpd服务搭建
  7. subversion的windows平台下载地址
  8. PHP的静态变量和引用函数
  9. 在html5水平边距属性hspace,HTML5 常用语法一览(列举不支持的属性)
  10. Capture One使用的几个小技巧
  11. 系统架构师论文-图书馆网络应用体系安全设计
  12. 关于Open函数的newline参数
  13. 厦大C语言上机 1413 模式匹配
  14. Python爬虫实战—vmgrils图片网站
  15. linux p4 环境配置,linux p4使用心得
  16. 给计算机老师的元旦祝福,送给老师的元旦祝福语
  17. 基于Nonebot2搭建QQ机器人(一)机器人环境配置
  18. 计算机会议期刊投稿,中国计算机学会推荐的投稿期刊和会议
  19. 系统特征根_20160204
  20. mysql 查询不重复的值_在 MySQL 中查询不重复记录值的方法

热门文章

  1. 电脑还原数据丢失的解决技巧
  2. HQChart使用教程2- 如何把自定义指标显示在K线图页面
  3. 小红书爆款标题怎么写?分享你一份爆款标题公式。
  4. HTML批量删除标记,批量删除LabelImg制作的.xml中的部分标签值(删除.xml的节点值)...
  5. golang量化投资数据接口是什么
  6. 山重水复疑无路,最快下降问梯度
  7. 基于STM32单片机温湿度一氧化碳(CO)浓度仿真设计
  8. 解决Win11安装PS2022版本卡顿闪退问题 win11安装Photoshop2022闪退卡顿问题解决方案
  9. 自动化测试之ios测试脚本
  10. 端口开通情况检测工具的阿里云服务器