ftl(freemarker)模板中动态批量插入文字和图片

ftl模板中动态批量插入文字和图片

因为某种原因,需要在表格中的一块地方同时放入图片和文字,并且需要动态插入,并且按照顺序,ftl本质上还是word的xml文件的进阶版,所以直接生成一份xml文件,从里面抠代码动态添加就行了

不熟悉word xml语法的可以往需要动态添加的模板中手动添加一下,然后拿记事本看这个xml文件就可以

插入图片:

图片会以附件的形式保存在word文档中,一般没有链接本地文件的话,图片会以base64的形式保存在文档中

1. 保存图片主要信息

图片的主要信息,会以binaryData的形式存在word中,也就是一大串base64所在的地方,很容易找到

<pkg:part pkg:name="/word/media/image1.png" pkg:contentType="image/png" pkg:compression="store">
    <pkg:binaryData>base64xxxxxxxxxxxxxxxxxxxx</pkg:binaryData>
</pkg:part>

如果有多张图片,只需要拿占位符替换关键部分,然后外面套一层list循环就可以:

<#list imagesData as imgData>
    <pkg:part pkg:name="/word/media/image${imgData.index}.${imgData.type}" pkg:contentType="image/${imgData.type}" pkg:compression="store">
        <pkg:binaryData>${imgData.data}</pkg:binaryData>
    </pkg:part>
</#list>
2. 将附件关联到id,以便在正文中直接引用

附件信息需要被关联到id,这样正文中可以直接引用这个id

搜索Relationship关键字,可以发现插入的图片都被放在一堆里面,这时候只需要动态插入即可

<#list imagesData as imgData>
    <Relationship Id="rId${imgData.index}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
                  Target="media/image${imgData.index}.${imgData.type}"/>
</#list>

rId的编号可以为字母,但是要注意在程序中存住这个变量,因为后面循环添加图片会用到

3. 在正文中引用图片

找到你需要插入这些图片的地方,直接以行标签的形式插入

至于字体以及别的格式,自己手动在word中设置然后生成xml就能获取到代码

图片高度和宽度需要自己指定,注意,正常的宽/高度需要*1000才可以成为word中的

<w:p w14:paraId="0E9CC753" w14:textId="0C4B0705" w:rsidR="003D6FEB"
                                     w:rsidRDefault="00224C7D" w:rsidP="003D6FEB">
    <w:r w:rsidRPr="00417179">
        <w:rPr>
            <w:rFonts w:ascii="仿宋_GB2312" w:eastAsia="仿宋_GB2312"
                      w:hAnsi="Times New Roman" w:cs="Times New Roman"
                      w:hint="eastAsia"/>
            <w:noProof/>
            <w:kern w:val="0"/>
            <w:sz w:val="32"/>
            <w:szCs w:val="32"/>
        </w:rPr>
        <w:drawing>
            <wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="2F977AB1"
                       wp14:editId="3FD9BDF8">
                <wp:extent cx="${图片宽度}" cy="${图片高度}"/>
                <wp:effectExtent l="0" t="0" r="0" b="0"/>
                <wp:docPr id="10" name="图片 10"/>
                <wp:cNvGraphicFramePr>
                    <a:graphicFrameLocks
                                         xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
                                         noChangeAspect="1"/>
                </wp:cNvGraphicFramePr>
                <a:graphic
                           xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                    <a:graphicData
                                   uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                        <pic:pic
                                 xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                            <pic:nvPicPr>
                                <pic:cNvPr id="1" name=""/>
                                <pic:cNvPicPr/>
                            </pic:nvPicPr>
                            <pic:blipFill>
                                <a:blip r:embed="rId${index}"/>
                                <a:stretch>
                                    <a:fillRect/>
                                </a:stretch>
                            </pic:blipFill>
                            <pic:spPr>
                                <a:xfrm>
                                    <a:off x="0" y="0"/>
                                    <a:ext cx="${图片宽度}" cy="${图片高度}"/>
                                </a:xfrm>
                                <a:prstGeom prst="rect">
                                    <a:avLst/>
                                </a:prstGeom>
                            </pic:spPr>
                        </pic:pic>
                    </a:graphicData>
                </a:graphic>
            </wp:inline>
        </w:drawing>
    </w:r>
</w:p>

进阶:如果需要在图片的同一行追加文字,可以添加<w:r></w:r>行内标签在你需要加文字的地方,在%s的地方换成你需要增加的文字就可以

<w:r w:rsidR="001A0BEE" w:rsidRPr="00FB2FAF">
    <w:rPr>
        <w:rFonts w:ascii="仿宋_GB2312" w:eastAsia="仿宋_GB2312"
                  w:hAnsi="Times New Roman" w:cs="Times New Roman"
                  w:hint="eastAsia"/>
        <w:kern w:val="0"/>
        <w:sz w:val="32"/>
        <w:szCs w:val="32"/>
    </w:rPr>
    <w:t>%s</w:t>
</w:r>

插入一行文字

<w:p w14:paraId="7B0A2654" w14:textId="77777777" w:rsidR="007D5F92"
                                     w:rsidRDefault="00224C7D" w:rsidP="00417179">
    <w:pPr>
        <w:snapToGrid w:val="0"/>
        <w:spacing w:line="580" w:lineRule="exact"/>
        <w:rPr>
            <w:rFonts w:ascii="仿宋_GB2312" w:eastAsia="仿宋_GB2312"
                      w:hAnsi="Times New Roman" w:cs="Times New Roman"/>
            <w:kern w:val="0"/>
            <w:sz w:val="32"/>
            <w:szCs w:val="32"/>
        </w:rPr>
    </w:pPr>
    <w:r w:rsidRPr="00417179">
        <w:rPr>
            <w:rFonts w:ascii="仿宋_GB2312" w:eastAsia="仿宋_GB2312"
                      w:hAnsi="Times New Roman" w:cs="Times New Roman"
                      w:hint="eastAsia"/>
            <w:kern w:val="0"/>
            <w:sz w:val="32"/>
            <w:szCs w:val="32"/>
        </w:rPr>
        <w:t>测试专用文字</w:t>
    </w:r>
</w:p>

同时插入图片和文字

做法就是使用上面的代码段,使用程序去动态添加代码段在指定位置就行,比如在一个<w:p></w:p>结束的地方放上一个占位符,然后你就可以直接将动态生成完的代码段直接扔到这个占位符里头去

注意事项:

建议每一个占位符或者循环外面都套一层if判空,如下所示:

否则,当生成时数据集中不存在这个变量时,会报ftl语法错误,然后直接生成失败

<#if 变量名称??>${变量名称}</#if>

<w:r></w:r>为行内标签,通常用于一行

<w:p></w:p>为行标签,通常用于另起一行,类似于System.out.println(),p标签中可以存在r标签,但是通常来说r标签不会单独放在p标签外面

关于附件ID,也就是上面的rId${index},有的地方会包含word自己的附件,按理来说这些附件id不能冲突,所以尽量不要使index从1开始遍历,或者,你完全可以不叫rId,使用别的名称来避免冲突

不了解语法的可以参考官网:模板一览 - FreeMarker 中文官方参考手册 (foofun.cn)

评论区
头像
文章目录