一步一步带你实现java根据模板导出word循环数据

  • 之前操作EXCEL使用的是poi,用poi操作word有点复杂,且没有模板功能.放弃
  • 找到了freemarker这个工具,他可以根据word的模板生成导出的word

话不多说,跟着我来一步一步走

首先 我默认你已经有个maven或者gradle工程了

先别急着找freemarker的依赖,查查自己已有的依赖中是否已经有freemarker了.
查这里
在这里插入图片描述
有这个包就说明已经有该依赖了,不需要在导入了
在这里插入图片描述

  • 若没有该包,请导入该依赖项:
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.28</version>
</dependency>

准备工作结束了,开始创建word模板

新建一个word,做好自己的模板,附上我的模板
在这里插入图片描述

解释:
${}中的是后面要使用的变量.
我用第一个

${l.communityName}

来举例
l表示某个集合中的某个实体,communityName是他的属性,也就是这里要填入的数据
在后面的代码中会有这样的:

List<Community> communities = communityMapper.selectList(null);
Map<String,Object> dataMap = new HashMap<String, Object>();
dataMap.put("list", communities);

word设计好后,将其转为xml

对该word文件点击另存为,选择xml
在这里插入图片描述
保存好后,打开,若没有一个xml的格式,大家可以对其格式化,idea直接格式化就行了,notepad++需要下载 xml tools 插件
下载xml tools插件 请自行搜索

下来这步很重要 ,需要各位非常细心!!!

打开xml后,找到第一个变量的位置,可以通过’$'符号找
找到后,会发现,这样的代码

                        <w:tc>
                                <w:tcPr>
                                    <w:tcW w:w="3040" w:type="dxa"/>
                                    <w:vAlign w:val="center"/>
                                </w:tcPr>
                                <w:p w:rsidR="00C43AC5" w:rsidRPr="00C43AC5" w:rsidRDefault="00C43AC5">
                                    <w:pPr>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                    </w:pPr>
                                    <w:bookmarkStart w:id="0" w:name="_GoBack"/>
                                    <w:r>
                                        <w:rPr>
                                            <w:rFonts w:hint="eastAsia"/>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>$</w:t>
                                    </w:r>
                                    <w:r>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>{</w:t>
                                    </w:r>
                                    <w:proofErr w:type="spellStart"/>
                                    <w:r w:rsidR="00724485">
                                        <w:rPr>
                                            <w:rFonts w:hint="eastAsia"/>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>l</w:t>
                                    </w:r>
                                    <w:r w:rsidR="00724485">
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>.</w:t>
                                    </w:r>
                                    <w:r w:rsidRPr="00C43AC5">
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>communityName</w:t>
                                    </w:r>
                                    <w:proofErr w:type="spellEnd"/>
                                    <w:r>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>}</w:t>
                                    </w:r>
                                    <w:bookmarkEnd w:id="0"/>
                                </w:p>
                            </w:tc>

仔细观察这段代码中每个<w:t>标签,你会发现,他将刚刚我们写好的变量给拆分了.
下来就对这段代码进行修改.

注意:!!!

整个代码不能有删改,否则word会出现问题~~

我们只需要将<w:t>标签内的内容合并起来,变成如下所示的代码:

<w:tc>
                                <w:tcPr>
                                    <w:tcW w:w="3040" w:type="dxa"/>
                                    <w:vAlign w:val="center"/>
                                </w:tcPr>
                                <w:p w:rsidR="00C43AC5" w:rsidRPr="00C43AC5" w:rsidRDefault="00C43AC5">
                                    <w:pPr>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                    </w:pPr>
                                    <w:bookmarkStart w:id="0" w:name="_GoBack"/>
                                    <w:r>
                                        <w:rPr>
                                            <w:rFonts w:hint="eastAsia"/>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t>${l.communityName}</w:t>
                                    </w:r>
                                    <w:r>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t></w:t>
                                    </w:r>
                                    <w:proofErr w:type="spellStart"/>
                                    <w:r w:rsidR="00724485">
                                        <w:rPr>
                                            <w:rFonts w:hint="eastAsia"/>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t></w:t>
                                    </w:r>
                                    <w:r w:rsidR="00724485">
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t></w:t>
                                    </w:r>
                                    <w:r w:rsidRPr="00C43AC5">
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t></w:t>
                                    </w:r>
                                    <w:proofErr w:type="spellEnd"/>
                                    <w:r>
                                        <w:rPr>
                                            <w:sz w:val="21"/>
                                        </w:rPr>
                                        <w:t></w:t>
                                    </w:r>
                                    <w:bookmarkEnd w:id="0"/>
                                </w:p>
                            </w:tc>

就是把<w:t>标签内的变量全部移动到第一个$后面,其他的<w:t>标签滞空.

接下来进行循环设置

找到需要循环的代码
将该段填入

<#list list as l>

第一个list表示循环,第二个表示

dataMap.put("list", communities);

dataMap的key

填入的位置

直观来看,是红色框内需要循环向下补充单元格
在这里插入图片描述
xml的代码中来看呢,

</w:tr>是单元格的一行结束的标签,找到他,下面就是需要循环的表格

注意!!!

<#list list as l>是需要结束标签的
结束标签:</#list>

另外,这个表格最后两个是时间格式的
如果就这样向后执行的话,会报这样的错

Tip: If you need a particular format only once, use ?string(pattern), like ?string('dd.MM.yyyy HH:mm:ss'), to specify which fields to display.

解决方法:

将这个代码
<w:t>${l.completionTime}</#if></w:t>
变为
<w:t>${l.completionTime?string('yyyy.MM.dd')}</#if></w:t>

处理数据为空的问题

当某个字段数据为空,且不处理时,会报错!
解决方法:
这里假设completionTime这个字段可能为空

<w:t><#if l.completionTime??>${l.completionTime?string('yyyy.MM.dd')}</#if></w:t>

加上

<#if l.completionTime??> 这个代码就行了

将word模板用java处理导出

将改好的xml后缀改为ftl

核心代码:

try {
            List<Community> communities = communityMapper.selectList(null);
            for (Community community : communities) {
                Integer state = community.getState();
                if(state==0){
                    community.setStateStr("未开始");
                }else if (state==1){
                    community.setStateStr("进行中");
                }else {
                    community.setStateStr("已完成");
                }
            }
            Map<String,Object> dataMap = new HashMap<String, Object>();
            dataMap.put("list", communities);
            //Configuration 用于读取ftl文件
            //new Configuration()构造方法内是当前依赖的版本号
            Configuration configuration = new Configuration(new Version("2.3.28"));
            configuration.setDefaultEncoding("utf-8");

            /**
             * 指定ftl文件所在目录的路径,而不是ftl文件的路径
             * setClassForTemplateLoading(a,b)
             * a代表某个类加载器,b是ftl文件所在的路径,实在a所在的路径之下
             * 网上查了下有人说可以这么理解
             * 假设a的路径是:org.ql  而ftl在目录org.ql.template下
             * 那么这里需要写为:configuration.setClassForTemplateLoading(a.getClass, "/template下");
             * 但是!!! 我试了不行
             * 所以还是将那个包路径填为空 在后面将ftl文件的相对路径写入
             */
            configuration.setClassForTemplateLoading(this.getClass(), "");

            //输出文档路径及名称
            File outFile = new File("E:/桌面/测试.doc");

            //以utf-8的编码读取ftl文件
            Template template = configuration.getTemplate("/template/老旧小.ftl", "utf-8");
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
            template.process(dataMap, out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

实际上,我的ftl文件放在该类所在的同包下的template包下

结束!

效果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qlanto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值