【Freemarker】Freemarker简介以及基本使用
1. 什么是Freemarker?
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
目前企业中:主要用Freemarker做静态页面或是页面展示
这种方式通常被称为 MVC (模型 视图 控制器) 模式,对于动态网页来说,是一种特别流行的模式。 它帮助从开发人员(Java 程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑, 在没有程序员来修改或重新编译代码时,也可以修改页面的样式。
而FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中。
2. Freemarker 快速入门
2.1 环境搭建
创建maven工程并导入Freemarker的maven坐标
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
2.2 创建模板文件
模板文件中有四种元素:
-
文本:文本会照着原样来输出。
-
插值:这部分的输出会被计算的值来替换。插值由 ${ and } 所分隔(或者 #{ and },这种风格已经不建议再使用了)。
-
FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
-
注释:注释和HTML的注释也很相似,但它们是由 <#-- 和 -->来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。
Freemarker的模板文件后缀可以任意,一般建议为ftl。
我们来看一个具体的模板。其中的内容已经用颜色来标记了: 文本, 插值, FTL 标签, 注释。为了看到可见的 换行符, 这里使用了 [BR]。
我们来看一个具体的模板。其中的内容已经用颜色来标记了: 文本, 插值, FTL 标签, 注释。
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<#-- Greet the user with his/her name -->
<h1>Welcome ${user}!</h1>
<p>We have these animals:
<ul>
<#list animals as animal>
<li>${animal.name} for ${animal.price} Euros
</#list>
</ul>
</body>
</html>
FTL是区分大小写的。 list 是指令的名称而 List 就不是。类似地 ${name} 和 ${Name} 或 ${NAME} 也是不同的。
请注意非常重要的一点: 插值 仅仅可以在 文本 中使用。 (也可以是字符串表达式)
FTL 标签 不可以在其他 FTL 标签 和 插值中使用。比如, 这样做是 错误 的: <#if <#include 'foo'>='bar'>...</#if>
注释 可以放在 FTL 标签 和 插值中。比如:
<h1>Welcome ${user <#-- The name of user -->}!</h1>
<p>We have these animals:
<ul>
<#list <#-- some comment... --> animals as <#-- again... --> animal>
...
2.3 生成文件
使用步骤:
第一步:创建一个 Configuration 对象,直接 new 一个对象。构造方法的参数就是 freemarker的版本号。
第二步:设置模板文件所在的路径。
第三步:设置模板文件使用的字符集。一般就是 utf-8。
第四步:加载一个模板,创建一个模板对象。
第五步:创建一个模板使用的数据集,可以是 pojo 也可以是map。一般是 Map。
第六步:创建一个 Writer 对象,一般创建 FileWriter 对象,指定生成的文件名。
第七步:调用模板对象的 process 方法输出文件。
第八步:关闭流。
模板文件 test.ftl
<html>
<head>
<meta charset="utf-8">
<title>Freemarker入门</title>
</head>
<body>
<#--我只是一个注释,我不会有任何输出 -->
${name}你好,${message}
</body>
</html>
java文件
public static void main(String[] args) throws Exception{
//1.创建配置类
Configuration configuration=new Configuration(Configuration.getVersion());
//2.设置模板所在的目录
configuration.setDirectoryForTemplateLoading(new File("D:\\ftl"));
//3.设置字符集
configuration.setDefaultEncoding("utf-8");
//4.加载模板
Template template = configuration.getTemplate("test.ftl");
//5.创建数据模型
Map map=new HashMap();
map.put("name", "张三");
map.put("message", "欢迎来到私忆一秒钟的博客!");
//6.创建Writer对象
Writer out =new FileWriter(new File("d:\\test.html"));
//7.输出
template.process(map, out);
//8.关闭Writer对象
out.close();
}
运行结果生成:test.html文件
3. Freemarker 基本指令
3.1 assign 指令
assign指令用于在页面上定义一个变量
- 定义简单类型
<#assign linkman="私忆一秒钟">
联系人:${linkman}
- 定义对象类型
<#assign info={"mobile":"123456789",'address':'地球'}>
电话:${info.mobile} 地址:${info.address}
3.2 if 指令
if指令用于判断
- 在模板文件中使用if指令进行判断
<#if success=true>
你已通过实名认证
<#else>
你未通过实名认证
</#if>
- 在java代码中为success变量赋值
map.put("success", true);
在freemarker的判断中,可以使用=也可以使用==
3.3 list 指令
list指令用于遍历
- 在模板文件中使用list指令进行遍历
<#list goodsList as goods>
<li>${goods.name} , ${goods.price}
</#list>
- 在java代码中为goodsList赋值
List goodsList=new ArrayList();
Map goods1=new HashMap();
goods1.put("name", "苹果");
goods1.put("price", 5.8);
Map goods2=new HashMap();
goods2.put("name", "香蕉");
goods2.put("price", 2.5);
Map goods3=new HashMap();
goods3.put("name", "橘子");
goods3.put("price", 3.2);
goodsList.add(goods1);
goodsList.add(goods2);
goodsList.add(goods3);
map.put("goodsList", goodsList);
3.4 include 指令
include指令用于模板文件的嵌套
<#include "test.ftl">
4. 联合使用指令
在页面上也可以多次使用指令,而且指令间也可以很容易地相互嵌套。 比如,在 list 指令中嵌套 if 指令:
<#list animals as animal>
<div<#if animal.protected> class="protected"</#if>>
${animal.name} for ${animal.price} Euros
</div>
</#list>
请注意,FreeMarker并不解析FTL标签以外的文本、插值和注释, 上面示例在HTML属性中使用FTL标签也不会有问题。
5. 常用内建函数
内建函数很像子变量(如果了解Java术语的话,也可以说像方法), 它们并不是数据模型中的东西,是 FreeMarker 在数值上添加的。 为了清晰子变量是哪部分,使用 ?(问号)代替 .(点)来访问它们。常用内建函数的示例:
-
user?html
给出 user 的HTML转义版本, 比如&
会由&
来代替。 -
user?upper_case
给出 user 值的大写版本 (比如 “JOHN DOE” 来替代 “John Doe”) -
animal.name?cap_first
给出 animal.name 的首字母大写版本(比如 “Mouse” 来替代 “mouse”) -
user?length
给出 user 值中 字符的数量(对于 “John Doe” 来说就是8) -
animals?size
给出 animals 序列中 项目 的个数(我们示例数据模型中是3个) -
如果在
<#list animals as animal>
和对应的</#list>
标签中:-
animal?index
给出了在 animals 中基于0开始的 animal的索引值 -
animal?counter
也像 index, 但是给出的是基于1的索引值 -
animal?item_parity
基于当前计数的奇偶性,给出字符串 “odd” 或 “even”。在给不同行着色时非常有用,比如在<td class="${animal?item_parity}Row">
中。
-
一些内建函数需要参数来指定行为,比如:
-
animal.protected?string("Y", "N")
基于 animal.protected 的布尔值来返回字符串 “Y” 或 “N”。 -
animal?item_cycle('lightRow','darkRow')
是之前介绍的 item_parity 更为常用的变体形式。 -
fruits?join(", ")
通过连接所有项,将列表转换为字符串, 在每个项之间插入参数分隔符(比如 “orange,banana”) -
user?starts_with("J")
根据 user 的首字母是否是 “J” 返回布尔值true或false。
内建函数应用可以链式操作,比如user?upper_case?html 会先转换用户名到大写形式,之后再进行HTML转义。(这就像可以链式使用 .(点)一样)
6. 处理不存在的变量
数据模型中经常会有可选的变量(也就是说有时并不存在)。 除了一些典型的人为原因导致失误外,FreeMarker 绝不能容忍引用不存在的变量, 除非明确地告诉它当变量不存在时如何处理。这里来介绍两种典型的处理方法。
这部分对程序员而言: 一个不存在的变量和一个是 null 值的变量, 对于FreeMarker来说是一样的,所以这里所指的"丢失"包含这两种情况。
不论在哪里引用变量,都可以指定一个默认值来避免变量丢失这种情况, 通过在变量名后面跟着一个 !(叹号)和默认值。 就像下面的这个例子,当 user 不存在于数据模型时, 模板将会将 user 的值表示为字符串 “visitor”。(当 user 存在时, 模板就会表现出 ${user} 的值):
<h1>Welcome ${user!"visitor"}!</h1>
也可以在变量名后面通过放置 ?? 来询问一个变量是否存在。将它和 if 指令合并, 那么如果 user 变量不存在的话将会忽略整个问候的代码段:
<#if user??><h1>Welcome ${user}!</h1></#if>