使用freemarker(ftl)生成复杂word表格,包含合并单元格
需要的效果如图
熟悉ftl的应该都知道单元格可以通过写list来动态遍历,但是这个因为上午下午晚上,数量不固定,因此没法把模板写死,这时候就需要用到合并单元格的操作:<w:vMerge/>
重点是这两个标签<w:vMerge w:val="restart"/>
这是合并开始的标签。<w:vMerge/>
这是被合并的标签。
制作模板
先制作一个模板,只需要一行就可以,因为除了需要合并左边的格子,右边的格子都是同一行的,并没有什么特殊的操作,因此模板很简单
然后填上对应占位符即可
然后使用word将模板另存为xml文档
千万不要选下面那个word 2003 xml
因为会有各种奇奇怪怪的兼容性问题
然后就可以得到一份xml,这里建议把xml扔到idea里头打开,因为idea格式化之后的代码会非常舒服
顺便提一句,idea原生支持ftl语法,把文件后缀名改为ftl就可以了
整理占位符
搜索$
符号,你会发现,有些${xx}都被word自动分开了,这时候就需要手动拼合
只需要选中中间那一堆,然后删除就行了
最后的效果就是这样的
找到需要遍历的单元格并加上list
在word xml语法中,表格的每一行标签为<w:tr>
,只需要找到这个然后在外层放一个<#list>
循环即可
不要忘记下面也得加</#list>
来结束循环
list中的变量
刚刚list data as xxx
中的xxx就是你定义的变量,相当于外层一个list,里面是个map,就和for循环是一个道理,整理好变量就可以
合并单元格
在示例图片中,最左边的单元格是要被合并的单元格,因此只需要对最左边的一个单元格做出操作即可
在word xml语法中,<w:tc>
便签代表单元格,里面通常会包含一个<w:tcPr>
来申明单元格的信息,自然合并单元格的语法也就加在这里
思路是定义一个变量存放单元格上一个循环中的内容,然后对比这个变量和当前循环的变量中的内容,如果变量相同则合并,如果变量不同就不合并
记得变量要定义在list外面!!!
申明变量:
<#assign xzFlag="">
单元格申明:
<#--这个是单元格中的写法-->
<w:tcPr>
<w:tcW w:w="1263" w:type="dxa"/>
<#if dat.date!=xzFlag>
<w:vMerge w:val="restart"/>
<#else>
<w:vMerge/>
</#if>
<#assign xzFlag=dat.date>
<w:vAlign w:val="center"/>
</w:tcPr>
结束,测试
//设置输出文件名称
String docName = "测试.doc";
//ftl模板名称,无需加word/ 因为内部类封装已经加上这个路径了
String ftlFile = "个人一周工作预安排模板.ftl";
//获取数据
Map<String, Object> map = new HashMap<>();
List<Map<String, Object>> dataList = new ArrayList<>();
Map<String, Object> dat1 = new HashMap<>();
Map<String, Object> dat2 = new HashMap<>();
Map<String, Object> dat3 = new HashMap<>();
dat1.put("date","4月1日<w:br/>星期一");
dat1.put("time","上午");
dat1.put("content","这是一堆内容");
dat1.put("remark","这是一堆备注");
dat2.put("date","4月1日<w:br/>星期一");
dat2.put("time","下午");
dat2.put("content","这是一堆内容1");
dat2.put("remark","这是一堆备注1");
dat3.put("date","4月2日<w:br/>星期二");
dat3.put("time","上午");
dat3.put("content","这是一堆内容1");
dat3.put("remark","这是一堆备注1");
dataList.add(dat1);
dataList.add(dat2);
dataList.add(dat3);
map.put("data",dataList);
//使用ftl模板生成文件并输出到response
WordGenerator.createDoc(null, null, map, docName, ftlFile);
输出就长这样
参考资料:https://www.freesion.com/article/21801322263/
分别是哔哩哔哩序号35,小米运动序号2,米友社序号13,这个是同一个账号下运行的任务