本文最后更新于:December 8, 2022 pm
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
目录
FreeMarker中文手册
本文仅记录了在Java中的一些基础使用。
快速了解
这里以一个Demo为例,快速生成一个自定义模板的Java类。这里将其方法封装成一个方法,方便后续学习和使用,后续生成模板时均是调用此方法生成。方法如下:
依赖
| <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> </dependency>
|
GenerateTemplateApi.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.tothefor.motorcode.component.GenerateTemplate;
import freemarker.template.Configuration;
import java.util.Map;
public interface GenerateTemplateApi {
<T> void generateTemplate(String baseTemplatePath, String templateFile, String classPath, String className, Map<String, T> dataMap);
}
|
GenerateTemplateApiImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package com.tothefor.motorcode.component.GenerateTemplate;
import freemarker.template.Configuration; import freemarker.template.Template; import org.springframework.stereotype.Service;
import java.io.File; import java.io.FileWriter; import java.util.Map;
@Service public class GenerateTemplateApiImpl implements GenerateTemplateApi {
private static final Configuration FREE_MAKER_CONFIG = new Configuration(Configuration.VERSION_2_3_28);
@Override public <T> void generateTemplate(String baseTemplatePath, String templateFile, String classPath, String className, Map<String, T> dataMap) { FREE_MAKER_CONFIG.setDefaultEncoding("UTF-8");
FileWriter fileWriter = null; try { FREE_MAKER_CONFIG.setDirectoryForTemplateLoading(new File(baseTemplatePath)); Template template = FREE_MAKER_CONFIG.getTemplate(templateFile); File file = new File(classPath + "/" + className + ".java"); fileWriter = new FileWriter(file); template.process(dataMap, fileWriter); fileWriter.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fileWriter != null) { fileWriter.close(); } } catch (Exception e) { e.printStackTrace(); }
} } }
|
测试
这里简单用一个模板进行测试:
test.ftl
| package ${package};
String PROJECT = "${title}";
|
然后,调用上面的方法,传入对应的参数。
| @Test void testFtl() { String baseTemplatePath = "src/main/resources/freemarker/project"; String filePath = "test.ftl"; String classPath = "src/main/java/com/tothefor"; HashMap<String, String> map = new HashMap<>(); map.put("package", "com.tothefor"); map.put("title", "totheforsssss");
GenerateTemplateApi().generateTemplate(baseTemplatePath, filePath, classPath, "ttttt", map); }
|
最后就可以在对应位置看见生成的Java类了。
数据类型
FreeMarker模板中的数据类型有以下几种,以及对应Java中的类型:
- 布尔值:对应Java中的Boolean类型。但是不能直接输出,需要转换为字符串输出。
- 日期型:对应Java中的Date类型。但是不能直接输出,需要转换为字符串输出。
- 数值型:对应Java中的int、float、double等数值类型。有三种显示形式:数值型(默认)、货币型、百分比型。
- 字符型:对应Java中的字符串,有很多内置函数。
- sequence类型:对应Java中的数组,list、set等集合类型。
- hash类型:对应Java中的Map类型。
布尔类型
不能直接输出,则需要先转换为字符串再输出(借助内建函数),所以有两种方式:
- 方式一:?c
- 方式二:?string 或者 ?string(“true时的文本”,”false时的文本”)
更多用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package ${package};
/** * @Author DragonOne * @Date 2022/12/4 14:13 * @墨水记忆 www.tothefor.com */ public class ttttt { public static void main(String[] args) { String PROJECT = "${title}";
boolean flag = ${flag}; if(flag){ System.out.println("yes"); }else{ System.out.println("no"); } } }
|
测试
| @Test void testMain() { String baseTemplatePath = "src/main/resources/freemarker/project"; String filePath = "test.ftl"; String classPath = "src/main/java/com/tothefor"; HashMap<String, Object> map = new HashMap<>(); map.put("package", "com.tothefor"); map.put("title", "totheforsssss"); map.put("flag", "true"); GenerateTemplateApi().generateTemplate(baseTemplatePath, filePath, classPath, "ttttt", map); }
|
日期类型
更多用法
自动生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package ${package}; /** * @Author DragonOne * @Date ${.now} * @墨水记忆 www.tothefor.com */ public class ttttt { public static void main(String[] args) { String PROJECT = "${title}";
String Tests="${flag}"; boolean flag = true; if(flag){ System.out.println("yes"); }else{ System.out.println("no"); } } }
|
生成效果:
指定时间
| /** * @Author DragonOne * @Date ${DATE?date} * @墨水记忆 www.tothefor.com */
|
传入值:
| map.put("DATE", new Date());
|
效果:
更多用法
不能使用:${DATE?datetime(“yyyy-MM-dd HH:mm:ss”)}。因为datetime的类型在月份只有一位数时,显示的就是一位数,而转换需要两位数(前面补0)。可见下面用例的区别。
| /** * @Author DragonOne * @Date ${DATE?date} * @Date ${DATE?time} * @Date ${DATE?datetime} * @Date ${DATE?string("yyyy-MM-dd HH:mm:ss")} * @墨水记忆 www.tothefor.com */
|
效果:
数值类型
可以直接输出,也可以转换成字符串输出。
- 转普通字符串:?c
- 转货币型字符串:?string.currency
- 转百分比型字符串:?string.percent
- 保留浮点数,指定小数(#表示一个小数位,两个表示保留两位小数):?string[“0.##”]
| String s1="${numA}"; String s2="${numB}"; String s3="${numB?c}"; String s4="${numB?string.currency}"; String s5="${numC?c}"; String s6="${numC?string.currency}"; String s7="${numC?string.percent}"; String s8="${numC?string["0.##"]}";
|
效果:(会四舍五入)
| String s1="11"; String s2="12.34"; String s3="12.34"; String s4="¥12.34"; String s5="0.3456"; String s6="¥0.35"; String s7="35%"; String s8="0.35";
|
字符串类型
更多用法
常用函数:
截取字符串(左闭右开):?substring(start,end)。
首字母小写输出:?uncap_first。
首字母大写输出:?cap_first。
字母转小写输出:?lower_case。
字母转大写输出:?upper_case。
获取字符串长度:?length。
是否以指定字符开始(布尔类型):?starts_with(“xxx”)。
是否以指定字符结尾(布尔类型):?ends_with(“xxx”)。
获取指定字符的索引:?index_of(“xx”)。
去除字符串前后空格:?trim。
替换指定字符串:?replace(“xx”,”sss”)
空值处理
FreeMarker的变量必须赋值,否则会抛出异常。对于FreeMarker来说,null值和不存在的变量是一样的,因为FreeMarker无法理解null值。FreeMarker提供了两个运算符来避免空值:
示例:
| String nullStrA="${nullStrA!}"; String nullStrAA="${nullStrA!"nullStrA默认值"}"; String nullStrAAA="${(nullStrA??)?string}"; String nullStrB="${nullStrB!}"; String nullStrBB="${nullStrB!"nullStrB默认值"}"; String nullStrBBB="${(nullStrB??)?string}";
|
传入值:
| map.put("nullStrA",null); map.put("nullStrB","");
|
效果:
| String nullStrA=""; String nullStrAA="nullStrA默认值"; String nullStrAAA="false"; String nullStrB=""; String nullStrBB=""; String nullStrBBB="true";
|
sequence类型
适用于:数组、List等。
介绍:
| <#list 序列名 as 元素名> ${元素名} </#list> 获取序列长度:${序列名?size} 获取序列元素的下标:${元素名?index} 获取第一个元素:${序列名?first} 获取最后一个元素:${序列名?last}
倒序输出 序列名?reverse 升序输出 序列名?sort 降序输出 序列名?sort?reverse 指定字段名排序 序列名?sort_by("字段名") 注意:JavaBean集合,对应的字段名需要提供get方法
|
插入数据:
| String[] strings = new String[]{"aaaa","bbbb","cccc","dddd"}; map.put("stringArray",strings);
|
模板使用:
| <#list stringArray as it> // 下标为 ${it?index} String ${it} = "${it}"; </#list> // 元素个数为:${stringArray?size} // 第一个元素为:${stringArray?first} // 最后一个元素为:${stringArray?last}
|
效果:
| String aaaa = "aaaa";
String bbbb = "bbbb";
String cccc = "cccc";
String dddd = "dddd";
|
其他操作
模板使用:
| <#list stringArray?reverse as it> // 下标为 ${it?index} String ${it} = "${it}"; </#list>
|
效果实现:
| String dddd = "dddd";
String cccc = "cccc";
String bbbb = "bbbb";
String aaaa = "aaaa";
|
其他操作同理,如:
| <#list stringArray?sort as it> // 下标为 ${it?index} String ${it} = "${it}"; </#list>
<#list stringArray?sort?reverse as it> // 下标为 ${it?index} String ${it} = "${it}"; </#list>
|
如果是JavaBean,指定字段排序:(假定类有age字段)
| <#list stringArray?sort_by("age") as it> // 下标为 ${it?index} String ${it} = "${it}"; </#list>
|
Hash类型
使用Hash类型。有两种遍历方式:key遍历输出、value遍历输出。
介绍:
| key遍历输出: <#list hash?keys as key> ${key} -- ${hash[key]} </#list>
value遍历输出: <#list hash?values as value> ${value} </#list>
|
添加数据:
| Map<String, Integer> hashMap = new HashMap<>(); hashMap.put("aaa", 111); hashMap.put("bbb", 222); hashMap.put("ccc", 333); map.put("hashMap", hashMap);
|
模板使用:
| <#list hashMap?keys as key> ${key} -- ${hashMap[key]} </#list> <#list hashMap?values as value> #{value} </#list>
|
效果实现:
| aaa -- 111 ccc -- 333 bbb -- 222 111 333 222
|