java使用freemarker模板导出word(带有合并单元格)文档
来自:https://blog.csdn.net/qq_33195578/article/details/73790283
前言:最近要做一个导出word功能,其实网上有很多的例子,但是我需要的是合并单元格的,可是查了好久都没有自己想要的。研究了几天其实挺简单的,在这儿我就简单的介绍一下吧!(此方法只是一种思路,借鉴者还有根据需求来具体写代码)
一、准备工作
1、jar包:freemarker-2.3.20.jar
2、模板:word.ftl
2.1:这个word.ftl怎么来?
首先准备一份要导出的word.doc文档;
这是一个事先写好的一个word模板,我们需要做的就是把需要导出的数据相应的插入${}到里面(其实如果你了解
freemarker就会明白的,${}是个占位符,来放数据的,这里不详细介绍)。
如果下面的表格是固定的,比如像我们的课程表,那种是固定的,就特别简单了。我要做的就是下面的表格需要根据
数据的不同,实现合并单元格,先看一下生成以后的效果:
大家可以看一下,前面三个格子是合并以后的,当然,如果后面两个格子的数据只有一行,那么也就是一行就行
了。
2.2 将word.doc 转化成word.xml
个人觉得,其实word就是一个xml文件。打开这个word,然后另存为xml格式,然后你再用office打开这个xml,也是可
打开的。
然后用notepad(其他软件随意,不过最好可以格式化这个xml或者ftl文件,否则你会头炸的,啥都看不清)打开这个
word.xml。然后你会发现,可能解析的时候,会把我们的"${}"这些给分开,没事,你手动再把他们拼好就行了。
切记:拼接的时候,千万要注意不要删除或修改了里面的什么结构,后果自负(呵呵,其实就是格式错误了,就算你
导出成功,也不会打开的,因为你已经损害了这个word)
2.3 完成这个xml以后,把这个word.xml 修改成后缀为.ftl的模板文件,到此,这个模板就算完成了。
二、这里先说根据模板word.ftl将导出新的new.doc
1、其实这一步,网上多的是,我唯一有点不满意的就是,它获取模板的方法好像只有通过路径来获取,也许还有别的方法,欢
迎知情者可以告诉我,哈哈!
2、先创建一个类(个人随意,实现功能就行。)DocmentHandler.class
- public class DocumentHandler {
- private Configuration configuration = null;
- public DocumentHandler(){
- configuration = new Configuration();
- configuration.setDefaultEncoding("UTF-8");
- }
- public byte[] createDocArea (Map<String, Object> dataMap ,String outFilePath,String fileName) throws Exception{
- //this.configuration.setClassForTemplateLoading(DocumentHandler.class, "D:\\");//第一种模板路径
- System.out.println("---进入createDocArea---");
- this.configuration.setDirectoryForTemplateLoading(new File("/template/"));//第二种模板路径
- Template t = null;
- File outFile = null;
- byte[] bFile = null;
- try {
- t = this.configuration.getTemplate(fileName,"UTF-8");
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- outFile = new File(outFilePath);
- Writer w = null;
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(outFile);
- OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
- w = new BufferedWriter(osw);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- try {
- t.process(dataMap, w);
- if(outFile!=null){
- FileInputStream fis = new FileInputStream(outFile);
- bFile = new byte[(int) outFile.length()];
- fis.read(bFile);
- fis.close();
- }
- System.out.println("--写入完成---");
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }finally{
- w.close();
- fos.close();
- }
- return bFile;
- }
- }
public class DocumentHandler {private Configuration configuration = null; public DocumentHandler(){
configuration = new Configuration();
configuration.setDefaultEncoding("UTF-8");
} public byte[] createDocArea (Map<String, Object> dataMap ,String outFilePath,String fileName) throws Exception{
//this.configuration.setClassForTemplateLoading(DocumentHandler.class, "D:\\");//第一种模板路径
System.out.println("---进入createDocArea---");
this.configuration.setDirectoryForTemplateLoading(new File("/template/"));//第二种模板路径
Template t = null;
File outFile = null;
byte[] bFile = null;
try {
t = this.configuration.getTemplate(fileName,"UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
} outFile = new File(outFilePath);
Writer w = null;
FileOutputStream fos = null; try {
fos = new FileOutputStream(outFile);
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8"); w = new BufferedWriter(osw);
} catch (Exception e) {
e.printStackTrace();
return null;
} try {
t.process(dataMap, w);
if(outFile!=null){
FileInputStream fis = new FileInputStream(outFile);
bFile = new byte[(int) outFile.length()];
fis.read(bFile);
fis.close();
}
System.out.println("--写入完成---");
} catch (Exception e) {
e.printStackTrace();
return null;
}finally{
w.close();
fos.close();
}
return bFile;
}
}
3、简单介绍一下思路:它是通过这个configuration来获取模板的,目前我就知道这两种,一个是通过File,另一个种是通过
Class,不过我试了一下,不过这两种用哪一种,其实都是通过路径来获取的,然后它会根据在这个路径下,来通过你给的模板
名称来找这个模板。所以这里路径下一定要有相应的模板。然后获取模板以后,你再定义一个File,把封装好的Map(这个map就
是你要填充的数据)传过来,它会通过流,结合模板,把数据写入到你的新File中。至于你怎么处理这个File,我就不管了。
三、封装数据(关键)
1、其实很好理解,填充模板数据的方式就是用key-value这个格式写的(这个应该好理解吧!freemark),定义一个Map,map
的key就是模板里面的${key}这个属性,一定要跟模板里面的对应起来,value就是你要写的数据;如果你不需要合并单元格,你
就无脑的按照模板里${key},对应的放数据就行,最后把map给第二步的导出方法;
2、如果你的word里需要循环的,那就再map里放个list,至于模板里怎么循环,这就是涉及到freemarker的知识了,我就不解释
了,自己百度去;(哎,给个例子吧!)
一定要判断你传的这个是否为空,否则要是空的话,会报错(它会用英文提示你,这个是空,你要判断空的情况,利用<#if>
<#else></#if>,自己理解去吧!);
3、哈哈这儿才是重点:
1、其实这个word合并单元格挺简单的,就拿我上图的那个结果来说,1到4(算上
前面的那个序列号)个格子是需要合并的,后面的三个不需要。上图是一个IP对应
后面五个单元格,所以其实它并不是一行,它是5行,(在这里)ip是在第一行, 然后第2到第4行的ip是空的。先理解这个!
2、合并需要的属性值:<w:vMerge w:val='restart'/>和<w:vMerge/>
这俩才是控制合并单元格的罪魁祸首;
3、怎么用?(看上图)当循环第一行的时候,有IP、地域、重要攻击、单位、时
间;第二行,有空、空、空、单位、时间;第三行。。。。
4、然后在模板里的第一行(也就是循环第一次的时候),添加<w:vMerge
w:val='restart'/>(只在需要合并单元格的地方添加,看下图)
简单的解释一下,一行的开始是以<w:tr w:rsidR="00806640"
w:rsidRPr="00914E05" w:rsidTr="00806640">这个开始的,以</w:tr>结束的,这
个是完整的一行,里面的<w:tc>是代表一个格子,算是前面的序列号,我上图也就
是6个<w:tc>放那个合并属性的时候千万别放错地方了,我的是前四个(算上序列
号)需要合并,所以我就在前四个<w:tc>里放了这个;
然后再第二行(三行。。。循环)的时候,前面的ip是空的,这个时候要放
<w:vMerge/>这个属性,放的位置跟第一行的方法一样,只是这个熟悉变了;
这样的话就实现了合并单元格了;这样第一个IP对应的单元格就完成了,第二个IP
就循环着来呗!
4、以上就是一个完整的导出过程了,当然,不管是封装数据,还是合并单元格,
我说的可能更多的只是个思路,具体怎么封装数据,怎么想方设法的把数据放进模
板,仁者见者,智者见智吧!就到此为止吧,希望我说的大家可以看的明白,如果 哪儿不明白的,或者哪儿写的不对的,欢迎吐槽!
java使用freemarker模板导出word(带有合并单元格)文档的更多相关文章
- Java 用Freemarker完美导出word文档(带图片)
Java 用Freemarker完美导出word文档(带图片) 前言 最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题. ...
- WPF 导出Excel(合并单元格)
WPF 导出Excel(合并单元格) DataTable 导出Excel(导出想要的列,不想要的去掉) ,B1,B2,B3,B4,B5} MisroSoft.Office.Interop.Excel. ...
- 使用POI创建word表格合并单元格兼容wps
poi创建word表格合并单元格代码如下: /** * @Description: 跨列合并 */ public void mergeCellsHorizontal(XWPFTable table, ...
- php 数据导出到excel 2种带有合并单元格的导出
具体业务层面 可能会有所不同.以下两种方式涉及的合并单元格地方有所不同,不过基本思路是一致的. 第一种是非插件版本.可能更容易理解点,基本思路就是 组装table 然后 读取 输出到excel上.缺点 ...
- 导出excel带合并单元格方法的Demo
package com.test.util; import java.io.FileNotFoundException; import java.io.FileOutputStream; import ...
- 前端Excel表格导入导出,包括合并单元格,表格自定义样式等
表格数据导入 读取导入Excel表格数据这里采用的是 xlsx 插件 npm i xlsx 读取excel需要通过 XLSX.read(data, {type: type}) 方法来实现,返回一个叫W ...
- java通过freemarker模板导出pdf
需求:将网页内容导出为pdf文件,其中包含文字,图片,echarts图 原理:利用freemarker模板与数据渲染所得到的html内容,通过ITextRenderer对象解析html内容生成pdf ...
- 转:jxl导出excel(合并单元格)
Demo 代码如下: import java.io.*; import jxl.*; import jxl.format.UnderlineStyle; import jxl.write.*; pub ...
- Java根据Freemarker模板生成Word文件
1. 准备模板 模板 + 数据 = 模型 1.将准备好的Word模板文件另存为.xml文件(PS:建议使用WPS来创建Word文件,不建议用Office) 2.将.xml文件重命名为.ftl文件 3 ...
随机推荐
- 依赖注入的方式测试ArrayList和LinkedList的效率(对依赖注入的再次理解)
9/20 号再进行学习 在C++中,main函数尽可能的简单,只要调用子函数的一句话就实现了功能. java开发中,controller就相同于是main函数,其他类的方法不在本类中时候, 1.可以用 ...
- gvim最简化设置,去掉工具栏和菜单栏
编辑vimrc文件(该文件位于gvim安装目录下),在文件末尾添加以下语句即可 set gfn=Courier_New:h14colorscheme torteset guioptions-=mset ...
- linux网络编程概念(一)
AF表示地址族(address family) PF表示协议族(protocol family) domain参数 AF_UNIX 内核中通信 sockaddr_un AF_INET 通过ipv4 s ...
- Laya学习
IDE安装 https://www.jianshu.com/p/88fa76a5becc npm uninstall -g typescript npm install -g typescript@2 ...
- extundelete
http://extundelete.sourceforge.net/options.html 误删除/usr/share目录因此考虑恢复目录过程如下:1.选用extundelete软件来进行恢复,源 ...
- SharePoint Online 使用 adal js 获取access token
最近在写一些SharePoint 的sample code, 有兴趣的小伙伴可以查看我的GitHub. 今天给大家介绍SharePoint Framework (SPFx )web part 当中怎 ...
- Linux 日志分析工具之awstats
一.awstats 是什么 官方网站:AWStats is a free powerful and featureful tool that generates advanced web, strea ...
- Zabbix-2.4-安装-2
zabbix自定义报警-动作 打开资产自动接收 这里看到主机资产有数据了,这里的数据,就是来自下面的关联 上面的数据就是设置login-user时候设置的关联 有些关联显示的慢,比如下面 ...
- JQury基础(一)样式篇
1 初识jQury 1.1 环境搭建 jQuery是一个JavaScript脚本库,不需要特别的安装,只需要我们在页面 标签内中,通过 script 标签引入 jQuery 库即可. <head ...
- mysql之 myloader原理介绍
myloader恢复主要流程 1.首先由myloader主线程完成建库建表,依次将备份目录下建库和建表文件执行应用到目标数据库实例中: 2.接着myloader主线程会生成多个工作线程,由这些 ...