官网原文https://freemarker.apache.org/
看不进去,所以就自己翻译一下官网原文,但是感觉速度太慢啦!!!
什么是Apache FreeMarker
apache freemarker 是一个模板引擎,一个基于模板和变化的数据去生成输出文本(HTML 网站页面,邮箱,配置文件,源代码等等)的java库。模板是用freeMarker 模板语言(FTL)(并不是一个像PHP那样的成熟语言),一个简单特殊的语言去写的。通常情况下,一个通用编程语言如java去准备数据(查询db,做业务计算),然后Apache freemarker去使用模板展示数据。在模板中你关注的是怎样呈现数据,在模板之外,你要关注的是呈现的是哪些数据
这种方法被称为MVC模式(model View Controller),并且在动态网页中特别受欢迎。并且对前后端分离非常有帮助,前端页面的设计者在使用模板中不用面对复杂的后台逻辑,并且可以在不修改工程或者重新编译的情况下,去改变前端页面的样式
freemarker最初是为了在MVC框架模式中生成HTML页面所创造的,但它并不非得绑定到servlets 或者 HTML或者与web关联,它是可以用在非web应用环境中的
特点
一些freemarker的优势
1.强大的模板语言,Conditional blocks(条件块), iterations(迭代), assignments, string and arithmetic operations(算术运算) and formatting(格式化), macros(宏) and functions(函数),可以引入其他模板语言,默认下是此功能时关闭的
2.多用途和轻量级的:0依赖,任何的输出格式,能够从任何地方加载模板(插入),有许多配置选项
3.国际化/根据语言环境而变化:可以根据语言环境使其数字,数据/时间格式变化,也可以局部模板发生变化
4.处理XML功能:可以删除xml DOM-S,也可以遍历它们,甚至可以声明它们
5.通用数据模板:通过插入适配器,在模板中的java对象可以作为变量树,决定模板如何看待它们
许可
Apache FreeMarker is Free software, licensed under the Apache License, Version 2.0. See the license here....
Note that the project is owned by the Apache Software Foundation since 2.3.24-pre01 (2015-09-02). Earlier releases, such as 2.3.23, has a different copyright owner.
模板+数据模型=输出
假设你需要一个网站的前端页面,和下面的类似
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome John Doe!</h1>
<p>Our latest product:
<a href="products/greenmouse.html">green mouse</a>!
</body>
</html
但是用户的名字是根据登录者的不同去变化的,最新的数据来自db中,由于这个数据是变化的,所以无法使用静态HTML,此时可以使用要求输出模板,模板和静态HTML相同,只是它会包含一些freemarker指令使其变为动态
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
这个模板存储在web服务器,和静态HTML页面相同,当有人来访问这个页面,freemarker会介入,将html中的模板${...}动态替换成最新的内容,并且将结果返回用户浏览的浏览器。用户的web浏览器会接受到一个和第一个实例代码类似的html页面(不含有freemarker指令),并且服务器中的模板不会被改变,替换只是出现在web 服务的相应中
注意。模板当中不含有查找当前访问者是谁的逻辑,或者去查询数据库获取最新数据的逻辑,被显示的数据是在freemarker之外事先准备的,通常是由java等编程语言去获取的。模板的使用者不需要知道这些值是如何计算的。事实上,这些值可以被修改,但是模板完全不变,页面样式可以被改变,模板也不改变,当前后端分离时,freemarker是非常有用的。保证模板专注于显示问题(视觉设计,布局和格式化)是高效使用模板引擎的关键
为模板准备的全部数据被称为数据-模型,模板作者要关心的是,数据模型是一个树形结构(像在硬盘上的文件夹和文件),这些数据模型可以看做下面的结构
注意:上面仅仅是一个形象化的描述,数据模型不是文本格式,它来自java对象,对于java程序员来说,root 也许是一个有getUser和getLastesProduce方法的java对象,或者是一个带有user 和 latestProdects key的java Map,同样的,latestProdect 也许是一个java对象带有getUrl 和 getName方法
早期时候,可以通过user,lastProdect.name获取数据,如果我们继续类比,数据模型就像一个文件系统,root 和 latestProdect就像是文件夹,user,url 和 name是这些目录中的文件
概括来说,在freemarker中使用模板+数据模型完成数据输出
Template + data-model = output
数据模型一览
如下图所见,数据模型就像是一个基本的树,这个树结构可以越来越复杂,有更深的深度
这些扮演文件夹的变量(root,animals,mouse,elephant,python,misc)被称为hashes,hashes存储其他变量(子变量),可以通过名字查找他们
这些存储数值的变量被称为scalars
当想在模板中使用子变量,你需要从根指定它的路径,并且用点去分割。想访问price 或者 mouse,应该写为animals.mouse.price
另一个重要的变量是序列(sequences),他们想hashes一样存储子节点,但是子节点没有名字,他们仅仅在一个list当中,在这个数据模型中,animals和misc,fruits是序列
可以使用方括号加数字索引去访问一个序列,索引从0开始,获取animal的第一个名字就写成animals[0].name(实际中,一般只会按顺序遍历数据,而不是关心索引).
Scalars可以分为以下类别
1.字符串
2.数字
3.时间
4.布尔
总结:
1.数据模型可以看出树形
2.scalars存储一个值,这个值可以是字符串,数字,时间,布尔
3.hashes是一个存储变量的容器,可以通过名字查找他们
4.序列是一个顺序存储遍历的容器,索引从0开始
模板一览
最简单的模板是一个纯HTML文件(freemarker并不是HTML)当客户浏览页面时,freemarker将返送html到客户端,但是想要页面有更多动态的部分,需要在页面加入能被freemarker解析的代码
${...}:freemarker将真实的数据输出到方括号当中,被称为interpolations
FTL tags:FTL tags 和 HTML tags比较相似,但是它们属于freemarker的指令,并且不会对外输出,这些tag的名字以#开头(自定义的tags需要使用@来开头)
Commets:注释和html注释相似,都是通过该<#--内容-->来注释,不像html注释那样,FTL注释不会出现在输出中
其他不是FTL标签或者interpolation或者注释的都会被认作静态文本,并输出到页面
FTL标签也被称为指令,和html标签和html元素相似
一些基本的指令
if指令
通过if指令,可以选择性跳过模板
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>
Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>!
</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
让我们详细说说condition:==是一个基本的操作如果左侧的值与右侧的值相等,并且结果是一个布尔值,等号左侧是引用的变量,这种语法结构我们已经很熟悉了。这个变量值将会被等号右侧所替代。总结来说,没有被引号标注的都会被视为变量。
右侧是字符串,在模板中的字符串只能放在引号内
<#if animals.python.price == 0>
Pythons are free today!
</#if>
<#if animals.python.price != 0>
Pythons are not free today!
</#if>
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
</#if>
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#else>
Pythons are not cheaper than elephants today.
</#if>
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#elseif animals.elephant.price < animals.python.price>
Elephants are cheaper than pythons today.
<#else>
Elephants and pythons cost the same today.
</#if>
<#if animals.python.protected>
Pythons are protected animals!
</#if>
list指令
如果需要把数据列出来,举例如果想这个模板与数据模型合并,要像下面这样
<p>We have these animals:
<table border=1>
<#list animals as animal>
<tr><td>${animal.name}<td>${animal.price} Euros
</#list>
</table>
如果用list,如果list中为0,还是会执行一下循环中的值,所以可以用item
<#list misc.fruits>
<ul>
<#items as fruit>
<li>${fruit}
</#items>
</ul>
</#list>
其他比较频繁使用的list:
<p>Fruits: <#list misc.fruits as fruit>{fruits?join(", ", "None")}*
所有指令( (list, items, sep, else))可以一起使用
<#list misc.fruits>
<p>Fruits:
<ul>
<#items as fruit>
<li>${fruit}<#sep> and</#sep>
</#items>
</ul>
<#else>
<p>We have no fruits.
</#list>
include 指令
使用include指令你可以将其他文件的内容放入模板
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
被引用的文件copyright_footer.html
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>
联合使用指令
<#list animals as animal>
<div<#if animal.protected> class="protected"</#if>>
${animal.name} for ${animal.price} Euros
</div>
</#list>
注意freemarker并不解析FTL 标签,interpolations 和FTL 注释以外的其他文本,注释,和interpolations
使用内建函数
内建函数很像子变量(或者更像java中的方法),并不来自数据-模型,但是通过freemarker添加的。为了获知自变量是从哪里来的,你需要用?去代替.
1.user?upper_case给出user的大写形式
2.animal.name?cap_first使其首字母大写
3.user?length给出user的字符数量
4.animals?size给出animals序列中项目的个数
5.如果在<#list animals as animals>和</#list>中
1.animal?index 提供基于0的所有数
2.animal?counter 很像索引,但是是基于1的索引
3.animal?item_parity 基于当前计数的奇偶,给出字符串"odd"或者"even",这个在给行着色的时候特别有用,比如"<td class="${animal?item_parity}Row">"
一些内建函数需要参数来指定行为
1.animal.protected?string("Y","N")根据animal.protected去返回Y或者N
2.animal?item_cycle('lightRow','darkRow')是之前itme_parity更常见的变体
3.fruits?join(","):将list 转换为string,并且用分隔符的参数去连接它们(like "orange, banana")
4.user?starts_with("J")根据user的首字符是否是J给出true或者false
5.animal?filter(it -> it.protected)展示受保护的元素
animals?filter(it -> it.protected) gives the list of protected animals.
<#list animals?filter(it -> it.protected) as animal>...</#list>.
处理不存在的数据
数据模型经常有变量是不存在的,除了一些特殊的人为错误,freemarker是无法忍受不存在的变量的,以下是最常用的两种处理方法
当指向一个变量,你可以在变量名后面加!去指定一个默认值当变量缺失,像下面的情况,当user在数据模型中缺失,模板将显示"visitor".(当user没有丢失,模板将显示数据)
<h1>Welcome ${user!"visitor"}!</h1>
也可以在名字后面加??来询问变量是否缺失,如果这个user缺失,那么你可以跳过此访问
<#if user??><h1>Welcome ${user}!</h1></#if>
转义其他的HTML,XML和其他的markup
如果{name}会输出"Someone & Co."
使用ftlh,freemarker将自动转义Html中的所有带有${...}
<#ftl output_format="HTML">
(如果生成的是XML,则使用XML代替HTML)
此方法需要版本在2.3.24以上
基本类型
理解数值和类型的概念是理解数据类型的基础,但是数据和类型并不局限于数据模型
什么是数值
![image.png](https://upload-images.jianshu.io/upload_images/24525532-28a067124367174d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我们说user变量值为"Big Joe",today值为Jul 6, 2007,,,,lotteryNumbers里面有很多值,并且包含很多值,这就像一个盒子包含其他一些东西(容器),整个盒子会被看成一个独立的主题,最后还有一个数值cargo,他是一个hash值,所以,一个值有时可以存储在一个变量中,但是不需要存储在变量中的数值也可以成为数值
<#if cargo.weight < 100>Light cargo</#if>
什么是类型
数值有一个很重要的方面,他们的类型
一个数值可以同时包含很多类型
数据模型是一个hash
看了不同的数据模型实例可能会意识到:被root标识的内容,仅仅是一种类型hash的值,但编写类似user,那就意味着想要将user存储到root hash上,这里没有名为root的变量,就起不到任何作用