业务背景

最近接到一个需求需要将学员的基本信息生成word格式的内容,word的格式如下图所示

开发的任务就是将学员的信息替换掉表格中的** 即可,感觉还蛮简单的。

相信大家以前做的最多的是Java和Excel的转换的功能比较多吧,我也是如此,之前也没有做过word转换的功能,所以此次接到这个任务我也是一样,从网上找方法,在网上找了一些博客论坛大概有几种方法可以尝试。

几种解决思路

1:Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。使用Jacob自带的DLL动态链接库,并通过JNI的方式实现了在Java平台上对COM程序的调用。DLL动态链接库的生成需要windows平台的支持。该方案只能在windows平台实现,是其局限性。

2:Apache POI包括一系列的API,它们可以操作基于MicroSoft OLE 2 Compound Document Format的各种格式文件,可以通过这些API在Java中读写Excel、Word等文件。他的excel处理很强大,对于word还局限于读取,目前只能实现一些简单文件的操作,不能设置样式。

3:Java2word是一个在java程序中调用 MS Office Word 文档的组件(类库)。该组件提供了一组简单的接口,以便java程序调用他的服务操作Word 文档。 这些服务包括: 打开文档、新建文档、查找文字、替换文字,插入文字、插入图片、插入表格,在书签处插入文字、插入图片、插入表格等。填充数据到表格中读取表格数据 ,1.1版增强的功能: 指定文本样式,指定表格样式。如此,则可动态排版word文档。是一种不错的解决方案。

4:iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。功能强大。

5:JSP输出样式,该方案实现简单,但是处理样式有点缺陷,简单的导出可以使用。

6:用XML做就很简单了。Word从2003开始支持XML格式,大致的思路是先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。经测试这样方式生成的word文档完全符合office标准,样式、内容控制非常便利,打印也不会变形,生成的文档和office中编辑文档完全一样。

综合以上资料的参考,和网上的一些意见,最后我选择了,第6种用xml做导出方案。

开发流程

替换word模板

对照上面发的那个word格式,将** 替换成变量名称,比如用户名称用${userName}表示,全部替换后的格式如下图所示

导出xml格式并重命名ftl格式

将上图的word文件另存为xml格式,并且重命名为ftl结尾的文件


编写Java代码

项目需要引用到freemaker的jar包,在pom.xml配置文件中,添加下面的依赖

<!-- freemarker jar --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.20</version></dependency>

将ftl模板文件复制到项目的指定路径下

将freemaker的配置文件放到项目的指定目录下

编写WordUtil.java

package com.xyq.maventest.util;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/****
* Project Name:maventest
* <p>生成word工具类<br>
*
* @ClassName: WordUtil
* @date 2019年2月20日  下午5:50:49
*
* @author youqiang.xiong
* @version 1.0
* @since
* @see*/
public class WordUtil {  private Configuration configuration = null;  /***** 模板文件存放的目录*/private static final String  baseDir = "F:/study/GIT/maventest/src/main/resources/freemaker";/**** 模板文件名称*/private static final String  templateFile = "template.ftl";/**** word生成的输出目录*/private static final String  outputDir = "F:/file/";public WordUtil(){  configuration = new Configuration();  configuration.setDefaultEncoding("UTF-8");  }  public static void main(String[] args) {  WordUtil test = new WordUtil();  test.createWord();  }  /****** * Project Name: maventest* <p>转换成word<br> ** @author youqiang.xiong* @date 2019年2月21日  上午11:22:03* @version v1.0* @since*/public void createWord(){  Map<String,Object> dataMap=new HashMap<String,Object>();  //构造参数getData(dataMap);  configuration.setClassForTemplateLoading(this.getClass(), "");//模板文件所在路径Template t=null;  try {  configuration.setDirectoryForTemplateLoading(new File(baseDir));t = configuration.getTemplate(templateFile);} catch (IOException e) {  e.printStackTrace();  }  File outFile = new File(outputDir+Math.random()*10000+".doc"); //导出文件Writer out = null;  try {  out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));  } catch (FileNotFoundException e1) {  e1.printStackTrace();  }  try {  t.process(dataMap, out); //将填充数据填入模板文件并输出到目标文件 System.out.println("生成成功...");} catch (TemplateException e) {  e.printStackTrace();  } catch (IOException e) {  e.printStackTrace();  }  }  /***** * Project Name: maventest* <p>初始化数据map <br> ** @author youqiang.xiong* @date 2019年2月21日  上午11:26:34* @version v1.0* @since * @param dataMap*       封装数据的map*/private void getData(Map<String, Object> dataMap) {  dataMap.put("userName", "刘德华");  dataMap.put("sex", "男");  dataMap.put("nation", "汉族");  dataMap.put("birthday", "1985-02-26");   dataMap.put("nationPlace", "春日部");  dataMap.put("politicalStatus", "党员");  dataMap.put("graduationSchool", "双叶幼稚园");  dataMap.put("lastBackground", "幼稚园");  dataMap.put("graduationMajor", "玩泥沙");  dataMap.put("workUnit", "NASA");  dataMap.put("business", "煮菜的");  dataMap.put("postalAddress", "lc");  dataMap.put("postalcode", "lc");  dataMap.put("mobile", "18898416969");  dataMap.put("admissionTicket", "lc");  dataMap.put("enterSchoolTime", "lc");  dataMap.put("emergencyContact", "lc");  dataMap.put("readingInstrouction", "lc");  dataMap.put("year", "2019");  dataMap.put("month", "02");  dataMap.put("day", "20");  }
}

运行main方法,抛出如下异常:

freemarker.core.ParseException: Parsing error in template "template.ftl" in line 3, column 11570:
Encountered "<", but was expecting one of:<STRING_LITERAL><RAW_STRING>"false""true"<INTEGER><DECIMAL>".""+""-""!""[""(""{"<ID>at freemarker.core.FMParser.generateParseException(FMParser.java:4672)at freemarker.core.FMParser.jj_consume_token(FMParser.java:4543)at freemarker.core.FMParser.UnaryExpression(FMParser.java:340)at freemarker.core.FMParser.MultiplicativeExpression(FMParser.java:452)at freemarker.core.FMParser.AdditiveExpression(FMParser.java:402)at freemarker.core.FMParser.RangeExpression(FMParser.java:573)at freemarker.core.FMParser.RelationalExpression(FMParser.java:528)at freemarker.core.FMParser.EqualityExpression(FMParser.java:493)at freemarker.core.FMParser.AndExpression(FMParser.java:602)at freemarker.core.FMParser.OrExpression(FMParser.java:625)at freemarker.core.FMParser.Expression(FMParser.java:238)at freemarker.core.FMParser.StringOutput(FMParser.java:1076)at freemarker.core.FMParser.Content(FMParser.java:2550)at freemarker.core.FMParser.OptionalBlock(FMParser.java:2761)at freemarker.core.FMParser.Root(FMParser.java:2933)at freemarker.template.Template.<init>(Template.java:193)at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:419)at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:330)at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:205)at freemarker.template.Configuration.getTemplate(Configuration.java:740)at freemarker.template.Configuration.getTemplate(Configuration.java:665)at com.xyq.maventest.util.WordUtil.createWord(WordUtil.java:75)at com.xyq.maventest.util.WordUtil.main(WordUtil.java:53)
Exception in thread "main" java.lang.NullPointerExceptionat com.xyq.maventest.util.WordUtil.createWord(WordUtil.java:88)at com.xyq.maventest.util.WordUtil.main(WordUtil.java:53)

这个错误估计很人都有遇到过,起初我并不知道报错提示的是什么原因,大概猜测应该是ftl模板出错了,但是又不知道为什么会报错,初步怀疑是不是word编写的变量格式书写有误?后来返回修改word的变量格式逐步缩小问题原因所在,经过反复试验才发现,word转换成xml格式的时候,如果文档中有{}格式书写有误? 后来返回修改word的变量格式逐步缩小问题原因所在,经过反复试验才发现,word转换成xml格式的时候,如果文档中有格式书写有误?后来返回修改word的变量格式逐步缩小问题原因所在,经过反复试验才发现,word转换成xml格式的时候,如果文档中有{}特殊符号的时候,转换成xml格式会出现错位的情况,如下所示:

因为我对word生成xml这个机制并不是很了解,由于时间原因,也没有深究这里的根本原因,于是原因找到了,是生成ftl模板的时候格式有问题。那么既然${}符合会被解析错误的话,那可以换一种思路,将word中的符合全部不需要,只留变量即可,如下所示:

然后重新生成xml文件,修改文件后缀ftl,打开模板文件,将模板文件复制到notepad++文件编辑器打开,
然后一个个将变量替换成${}即可,比如讲userName 替换成 ${userName} 即可

一个个变量替换完毕后,将模板文件覆盖原有的内容,重新运行WordUtil.java ,运行成功。并且在指定目录下会生成一个新的word文件,打开word文件如下图所示:

至此用Java生成word的功能已经完成,大家可以根据各自所需修改word模板即可。

记录一次用Java生成word文档的经验相关推荐

  1. [摘]用Java生成Word文档

    开发中隔三叉五的就要用到Word,经常被搞得不胜其烦,不过这次找到了不少好例子,干脆将他们都摘了过来,内容如下: 1. poi是apache的一个项目,不过就算用poi你可能都觉得很烦,不过不要紧,这 ...

  2. 用java生成word文档(转载)

    用java生成word文档 poi是apache的一个项目,不过就算用poi你可能都觉得很烦,不过不要紧,这里提供了更加简单的一个接口给你: 下载经过封装后的poi包: 这个包就是:tm-extrac ...

  3. Java 生成Word文档 — 简单示例

    前言 这篇文章将介绍如何使用免费Java Word组件Free Spire.Doc for Java在Java应用程序中生成Word文档,插入文本,并设置段落的字体格式.对齐方式以及段后间距等. Fr ...

  4. java生成word文档freemarker

    java freemarker + word 模板 生成 word 文档 (变量替换,数据的循环,表格数据的循环,以及图片的替换) 1,最近有个需求,动态生成 Word 文当并供前端下载,网上找了一下 ...

  5. Java生成Word文档

    在开发文档系统或办公系统的过程中,有时候我们需要导出word文档.在网上发现了一个用PageOffice生成word文件的功能,就将这块拿出来和大家分享. 生成word文件与我们编辑word文档本质上 ...

  6. java word模板poi生成文件_poi读写word模板 / java生成word文档

    有一word文档表格 形如: 姓名 ${name} 电话 ${tel} 下载包链接:点击进入 从数据库读取记录替换上述变量 import java.io.FileOutputStream; impor ...

  7. java生成word文档(最简单)

    首先说明,使用该方法时,尽量不要使用wps新建word文档,经测试,手机不能兼容,出现很多格式问题,office则手机可以很好的兼容,所以,本文以office做教程 1 首先新建一个word文档,然后 ...

  8. java生成word文档_Java多种方式动态生成doc文档

    本来是要在Android端生成doc的(这需求...),最后方法没有好的方法能够在Android上做到完美,最后还是只能搬迁到服务器.不浪费,还是记录下各框架不支持Android的原因以及他们的特点. ...

  9. java生成word文档 图片_java生成带有图片的word的文档-Go语言中文社区

    生成带有图片的word的文档 @RequestMapping(params ="getWordByDate",produces = "text/html;charset= ...

最新文章

  1. 菜鸟进阶: C++实现KNN文本分类算法
  2. MVC学习笔记1 MVC概述
  3. Java6 WebService学习
  4. Spring自学日志07(整合Mybatis)
  5. c gui qt 4编程第二版_一本专门学习PyQt5 GUI编程的书
  6. outermost shell_outermost是什么意思_outermost的翻译_音标_读音_用法_例句_爱词霸在线词典...
  7. 使用Emit创建DBContext对象
  8. 计算机安全权限不足或配置文件损坏,Windows XP用户配置文件丢失或损坏后的恢复方法...
  9. python输出9*9口诀表_python 9*9 乘法表
  10. 三层交换机和vrrp协议
  11. 天下武功唯快不破WP
  12. Django数据映射 一对一 一对多 多对多
  13. CSS | 盒模型的宽度计算规则
  14. java自学练习网站推荐
  15. 嵌入式学习之QT学习---8 QT网络编程之TCP通信
  16. 区块链-区块链的概念
  17. Matlab Deep Network Designer APP搭建神经网络及相关函数讲解
  18. Web安全之跨站脚本攻击漏洞
  19. 面试题-谈谈你对JVM的理解
  20. 在线重装Win11系统详细教程

热门文章

  1. 测试总结该怎么写才高级?
  2. WIN7系统的.txt文件,默认打开方式设置不成记事本的解决方法
  3. 英语学习打卡day4
  4. Qt开发技术:Q3D图表开发笔记(三):Q3DSurface三维曲面图介绍、Demo以及代码详解
  5. day2-MySQL规约
  6. 使用代理爬去微信公众号_公众号粉丝从0到1000的引流思路企业如何做好微信公众号运营?公众号运营技巧,你都知道吗?微信公众号怎么去推广运营?...
  7. 利用Servlet监听器实现简单网站访问量和在线人数统计
  8. 服务器开关电源型号ab和sb,北京DELTA DPS-500AB-21A 500W 小1U开关电源 FLEX 80PLUS 白金价格 - 中国供应商...
  9. C#向pdf 添加水印
  10. java编程输入学生成绩 判断最高分,java代码初学者适用,输入学生成绩,符合要求的过~~~~注意数据范围...