上一篇我们学习了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<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的其它基础知识。