Apache FreeMarker
是一个基于 Java
的报表引擎,之前听说过它可以生成 HTML
网页、源代码(代码生成器)等,但是使用 FreeMarker
导出 word
或 excel
文件却没有尝试过,不知道其中的可行性如何,不了解其中的大概操作流程怎样,遂有了此文。
准备操作实践环境
这里以一个新建的
springboot
项目作为操作实践环境
导入 FreeMarker
的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
报表模板设计
导出
word
或excel
文件可以看成导出word
格式 或excel
格式的报表
-
使用
word
编辑软件(如WPS Office
等)设计报表,下图所示为将要导出的word
文件样例
-
将上一步操作完成的
word
文件样例另存为xml
文件注意:不能直接修改文件的后缀名为 xml ,那样是无效的。修改文件后缀名不影响文件本身的内容。
3. 将 xml
文件的后缀名修改为 ftl
虽然这一步可以省略(因为修改文件后缀名不影响文件本身的内容),但是还是强烈建议将文件后缀名修改为
ftl
,这样能达到“见名知义”的效果,那样工作协作效率能高许多。
导出word格式报表
项目大体结构如下图所示,新建了一个 FreeMarkerTest
的 Java
类,报表文件放在 resources
目录下的 templates
其中 FreeMarkerTest
类里边创建了一个 main
方法用来导出 word
文件
package com.example.demo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
public class FreeMarkerTest {
public static void main(String[] args) throws Exception {
// 1. FreeMarker 初始化配置
Configuration configuration = new Configuration(Configuration.VERSION_2_3_26);
configuration.setDefaultEncoding("UTF-8");
configuration.setClassForTemplateLoading(FreeMarkerTest.class, "/templates/");
// 2. 获取模板
Template template = configuration.getTemplate("myReport.ftl");
// 3. 准备模板数据
Map<String, Object> dataMap = new HashMap<>();
// 4. 导出文件
File outFile = new File("C:/Users/ligs/Desktop/word测试.docx");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
template.process(dataMap, writer);
writer.flush();
writer.close();
System.out.println("导出文件完毕...");
}
}
执行上面的 main
方法,成功导出的 word
文件如下图所示。至此,可见使用 FreeMarker
报表引擎导出 word
文件是基本可行的。但是还有一个问题,目前导出的文件是静态的,它相当于原模板的一份拷贝,还无法做到根据具体数据进行动态填充报表文件。关于这个问题,继续往下探讨。
增加报表模板变量的再导出
使用 word
编辑软件打开 ftl
报表模板文件,将报表需动态改变的内容调整为占位符,占位符以 ${...}
这种变量形式表示。
${...}
是FreeMarker Template Language(FTL)
的语法,具体可以参考官网 https://freemarker.apache.org/docs/ref.html
调整程序,设置相应模板数据
// 3. 准备模板数据
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("reportTitle", "用户"); // 报告标题
dataMap.put("reporter", "admin"); // 报告人
dataMap.put("userName", "李四"); // 用户
dataMap.put("remark", "remark test"); // 备注
重新执行 FreeMarkerTest
的 main
方法,导出的 word
文件如下图所示。
总结
- 使用
FreeMarker
导出word
文件是可行的。excel
文件类似,只是报表模板设计及调整报表模板变量时需对应使用excel
编辑软件(注意不能混用,比如ftl
模板文件是由word
编辑软件设计转换而来的,那么调整报表模板变量或对模板进行调整设计时,也要使用word
编辑软件来调整。否则,报表模板无法正常显示,只是显示出一些文本内容)。 - 使用
FreeMarker
导出word
/excel
文件的大致流程:设计报表模板原型 => 调整报表模板变量 => 程序设置模板数据并导出。(在这个过程中,word
、excel
编辑软件既充当了报表设计工具,又充当了报表文件的查看工具) - 文中的
FreeMarkerTest
Java
类里边的代码只是为了快速进行技术验证,在实际项目中不能直接这样使用,其中还有许多要点需要注意:// 代码省略... public class FreeMarkerTest { // 要点1:实际项目中,FreeMarker 导出文件可能需要单独整理出来一个工具类 public static void main(String[] args) throws Exception { // 1. FreeMarker 初始化配置 // 代码省略... // 要点2:根据 FreeMarker 官网(https://freemarker.apache.org/)的介绍,FreeMarker 的配置实例应该仅初始化一次, // 比如仅在应用程序启动时初始化,后续整个应用程序都共用一个相同的 Configuration Configuration configuration = ...; // 2. 获取模板 Template template = configuration.getTemplate("xx.ftl"); // 3. 准备模板数据 Map<String, Object> dataMap = new HashMap<>(); // 代码省略... // 要点3:模板数据可以是一个 map 类型,也可以是一个带 get/set 方法的 JavaBean,等等 // 4. 导出文件 // 代码省略... File outFile = new File("xx.docx"); // 要点4:如果 ftl 模板原先由 excel 编辑软件设计的,这里应该导出 excel 格式(如 *.xlsx),保持一致,达到“见名知义”的效果 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile))); template.process(dataMap, writer); writer.flush(); writer.close(); // 要点5:资源的回收应该确保一定会得到执行,比如相应操作放在 try...catch...finally 中的 finally 块中。 } }