使用freemarker(ftl)生成复杂word表格,包含合并单元格

使用freemarker(ftl)生成复杂word表格,包含合并单元格

需要的效果如图

image-20220424142015317

熟悉ftl的应该都知道单元格可以通过写list来动态遍历,但是这个因为上午下午晚上,数量不固定,因此没法把模板写死,这时候就需要用到合并单元格的操作:<w:vMerge/>

重点是这两个标签
<w:vMerge w:val="restart"/> 这是合并开始的标签。
<w:vMerge/> 这是被合并的标签。

制作模板

先制作一个模板,只需要一行就可以,因为除了需要合并左边的格子,右边的格子都是同一行的,并没有什么特殊的操作,因此模板很简单

image-20220424142631011

然后填上对应占位符即可

image-20220424142713294

然后使用word将模板另存为xml文档

image-20220424142757987

千万不要选下面那个word 2003 xml 因为会有各种奇奇怪怪的兼容性问题

然后就可以得到一份xml,这里建议把xml扔到idea里头打开,因为idea格式化之后的代码会非常舒服

顺便提一句,idea原生支持ftl语法,把文件后缀名改为ftl就可以了

整理占位符

搜索$符号,你会发现,有些${xx}都被word自动分开了,这时候就需要手动拼合

image-20220424143247364

只需要选中中间那一堆,然后删除就行了

image-20220424143314716

最后的效果就是这样的

image-20220424143333159

找到需要遍历的单元格并加上list

在word xml语法中,表格的每一行标签为<w:tr>,只需要找到这个然后在外层放一个<#list>循环即可

image-20220424143605140

不要忘记下面也得加</#list>来结束循环

image-20220424143649116

list中的变量

刚刚list data as xxx中的xxx就是你定义的变量,相当于外层一个list,里面是个map,就和for循环是一个道理,整理好变量就可以

image-20220424143831637

合并单元格

在示例图片中,最左边的单元格是要被合并的单元格,因此只需要对最左边的一个单元格做出操作即可

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

输出就长这样

image-20220424144801394

参考资料:https://www.freesion.com/article/21801322263/
ftl
评论区
头像