【FreeMarker模板引擎】2.freemarker数据结构、控制语句

上一篇我们学习了freemarker的基础知识,并实现和加载了一个freemarker的及本页面。
本篇我们来探讨一下freemarker的数据结构以及控制语句。

freemarker提供了一系列模板变量控制语句,使用其既定规则的数据结构以及输出语句,对
我们更好的展示页面数据提供很大的帮助。

在学习模板开发语句之前,先了解一下freemarker的数据结构。

一、数据结构
(1)直接指定值

直接指定值可以是字符串、数值、布尔值、集合及Map对象。
1. 字符串
直接指定字符串值使用单引号或双引号限定。字符串中可以使用转义字符”\"。如果字符串内有大量的特殊字符,则可以在引号的前面加上一个字母r,则字符串内的所有字符都将直接输出。

2. 数值
数值可以直接输入,不需要引号。FreeMarker不支持科学计数法。

3. 布尔值 
直接使用true或false,不使用引号。

4. 集合
集合用中括号包括,集合元素之间用逗号分隔。
使用数字范围也可以表示一个数字集合,如1..5等同于集合[1, 2, 3, 4, 5];同样也可以用5..1来表示[5, 4, 3, 2, 1]。

5. Map对象
Map对象使用花括号包括,Map中的key-value对之间用冒号分隔,多组key-value对之间用逗号分隔。
注意:Map对象的key和value都是表达式,但key必须是字符串。

6. 时间对象
root.put("date1", new Date());
${date1?string("yyyy-MM-dd HH:mm:ss")}

7. JAVABEAN的处理
Freemarker中对于javabean的处理跟EL表达式一致,类型可自动转化!非常方便!

(2)输出变量值
FreeMarker的表达式输出变量时,这些变量可以是顶层变量,也可以是Map对象的变量,还可以是集
合中的变量,并可以使用点(.)语法来访问Java对象的属性。

1. 顶层变量
所谓顶层变量就是直接放在数据模型中的值。输出时直接用${variableName}即可。

2. 输出集合元素
可 以根据集合元素的索引来输出集合元素,索引用中括号包括。如: 输出["1","2","3"]这个名为
number的集合,可以用${number[0]}来输出第一个数字。FreeMarker还支持用number[1..2]来表示原
集合的子集合["2","3"]。

3. 输出Map元素
对于JavaBean实例,FreeMarker一样把它看作属性为key,属性值为value的Map对象。
输出Map对象时,可以使用点语法或中括号语法,如下面的几种写法的效果是一样的:
book.author.namebook.author["name"]
book["author"].name
book["author"]["name"]
使用点语法时,变量名字有和顶层变量一样的限制,但中括号语法没有任何限制。

(3)字符串操作
1. 字符串连接
字符串连接有两种语法:
①使用${..}或#{..}在字符串常量内插入表达式的值;
②直接使用连接运算符“+”连接字符串。
如,下面两种写法等效:
${"Hello,${user}"}
${"Hello, " + user + "!"}
有一点需要注意: ${..}只能用于文本部分作为插值输出,而不能用于比较等其他用途,如:
<#if ${isBig}>Wow!</#if>
<#if "${isBig}">Wow!</#if>
应该写成:
<#if isBig>Wow!</#if>

2. 截取子串
截取子串可以根据字符串的索引来进行,如果指定一个索引值,则取得字符串该索引处的字符;如果指定两个索引值,则截取两个索引中间的字符串子串。如:
<#assign number="01234">
${number[0]} <#-- 输出字符0 -->
${number[0..3]} <#-- 输出子串“0123” -->

(4)集合连接操作

连接集合的运算符为“+”

(5)Map连接操作
Map连接操作的运算符为“+”

(6)算术运算符
FreeMarker表达式中支持“+”、“-”、“*”、“/”、“%”运算符。

(7)比较运算符
表达式中支持的比较运算符有如下几种:
1. =(或者==): 判断两个值是否相等;
2. !=: 判断两个值是否不相等;
注: =和!=可以用作字符串、数值和日期的比较,但两边的数据类型必须相同。而且FreeMarker的比
较是精确比较,不会忽略大小写及空格。
3. >(或者gt): 大于
4. >=(或者gte): 大于等于
5. <(或者lt): 小于
6. <=(或者lte): 小于等于
注: 上面这些比较运算符可以用于数字和日期,但不能用于字符串。大部分时候,
使用gt比>有更好的效果,因为FreeMarker会把>解释成标签的结束字符。可以使用
括号来避免这种情况,如:<#if (x>y)>。

if else 语句测试:
root.put("num0", 18);
<#if num0 gt 18>  <#-- 不是使用>,大部分时候,freemarker会把>解释成标签结束! -->
    及格!
<#else>
    不及格!
</#if>

(8)逻辑运算符
1. &&
逻辑与
2. ||
逻辑或
3. !
逻辑非
逻辑运算符只能用于布尔值。

(9)内建函数
FreeMarker提供了一些内建函数来转换输出,可以在任何变量后紧跟?,?后紧跟内建函数,就可以通
过内建函数来转换输出变量。

字符串相关常用的内建函数:
1. html: 对字符串进行HTML编码;
2. cap_first: 使字符串第一个字母大写;
3. lower_case: 将字符串转成小写;
4. upper_case: 将字符串转成大写;

集合相关常用的内建函数:
1. size: 获得集合中元素的个数;

数字值相关常用的内建函数:
1. int: 取得数字的整数部分。

举例:
root.put("htm2", "<b>粗体</b>");
内建函数:
${htm2?html}

(10)空值处理运算符
FreeMarker的变量必须赋值,否则就会抛出异常。而对于FreeMarker来说,null值和不存在的变量是
完全一样的,因为FreeMarker无法理解null值。
FreeMarker提供两个运算符来避免空值:
1. !
指定缺失变量的默认值;
2. ??
判断变量是否存在。
!运算符有两种用法:variable!或variable!defaultValue。
第一种用法不给变量指定默认值,表明默认值是空字符串、长度为0的集合、或长度为0的Map对象。

使用!运算符指定默认值并不要求默认值的类型和变量类型相同。

测试空值处理:
<#-- ${sss} 没有定义这个变量,会报异常! -->
${sss!} <#--没有定义这个变量,默认值是空字符串! -->
${sss!"abc"} <#--没有定义这个变量,默认值是字符串abc! -->

运算符返回布尔值,如:variable??,如果变量存在,返回true,否则返回false。
<#if user??><h1>欢迎${user}!</h1></#if>

总结:
数据类型常见示例
直接指定值 
    字符串 : "Foo"或 者'Foo'或"It's \"quoted\""或r"C:\raw\string" 
    数字:123.45 
    布尔值:true, false 
    序列:["foo", "bar", 123.45], 1..100 
    哈希表:{"name":"green mouse", "price":150} 
检索变量   
     顶层变量:user 
    从哈希表中检索数据:user.name, user[“name”] 
    从序列中检索:products[5] 
    特殊变量:.main 
字符串操作 
    插值(或连接):"Hello ${user}!"(或"Free" + "Marker") 
    获取一个字符:name[0] 
序列操作 
    连接:users + ["guest"] 
    序列切分:products[10..19]  或  products[5..] 
哈希表操作 
    连接:passwords + {"joe":"secret42"} 
    算数运算:(x * 1.5 + 10) / 2 - y % 100 
    比较运算: x==y,x!=y,x<y,x>y,x>=y,x<=y,x&lt;y,等等 
    逻辑操作:!registered && (firstVisit || fromEurope) 
    内建函数:name?upper_case 
    方法调用:repeat("What", 3) 
处理不存在的值 
    默认值:name!"unknown"或者(user.name)!"unknown"或者name!或者(user.name)! 
    检测不存在的值:name?? 或者(user.name)??

二、模板开发语句
如果需要在HTML页面放置后台加载的数据,则需要在HTML中放置能被FreeMarker所解析的特殊部分,
也就是FreeMarker的模板开发语句,其分为以下几类:

(1)${…}
FreeMarker将会输出真实的值来替换花括号内的表达式,这样的表达式被称为
interpolations 插值,可以参考第第一篇示例的内容。
示例:
欢迎您,${user},祝您有愉快的一天!
其中“${user}”后台使用Map集合装填的变量的Key,其值为“张三”。

(2)FTL tags标签(FreeMarker模板的语言标签)
FTL标签和HTML标签有一点相似,但是它们是FreeMarker的指令而且是不会直接输出出来的东西。这些标签的使用一般以符号#开头。
如下面要讲的if等FLT标签:
<#if user=="张三">欢迎张三先生</#if>
   
(3)Comments 注释
FreeMarker的注释和HTML的注释相似,但是它用<#--和-->来分隔的。任何介于这两个分隔符(包含分隔符本身)之间内容会被 FreeMarker忽略,就不会输出出来了。 
其他任何不是FTL标签,插值或注释的内容将被视为静态文本,这些东西就不会被
FreeMarker所解析,会被按照原样输出出来。 
示例:
<#if user=="张三">欢迎张三先生</#if> <#-- 显示用户信息 -->
上面的“显示用户信息”这句话不会显示出来。

(5)directives指令
就是所指的FTL标签。这些指令在HTML的标签(如<table>和</table>)和HTML元素(如table元素)
中的关系是相同的。

-- 以上基础资料摘自《[尚学堂]FreeMarker视频教程》

三、FTL标签指令

下面我们着重讲解一下FTL标签中的指令:
(1)if语句:
基本语法:
<#if 变量名 比较运算符 被比较值>要输出的信息</#if>
例子:
我们分别在后台分别给user赋值三个人的名字(“张三”、“李四”、“王五”),三个人分别是
“董事长”、“总经理”、“普通员工”:
package cn.com.test.freemarker;

import java.io.File;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

public class Test1 {
	public static void main(String[] args) throws Exception {
		//创建Freemarker配置实例
		Configuration cfg = new Configuration();
		
		cfg.setDirectoryForTemplateLoading(new File("templates")); 
		
		//创建数据模型
		Map root = new HashMap();
		root.put("user", "张三");
		/*root.put("user", "李四");
		root.put("user", "王五");*/
		
		//加载模板文件
		Template t1 = cfg.getTemplate("a.ftl");
		
		//显示生成的数据,将合并后的数据打印到控制台
		Writer out = new OutputStreamWriter(System.out); 
		t1.process(root, out);
		out.flush();
		out.close();
	}
}
注意,每次测试时,注释另外两个不需要显示的user,否则会造成value值被覆盖!

然后FTL标签指令语句写为:
欢迎您,${user},祝您有愉快的一天!

<#if user=="张三">董事长您辛苦了!</#if>
<#if user=="李四">总经理您注意休息!</#if>
<#if user=="王五">今天工作不努力,明天努力找工作!</#if>
分别运行三次(注释另外两个user),三次得到的结果分别为:



(2)if else语句
基本语法:
<#if 变量名 比较运算符 被比较值>
要输出的信息1
<#else>
要输出的信息2
</#if>

<#if 变量名 比较运算符 被比较值>
要输出的信息1
<#elseif 变量名 比较运算符 被比较值>
要输出的信息2
<#else>
要输出的信息3
</#if>

例子:
分别给number赋值“90”、“80”、“60”,当做考试的成绩,90分和以上是“优秀”,而80分和
90分以下是“良好”,80分以下是“一般”:
package cn.com.test.freemarker;

import java.io.File;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

public class Test1 {
	public static void main(String[] args) throws Exception {
		//创建Freemarker配置实例
		Configuration cfg = new Configuration();
		
		cfg.setDirectoryForTemplateLoading(new File("templates")); 
		
		//创建数据模型
		Map<String,Object> root = new HashMap<String,Object>();
		root.put("user", "张三");
		root.put("number", 90);
		/*root.put("number", 80);
		root.put("number", 60);*/
		
		//加载模板文件
		Template t1 = cfg.getTemplate("a.ftl");
		
		//显示生成的数据,将合并后的数据打印到控制台
		Writer out = new OutputStreamWriter(System.out); 
		t1.process(root, out);
		out.flush();
		out.close();
	}
}
注意,每次测试时,注释另外两个不需要显示的number,否则会造成value值被覆盖!

然后FTL标签指令语句写为:
<#if number gte 90> <#-- 不是使用>,大部分时候,freemarker会把>解释成标签结束! -->
    优秀!
<#elseif number gte 80>
    良好!
<#else>
    一般!	
</#if>
分别运行三次(注释另外两个number),三次得到的结果分别为:



(2)list指令
基本语法:
<#list list集合 as 遍历出来的子单位>
    ${子单位.属性名}
</#list>

例子:
后台装载一个包含user对象的集合:
package cn.com.test.freemarker;

import java.io.File;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

public class Test1 {
	public static void main(String[] args) throws Exception {
		//创建Freemarker配置实例
		Configuration cfg = new Configuration();
		
		cfg.setDirectoryForTemplateLoading(new File("templates")); 
		
		//创建数据模型
		Map<String,Object> root = new HashMap<String,Object>();
		List<User> userList = new ArrayList<User>();
		userList.add(new User("张三",1,27,new Address("中国","上海")));
		userList.add(new User("玛丽莲梦露",2,22,new Address("美国","百老汇")));
		userList.add(new User("后弦",1,26,new Address("中国","江苏")));
		root.put("userList", userList);


		//加载模板文件
		Template t1 = cfg.getTemplate("a.ftl");
		
		//显示生成的数据,将合并后的数据打印到控制台
		Writer out = new OutputStreamWriter(System.out); 
		t1.process(root, out);
		out.flush();
		out.close();
	}
}
其中User和Address类分别为:
public class User{
	private String name;
	private Integer sex;//1是男,2是女
	private Integer age;
	private Address address;//住址,一个包装类
	public User(String name,Integer sex,Integer age,Address address){
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.address = address;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getSex() {
		return sex;
	}
	public void setSex(Integer sex) {
		this.sex = sex;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
}
public class Address{
	private String country;
	private String city;
	public Address(String country,String city){
		super();
		this.country = country;
		this.city = city;
		
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
}
然后FTL标签指令语句写为:
<table border="1 #000 solid">
    <tr>
	<th>姓名</th><th>性别</th><th>年龄</th><th>所在地</th>
    </tr>
    <#if userList??> <#-- 判断list是否存在 -->
	<#list userList as u>
		<tr>
		    <td>${u.name}</td> 
		    <td>
		        <#if u.sex==1>
		            男
		        <#elseif u.sex==2>
		            女
		        <#else>
		            未知
		        </#if>
		    </td> 
		    <td>${u.age}岁</td> 
		    <td>国家:${u.address.country} 城市:${u.address.city}</td> 
	    	</tr>
	</#list>
    </#if>
</table>
运行的结果为:

得到了一串Html的table标签语句,将来可以用于输出到Web网页上展示:


(3)include指令
基本语法:
<#include "与模板同路径下的文件" />
例子:
我们在a.ftl模板文件的路径下放置名为“testInclude.txt”的txt文件:

其中的内容为:


在模板中放置一下语句:
<#include "testInclude.txt"/>
运行,在控制台得到结果:


(4)自定义指令(macro指令)
基本语法:
<#macro 自定义指令名>  
    指令显示的内容
</#macro>

<#macro 自定义指令名 参数1 参数2...参数N >
    使用${参数1}、${参数2}...${参数N}组成的显示信息
</#macro>

<#macro 自定义指令名>
    其他信息...<#nested>...其他信息
</#macro>
注意,“<#nested>”标签就是一会调用自定义标签时中间的参数信息。

调用自定义指令:
<@自定义指令名 />

<@自定义指令名 参数1="值1" 参数2="值2"...参数N="值N" />

<@自定义指令名>要显示的信息,在<#nested>的位置显示</@自定义指令名>

例子:
<#macro alert> <#-- 警告信息 -->
    警告!您无权查看此信息!
</#macro>
<@alert />

<#macro nameInfo a b c> <#-- 展示参数信息 -->
    ${a}==>${b}==>${c}
</#macro>
<@nameInfo a="张三" b="李四" c="王五"/>

<#macro overStriking> <#-- 字体加粗 -->
    <b> <#nested> </b>
</#macro>
<@overStriking>你好!</@overStriking>

运行结果:


以上就是Freemarker的数据结构和控制语句知识,下次会继续介绍Freemarker的其它基础知识。

转载请注明出处:http://blog.csdn.net/acmman/article/details/79120933

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光仔December

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值