利用FreeMarker动态生成Word报告:打造灵活的信息表格实例

利用FreeMarker动态生成Word报告:打造灵活的信息表格实例

一、引言

  1. 背景介绍:
    • 项目背景及需求,需要按实际数据生成多行表格报告,并且每条数据生成一个具体表格信息。比如20条数据,生成一个20行数据,并且生成20个表格。

二、FreeMarker基础概览

  1. FreeMarker简介

    • FreeMarker的基本概念和作用

      FreeMarker 是一款强大的、基于Java的模板引擎,主要用于生成各种类型的文本输出,尤其是适用于Web开发领域,用于分离程序逻辑和页面展示层。它是由Apache软件基金会维护的一个开源项目,允许开发者编写简单的、易于理解和修改的模板文件,并结合预先准备好的数据模型,动态生成HTML、XML、邮件正文、配置文件等各种格式的文本内容。
      
    • FreeMarker在文档自动化生成领域的应用优势

      • 模板化能力:
        • FreeMarker强大的模板语言允许创建高度可复用的文档结构模板,只需要替换模板内的变量就可以生成不同内容的文档,这大大简化了文档生产流程,提高了工作效率。
        • 可以设计复杂的模板,通过嵌套结构、循环和条件语句来处理多变的数据结构,适应各类复杂报告和文档的布局需求。
      • 分离关注点:
        • FreeMarker遵循“模板+数据模型=输出”的原则,确保了文档内容与样式、数据与呈现逻辑之间的分离,使得文档生成过程更为模块化和组件化,更便于管理和维护。
      • 灵活性与兼容性:
        • 不仅限于HTML,FreeMarker可以生成多种格式的文本文件,包括XML、PDF、Word文档(通过转换服务)、纯文本文件等,适应不同的文档格式要求。
        • 对于企业级应用,它可以轻松与Java应用程序集成,支持从数据库、REST API等多种数据源获取实时数据,实现文档的动态更新和定制化生成。
      • 安全性与稳定性:
        • FreeMarker有严格的沙箱模式,限制了模板执行的权限,防止潜在的安全风险,确保了在大规模自动化文档生成过程中系统的安全稳定。
      • 跨平台和可扩展性:
        • 由于FreeMarker是Java编写的,因此具有良好的跨平台特性,可在任何支持Java环境的应用中部署和使用。
        • 具备良好的扩展性,可以根据实际需求定制额外的标签库或函数,增强模板的功能性。

      总之,FreeMarker在文档自动化生成领域的应用能帮助企业提高生产力,减少重复工作,同时保证文档的一致性和准确性,尤其适合诸如报表、合同、发票等大量标准化但又需个性化定制的文档生成任务。

  2. FreeMarker模板语言(FTL)基础

    • 变量替换与循环控制结构

      • 变量替换:在FTL中,变量替换是通过插值表达式完成的,通常使用 ${} 符号包裹变量名。例如:

        Hello, ${user.name}!
        

        在这个例子中,user.name 是一个从数据模型(Data Model)中提取的变量,当模板被处理时,它会被对应的实际值替换。

        如果变量可能不存在,可以使用条件修饰符检查其存在性:或者设置默认值:

        ${user.address?if_exists}
        ${user.title?default('Unknown User')}
        
    • 条件判断和其他常用指令

      • 循环控制结构(Looping Constructs): FreeMarker 提供了 listforeach 标签来进行迭代和循环输出集合或序列中的元素。

        例如,遍历一个名为 items 的列表:

        <ul>
        <#list items as item>
          <li>${item.name}</li>
        </#list>
        </ul>
        

三、FreeMarker模板设计与实现

  1. Word模板文件构建
    • 在Word中设计可复用的表格模板

      • 首先需要根据需求设计出word模板和动态生成的模板,如下:
      • 在这里插入图片描述
      • 在这里插入图片描述
    • 插入FreeMarker标签实现动态填充

      • 将需要动态填充的数据,设置为标签,如下:
      • 在这里插入图片描述
      • 在这里插入图片描述

五、核心代码片段解析

  1. 模板

    • 将word模板调整以后,另存格式为xml,然后重名为.ftl格式,放入idea中格式化

    • 格式化以后需要查看各个占位符在不在一行中或者出现乱码的情况,进行调整

      <w:r>
         <w:rPr>
           <w:rFonts w:h-ansi="宋体" w:hint="default"/>
           <w:b w:val="off"/>
           <w:sz w:val="28"/>
           <w:sz-cs w:val="28"/>
           <w:u w:val="single"/>
           </w:rPr>
           <w:t>${planYear}</w:t>
      </w:r>
      
    • 设置需要动态替换的表格数据,插入循环控制结构list标签

    • <#list list1 as item>
        //省略部分代码数据
                                  <w:r>
                                      <w:rPr>
                                          <w:rFonts w:ascii="Times New Roman" w:h-ansi="Times New Roman" w:fareast="等线"
                                                    w:cs="Times New Roman" w:hint="default"/>
                                          <w:color w:val="000000"/>
                                          <w:kern w:val="0"/>
                                          <w:sz-cs w:val="21"/>
                                          <w:lang w:bidi="AR-SA"/>
                                      </w:rPr>
                                      <w:t>${item.index}</w:t>
                                  </w:r>
                              </w:p>
                          </w:tc>
         //省略部分代码数据
      </#list>
      
    • 需要将循环填充的表格也插入list标签,但是需要找到<w:tbl>或者整个表格标签的上面

    • <#list itemsList as item>
                  <w:tbl>
                      <w:tblPr>
                          <w:tblpPr w:leftFromText="180" w:rightFromText="180" w:vertAnchor="text" w:horzAnchor="page"
                                    w:tblpX="1534" w:tblpY="501"/>
                          <w:tblOverlap w:val="Never"/>
                          <w:tblW w:w="11199" w:type="dxa"/>
                          <w:tblInd w:w="0" w:type="dxa"/>
                          <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                          <w:tblLayout w:type="Fixed"/>
                          <w:tblCellMar>
                              <w:top w:w="0" w:type="dxa"/>
                              <w:left w:w="108" w:type="dxa"/>
                              <w:bottom w:w="0" w:type="dxa"/>
                              <w:right w:w="108" w:type="dxa"/>
                          </w:tblCellMar>
                      </w:tblPr>
                      <w:tblGrid>
                          <w:gridCol w:w="1596"/>
                          <w:gridCol w:w="2283"/>
                          <w:gridCol w:w="1852"/>
                          <w:gridCol w:w="1733"/>
                          <w:gridCol w:w="2040"/>
                          <w:gridCol w:w="1695"/>
                      </w:tblGrid>
                      <w:tr>
                          <w:tblPrEx>
                              <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                              <w:tblCellMar>
                                  <w:top w:w="0" w:type="dxa"/>
                                  <w:left w:w="108" w:type="dxa"/>
                                  <w:bottom w:w="0" w:type="dxa"/>
                                  <w:right w:w="108" w:type="dxa"/>
                              </w:tblCellMar>
                          </w:tblPrEx>
                          <w:trPr>
                              <w:cantSplit w:val="on"/>
                              <w:trHeight w:val="600" w:h-rule="atLeast"/>
                          </w:trPr>
                          <w:tc>
                              <w:tcPr>
                                  <w:tcW w:w="11199" w:type="dxa"/>
                                  <w:gridSpan w:val="6"/>
                                  <w:tcBorders>
                                      <w:top w:val="single" w:sz="8" wx:bdrwidth="20" w:space="0" w:color="000000"/>
                                      <w:left w:val="single" w:sz="8" wx:bdrwidth="20" w:space="0" w:color="000000"/>
                                      <w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                  </w:tcBorders>
                                  <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                                  <w:noWrap/>
                                  <w:vAlign w:val="center"/>
                              </w:tcPr>
                              <w:p>
                                  <w:pPr>
                                      <w:keepNext w:val="off"/>
                                      <w:keepLines w:val="off"/>
                                      <w:widowControl/>
                                      <w:supressLineNumbers w:val="off"/>
                                      <w:jc w:val="center"/>
                                      <w:textAlignment w:val="center"/>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体"
                                                    w:hint="fareast"/>
                                          <w:b/>
                                          <w:b-cs/>
                                          <w:i w:val="off"/>
                                          <w:i-cs w:val="off"/>
                                          <w:color w:val="000000"/>
                                          <w:sz w:val="28"/>
                                          <w:sz-cs w:val="28"/>
                                          <w:u w:val="none"/>
                                      </w:rPr>
                                  </w:pPr>
                                  <w:r>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体"
                                                    w:hint="fareast"/>
                                          <w:b/>
                                          <w:b-cs/>
                                          <w:i w:val="off"/>
                                          <w:i-cs w:val="off"/>
                                          <w:color w:val="000000"/>
                                          <w:kern w:val="0"/>
                                          <w:sz w:val="28"/>
                                          <w:sz-cs w:val="28"/>
                                          <w:u w:val="none"/>
                                          <w:lang w:val="EN-US" w:fareast="ZH-CN" w:bidi="AR-SA"/>
                                      </w:rPr>
                                      <w:t>拜访记录表</w:t>
                                  </w:r>
                              </w:p>
                          </w:tc>
                      </w:tr>
                      <w:tr>
                          <w:tblPrEx>
                              <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                              <w:tblCellMar>
                                  <w:top w:w="0" w:type="dxa"/>
                                  <w:left w:w="108" w:type="dxa"/>
                                  <w:bottom w:w="0" w:type="dxa"/>
                                  <w:right w:w="108" w:type="dxa"/>
                              </w:tblCellMar>
                          </w:tblPrEx>
                          <w:trPr>
                              <w:cantSplit w:val="on"/>
                              <w:trHeight w:val="600" w:h-rule="atLeast"/>
                          </w:trPr>
                          <w:tc>
                              <w:tcPr>
                                  <w:tcW w:w="1596" w:type="dxa"/>
                                  <w:tcBorders>
                                      <w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:left w:val="single" w:sz="8" wx:bdrwidth="20" w:space="0" w:color="000000"/>
                                      <w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                  </w:tcBorders>
                                  <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                                  <w:noWrap/>
                                  <w:vAlign w:val="center"/>
                              </w:tcPr>
                              <w:p>
                                  <w:pPr>
                                      <w:keepNext w:val="off"/>
                                      <w:keepLines w:val="off"/>
                                      <w:widowControl/>
                                      <w:supressLineNumbers w:val="off"/>
                                      <w:jc w:val="center"/>
                                      <w:textAlignment w:val="center"/>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体"
                                                    w:hint="fareast"/>
                                          <w:i w:val="off"/>
                                          <w:i-cs w:val="off"/>
                                          <w:color w:val="000000"/>
                                          <w:sz w:val="22"/>
                                          <w:sz-cs w:val="22"/>
                                          <w:u w:val="none"/>
                                      </w:rPr>
                                  </w:pPr>
                                  <w:r>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体"
                                                    w:hint="fareast"/>
                                          <w:i w:val="off"/>
                                          <w:i-cs w:val="off"/>
                                          <w:color w:val="000000"/>
                                          <w:kern w:val="0"/>
                                          <w:sz w:val="22"/>
                                          <w:sz-cs w:val="22"/>
                                          <w:u w:val="none"/>
                                          <w:lang w:val="EN-US" w:fareast="ZH-CN" w:bidi="AR-SA"/>
                                      </w:rPr>
                                      <w:t>日期</w:t>
                                  </w:r>
                              </w:p>
                          </w:tc>
                          <w:tc>
                              <w:tcPr>
                                  <w:tcW w:w="2283" w:type="dxa"/>
                                  <w:tcBorders>
                                      <w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:left w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                      <w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="000000"/>
                                  </w:tcBorders>
                                  <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
                                  <w:noWrap/>
                                  <w:vAlign w:val="center"/>
                              </w:tcPr>
                              <w:p>
                                  <w:pPr>
                                      <w:jc w:val="center"/>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体"
                                                    w:hint="fareast"/>
                                          <w:i w:val="off"/>
                                          <w:i-cs w:val="off"/>
                                          <w:color w:val="000000"/>
                                          <w:sz w:val="22"/>
                                          <w:sz-cs w:val="22"/>
                                          <w:u w:val="none"/>
                                      </w:rPr>
                                  </w:pPr>
                                  <w:r>
                                      <w:rPr>
                                          <w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:cs="宋体" w:hint="default"/>
                                          <w:color w:val="000000"/>
                                          <w:sz w:val="22"/>
                                          <w:sz-cs w:val="22"/>
                                      </w:rPr>
                                      <w:t>${item.visitDate}</w:t>
                                  </w:r>
                              </w:p>
                          </w:tc>
      
      </#list>
      
  2. Java代码示例

    • 初始化FreeMarker环境

              <dependency>
                  <groupId>org.freemarker</groupId>
                  <artifactId>freemarker</artifactId>
                  <version>2.3.31</version>
              </dependency>
      
    • 加载模板文件

      		//封装map
              Map<String, Object> dataMap = new HashMap<>();
              Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
              configuration.setDefaultEncoding("utf-8");
              configuration.setClassForTemplateLoading(this.getClass(), "/templates");
              Template template = configuration.getTemplate("销售报告模板.ftl");
      
    • 将数据模型绑定到模板,dataMap替换基本信息,list去替换表格信息

    • //省略具体获取数据步骤, 这个根据实际情况查询就可
      dataMap.put("levelOneVisits", levelOneVisits);
      dataMap.put("levelTwoVisits", levelTwoVisits);
      dataMap.put("levelThreeVisits", levelThreeVisits);
      dataMap.put("managerCoVisits", managerCoVisits);
      dataMap.put("pharmacyVisits", pharmacyVisits);
      dataMap.put("list1", list2);
      dataMap.put("list2", list1);
      dataMap.put("itemsList", itemsList);
      		// 输出
              File outFile = new File(path);
              Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
              try {
                  template.process(dataMap, out);
                  out.flush();
                  out.close();
              } catch (TemplateException e) {
                  e.printStackTrace();
              }
      
    • 输出生成的Word文档

附录

  • 相关资源链接:FreeMarker官方文档:https://freemarker.apache.org/docs/
  • 26
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值