java生成word文档

最近得到一个需求:按用户提供的模板生成分析报告,并让用户可以在网页上导出。这个功能以前没做过,但是好像听说过freemarker。于是乎,开始了我的百度之旅。

一、word文档的本质

我也是最近才知道,word文档的本质原来是一个压缩文件。不信你看,将.docx文件修改文件后缀为.zip

然后解压缩得到了这些文件,这些就是组成word文档的所有文件。其中word文件夹下是主要内容

​其中,document.xml中是关于文档内容的设置,相当于网页里面的html文件一样。_rels文件夹下的document.xml.rels文件是图片配置信息。media文件夹下是文档中所有图片的文件,其他的应该是类似于网页里面的CSS文件,设置样式的。所以document.xml就是我们要修改的了。这样的操作就相当于网页已经编写好了,只差从后台传送数据到前端展示了。

二、创建freemarker模板

freemarker是一个模板引擎,百度是这样介绍的:

FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

​说白了就是跟前端页面的变量绑定是一样的,用过vuejs的都知道,前端使用“{{name}}”双括号括起来的变量可以通过传值改变页面上数据。freemarker也是这样,通过在document.xml中使用“${name}”dollar符大括号括起来的变量也可以通过传值改变模板文件内容。清楚了这点就好办了。

将document.xml文件放到IDEA项目中的templates文件夹下,然后按Ctrl+Alt+L键格式化xml内容,将需要动态修改的地方用“${}”括起来,如下

有的时候变量会被拆分成两个,就要麻烦点把两个中间的多余部分全都删掉,然后在用符号括起来。这点相信大家都能理解。

以上模板创建就结束了,是不是很简单。

三、代码实现

模板搞定了,怎么根据模板生成文档呢?关键步骤来了。

1.首先我们要将模板中的变量赋值,生成新的文件。

2.将生成的文件写入压缩文件。上面已经说了,word文档本质就是压缩文件。

3.将.docx文档的其他内容也写入压缩文件。

4.将压缩文件写入word文档,这就是最后生成的文档。

导入依赖:

org.freemarker

freemarker

2.3.28

主要用到下面的工具类:

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");//此处设置模板存放文件夹名称

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) {

e.printStackTrace();

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

}

return in;

}

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

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

ZipOutputStream zipout = null;

try {

//内容模板,传值生成新的文件输入流documentInput

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

//最初设计的模板,原word文件生成File对象

File docxFile = new File(WordUtils.class.getClassLoader().getResource("templates/demo.docx").getPath());//模板文件名称

if (!docxFile.exists()) {

docxFile.createNewFile();

}

ZipFile zipFile = new ZipFile(docxFile);//获取原word文件的zip文件对象,相当于解压缩了word文件

Enumeration extends ZipEntry> zipEntrys = zipFile.entries();//获取压缩文件内部所有内容

zipout = new ZipOutputStream(outputStream);

//开始覆盖文档------------------

int len = -1;

byte[] buffer = new byte[1024];

while (zipEntrys.hasMoreElements()) {//遍历zip文件内容

ZipEntry next = zipEntrys.nextElement();

InputStream is = zipFile.getInputStream(next);

if (next.toString().indexOf("media") < 0) {

zipout.putNextEntry(new ZipEntry(next.getName()));//这步相当于创建了个文件,下面是将流写入这个文件

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

}

}else{//这里设置图片信息,针对要显示的图片

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

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

zipout.write(buffer, 0, len);

}

is.close();

}

}

}

} catch (Exception e) {

e.printStackTrace();

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异常");

}

}

}

}

}

四、插入图片

​通过传值已经可以基本完成生成文档的功能了,但是用户还要求要在文档中生成统计分析图。知道文档本质的我马上想出了办法,但是这个就稍微有点麻烦了。刚刚说了,media文件夹下存放的是文档中所有的图片。我可以在word文档要生成统计图的地方先用图片占好位置,调好大小。然后解压后看这个图片在media文件夹中叫什么名字。最后在代码生成的时候,跳过原文件图片的写入替换成我生成的图片就可以了。核心代码如下:

while (zipEntrys.hasMoreElements()) {

ZipEntry next = zipEntrys.nextElement();

InputStream is = zipFile.getInputStream(next);

if (next.toString().indexOf("media") < 0) {

...省略

}else{//这里设置图片信息,针对要显示的图片

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

if(next.getName().indexOf("image1.png")>0){//例如要用一张图去替换模板中的image1.png

if(dataMap.get("image1")!=null){

byte[] bys = Base64Util.decode(dataMap.get("image1").toString());

zipout.write(bys,0,bys.length);

}else{

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

zipout.write(buffer, 0, len);

}

is.close();

}

}

}

}

注意:这个Base64Util是一个将图片文件转化为base64编码字符串和将base64编码字符串转换为字节数组的工具类。这里涉及到图片文件的本质,图片的本质是一个二进制文件,二进制文件可以转换成字节数组,而字节数组又可以和字符串互相转换。这个知道就好,这里我把生成的图片的字符串存入了集合中,写入文档的时候将字节数组写入。这样原图片就被替换成了生成的图片了。这里直接将新的图片文件写入也是一样的效果。

java xml生成word文档_java生成word文档相关推荐

  1. java导出word纸张方向_java导出word的几种方式

    目前来看,java导出word大致有6种解决方案: 1:Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁.使用Jacob自带的DLL动态链接库,并通过J ...

  2. 怎么向java窗口中插入XSL表_Java向word中插入Excel文件对象

    前言: 在word文件中,虽然也有表格.但是有时我们想要将Excel中表格的大量数据直接插入到word文档中,这就需要用到word的插入对象的功能,也就是直接将Excel文件当做对象插入到word中. ...

  3. java 读取word 带格式_java读取word带格式_游戏下载_游戏攻略资讯_尽在搜狗爱玩

    Started learning Java and think you're ready to move on to the next level? Find out if you have a go ...

  4. java语言 回文判断_java判断回文字符串的几种方法

    java判断回文字符串几种简单的实现: 1.将字符串倒置后逐一比较,实现如下: public class HuiWenTest { /** * @SERLIN */ public static voi ...

  5. java导出html word文档_java生成带html样式的word文件

    最近在项目中需要将通过富文本编辑器处理过的文字转换为Word,查了很久,大家通常的解决办法是使用Jacob或POI等组件直接生成Word,但是都无法将富文本编辑器处理过的文字保留样式并保存为Word, ...

  6. java word添加图片_Java 替换word文档文字并指定位置插入图片

    先说下 需要的依赖包 org.apache.poi poi-excelant 3.12 org.apache.poi poi-scratchpad 3.12 org.apache.poi poi-oo ...

  7. java读取带格式word文档_Java读取word文档解决方案

    java读取word文档时,虽然网上介绍了很多插件poi.java2Word.jacob.itext等等,poi无法读取格式(新的API估计行好像还在处于研发阶段,不太稳定,做项目不太敢用):java ...

  8. java生成文字与图片_java生成word(文字和图片)

    1.整体思路 利用xml模板,在模板中预留占位标识(${yourContent}),然后将xml转为ftl文件,通过Map传值填充对应的内容即可,word其实和html一样,也有自己的xml标签,表头 ...

  9. java word 颜色设置_Java 给Word文档添加背景颜色

    前言 当我们制作好Word文档后,想要让枯燥乏味的文本显得有活力,或是想高亮显示文档中指定的段落或文字,此时我们可以通过为整个文档或某特定文字/段落添加背景色的形式来实现.本文将使用Free Spir ...

  10. java设置标签艺术字体颜色_Java 在Word文档中添加艺术字

    与普通文字相比,艺术字更加美观有趣也更具有辨识度,常见于一些设计精美的杂志或宣传海报中.我们在日常工作中编辑Word文档时,也可以通过添加艺术字体来凸显文章的重点,美化页面排版.这篇文章将介绍如何使用 ...

最新文章

  1. btf-raft共识算法_了解Raft共识算法:学术文章摘要
  2. 针对Web应用的【攻击模式篇】
  3. CentOS-文件操作
  4. 初级程序员面试不靠谱指南(六)
  5. Python 生成器 和 yield 关键字
  6. 首次披露!阿里线下智能方案进化史
  7. 即时通讯应用战争开打,到底谁能最终定义我们的交流方式?
  8. 分析一个文本文件(英文文章)中各个词出现的频率,并且把频率最高的十个词打印出来...
  9. SpringBoot2.1.5(14)---外部配置
  10. Ubuntu18.04设置DNS服务器(可用)
  11. UTM(Undergraduate Texts in Mathematics)书单 |附下载链接
  12. 【JY】浅析各动力求解算法及其算法数值阻尼(人工阻尼)
  13. Ethernet/IP介绍
  14. java就业感言_JAVA就业班感言
  15. 从财报看纳德拉上任两年:云服务是最大的突破
  16. 《HelloGitHub》第 48 期
  17. C++ 实验3-2本月有几天?
  18. 银行卡在ATM机器上插入后显示IC磁条芯片卡拒绝交易解决办法
  19. Mac使用Microsoft-Remote-Desktop-for-Mac远程桌面Windows
  20. 故障诊断专家系统研究之四-----知识库结构

热门文章

  1. 解析《富爸爸财务自由之路》
  2. 千寻位置_SDK集成_Linux快速上手指南
  3. NET F/T六维力传感器使用
  4. 操作系统的工作流程(流程图表示)
  5. 非常规的DeepFaceLab(DeepFake)小花招和注意事项
  6. CHEMKIN III 学习笔记
  7. 服务实例是否宕机的后台检查线程任务
  8. windows系统下itunes的备份路径修改
  9. 传感器技术—压电式传感器(学习笔记八)
  10. setoolikt制作钓鱼网站