FreeMarker 是一款免费的模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件,也可以通过模板来生成Word、pdf、Excel
普通项目
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
SpringBoot项目
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
一般FreeMarker的模板文件后缀名为:.ftl
,模板文件中有四种元素:
<#-- … -->
格式不会输出Interpolation
):即${…}
部分,将使用数据模型中的部分替代输出FTL
指令:FreeMarker
指令,和HTML
标记类似,名字前加#
予以区分,不会输出<#-- 注释 -->
<body>${name}</body>
assign指令用于在页面上定义一个变量
<#-- 定义变量 -->
<#assign linkman="周先生">
<#-- 使用变量 -->
联系人:${linkman}
<#-- 定义变量 -->
<#assign info={"mobile":"13812345678",'address':'北京市昌平区'} >
<#-- 使用变量 -->
电话:${info.mobile} 地址:${info.address}
模板嵌套,在指定位置引入指定模板
<#include "head.ftl"/>
在模板文件中使用if
指令进行判断
<#if isSuccess=true>
你已通过实名认证
<#else>
你未通过实名认证
</#if>
在模板文件中使用list
指令进行遍历
<#list goodsList as goods>
第${goods?index}个商品,商品名称:${goods.name},价格:${goods.price}<br>
</#list>
Freemarker不支持null值,会报错,可以对空值进行处理
<#--不存在则什么都不显示-->
${abc!}
<#--如果为空,则显示没有字符-->
${abc!'没有字符'}
${flag?string("Yes","No")}
<#--格式化-->
${date?string("yyyy-MM-dd HH:mm:ss")}
<#--格式化,为null则不显示-->
${date?string("yyyy-MM-dd HH:mm:ss")!}
${变量名}
替换。.xml
的格式,并检查看格式是否有误(主要看占位符有没被分割开来)。.xml
改成.ftl
后(可以不改) public static void generateWord(Map<String,Object> map) throws Exception {
// 设置FreeMarker的版本和编码格式
Configuration configuration = new Configuration(Configuration.getVersion());
configuration.setDefaultEncoding("UTF-8");
// 设置FreeMarker生成Word文档所需要的模板的 绝对路径
// configuration.setDirectoryForTemplateLoading(new File("/Users/yanggang/Desktop/"));
// 设置FreeMarker生成Word文档所需要的模板 ClassPath下
configuration.setClassForTemplateLoading(XsReportGenerator.class, "/templates");
// 设置FreeMarker生成Word文档所需要的模板
Template tem = configuration.getTemplate("模板.xml", "UTF-8");
// 创建一个Word文档的输出流,生成到本地
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("/Users/yanggang/Desktop/生成结果.docx")), StandardCharsets.UTF_8));
tem.process(map, out);
out.flush();
out.close();
}
在我们编辑好Word模板,转成xml时,有的占位符会被分割,那么我们可以使用如下的程序对xml模板文件进行整理
注意:使用下面程序整理xml模板文件时,不要格式化
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</dependency>
package top.ygang;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileAppender;
import cn.hutool.core.io.file.FileReader;
import java.util.List;
/**
* Author: yanggang
* Date: 2023-12-11 16:41:51
*/
public class Main {
public static void main(String[] args) {
//文件读取-FileReader
//默认UTF-8编码,可以在构造中传入第二个参数作为编码
FileReader fileReader = new FileReader("/Users/yanggang/Desktop/模板.xml");
//从文件中读取每一行数据
List<String> strings = fileReader.readLines();
//文件追加-FileAppender
//destFile – 目标文件
//capacity – 当行数积累多少条时刷入到文件
//isNewLineMode – 追加内容是否为新行
FileAppender appender = new FileAppender(FileUtil.newFile("/Users/yanggang/Desktop/模板new.xml"), 16, true);
//遍历得到每一行数据
for (String string : strings) {
//判断每一行数据中不包含'$'的数据先添加进新文件
if (!string.contains("$")) {
appender.append(string);
continue;
}
//如果一行数据中包含'$'变量符将替换为'#$'
string = string.replaceAll("\\$", "#\\$");
//然后以'#'切割成每一行(数组),这样一来'$'都将在每一行的开头
String[] ss = string.split("#");
// 同一行的数据写到同一行,文件追加自动换行了(最后的完整数据)
StringBuilder sb = new StringBuilder();
//遍历每一行(数组ss)
for (int i = 0; i < ss.length; i++) {
//暂存数据
String s1 = ss[i];
//将不是以'$'开头的行数据放进StringBuilder
if (!s1.startsWith("$")) {
sb.append(s1);
continue;
}
//被分离的数据一般都是'${'这样被分开
//匹配以'$'开头的变量找到'}' 得到索引位置
int i1 = s1.lastIndexOf("}");
//先切割得到这个完整体
String substr = s1.substring(0, i1 + 1);
//把变量追加到StringBuilder
sb.append(substr.replaceAll("<[^>]+>", ""));
//再将标签数据追加到StringBuilder包裹变量
sb.append(s1.substring(i1 + 1));
}
appender.append(sb.toString());
}
appender.flush();
appender.toString();
}
}