一、流程list循环指令基础
<#list productList as p>
${p.id}--${p.name}
#list>
测试类:
public static void test_list(){
Map
FreemarkerUtil fu = new FreemarkerUtil();
Session session = null;
Transaction trans = null;
try{
session = HibernateUtil.getCurrentSession();
trans = session.getTransaction();
trans.begin();
List
map.put("productList", proList);
fu.print2File("/04.ftl", map, "04.html");
trans.commit();
}catch(Exception e){
trans.rollback();
e.printStackTrace();
}
}
如果我将测试类中的map.put("productList", proList);改成map.put("productList", null);,会抛出异常吗?结果是不会,在循环productList的时候,如果productList是空NULL的话,是不会抛异常的。为何?大家想一想。
原因很简单,我们之前已经将classic_compatible 为true了,即使productList为NULL,也不会抛异常的。
二、循环指令高级部分
以上讲述的是list循环指令的基础语法,那下面我们来看下具体的实际开发遇到的问题解决:
1)下标指示
在循环的时候的i如何来表示。比如在jstl中会有
<c:forEach var="ci" items="${sessionScope.cart.cartItem}" varStatus="vs">
在freemarker中如何实现呢?
List指令还隐含了两个循环变量:
item_index:当前迭代项在所有迭代项中的位置,是数字值。
item_has_next:用于判断当前迭代项是否是所有迭代项中的最后一项。
注意:在使用上述两个循环变量时,一定要将item换成你自己定义的循环变量名,item其实就是前缀罢了。
例如,如果你使用<# list list as l>..#list>定义,那么就要使用l_index,l_has_next。
Eg:
<#list productList as p>
这是第${p_index+1}个对象============${p.id}--${p.name}
<#if p_has_next!="true">
这是最后一个对象
#if>
#list>
如果还有下一个,则p_has_next会为true,如果是最后一个了,则为空
2)调用集合方法,比如size()方法,来展示集合大小,这点jstl是无法实现的
<#list productList as p>
这是第${p_index+1}个对象============${p.id}--${p.name}
${p["id"]}--${p["name"]}
<#if p_has_next!="true">
这是最后一个对象,共有${productList?size}个对象
#if>
#list>
看好了,属性是用点,而方法的调用则使用问号。
3)调用集合方法,比如排序sort
<#list productList?sort_by("id")?reverse as p>
#list>
4)跳出循环
<#if p.id==2>
<#break>
#if>
三、include指令
<#include "01.ftl"/>
很简单,同时也将引进来的页面静态化
四、定义变量指令
<#assign
(一)定义基础类型
<#assign userName="张三"/>
${userName}
测试类也就是生成静态页面的类方法为:
FreemarkerUtil fu = new FreemarkerUtil();
fu.print2File("07.ftl", null, "07.html");
既然要定义变量,那么得知道变量类型吧,总不能和js一样都是弱类型的,全部都是var吧。
有:数字类型<#assign num=10/>
字符串<#assign userName="张三"/>
字符串拼接,两种方式,都可以
${"hello"+userName}
${"hello${userName}"}--插值
布尔类型<#assign b=true/>${b}
在布尔值这需要注意,在freemarker中,除了字符串和数字之外,其他的均不可被输出,如果强制输出,那只能异常,这让我们很尴尬。比如最常用的日期,我们稍后会讲述到。
那么应该如何输出呢?需要用问号(?string)来将日期也好布尔值也好转成字符串。比如
${b?string}
比如再举一个例子,输出一个表达式的结果,在freemarker中,一个表达式的结果肯定是true OR false的布尔值了,那么如何来输出呢?
${(s1.s2)???string}
如果我再提出一个需求来,如果表达式为true,那么请输出yes,如果为假,请输出no
${(s1.s2)???string("yes","no")}
时间类型,这个比布尔值要重要的多吧。
public static void test_07(){
Map
map.put("now", new Date());
FreemarkerUtil fu = new FreemarkerUtil();
fu.print2File("07.ftl", map, "07.html");
}
如果我在ftl中进行${now?string}
为何要报错呢?我们来看看报错内容:
freemarker.template.TemplateModelException: Can't convert the date to string, because it is not known which parts of the date variable are in use. Use ?date, ?time or ?datetime built-in, or ?string.
需要日期格式指定${now?string("yyyy-MM-dd HH:mm:ss")}
刚才讲的是将日期转换为字符串来达到输出的目的,有的时候我们需要将字符串转成日期
${"2012-12-09"?date("yyyy-MM-dd")}
那我如果写成:
${"2012-12-09 12:12:12"?date("yyyy-MM-dd HH:mm:ss")}
输出的结果是什么?结果是2012-12-09,那我的时间哪去了呢?记住,date方法只能转换成date,要想有具体时间需要datetime
所以我写成了:<#assign bir="2012-12-09 15:12:12"?datetime("yyyy-MM-dd HH:mm:ss")/>
但是谁能告诉我为何我的时间还是溜走了?后面的具体的时间哪去了呢?我找了半天我发现freemarker.propertes里设定了时间格式,那里设定的格式的优先级要高于这的。至于为何要这么做?不知道人家肉食者咋想的,如果这么实现是无法实现一种需求的,就是大部分的时间格式是一种格式,我想统一在配置文件中进行配置就ok了,只有单个 的没几个地方的时间格式不同,如果这么实现的话,单独配置的优先级低,所以不起作用。
这里需要注意一点,变量是可以覆盖的,只要是名字相同,不管第一次你是数字还是字符串,完全按照后面的来(类型和值)
(二)定义数组序列
如何定义一个数组?
<#assign ar=[1,2,3,4,5,6,7,8,9,0]/>
<#list ar as a>
${a}
#list>
或者
<#assign ar=1..10/> 默认step为1
(三)定义map
如何定义一个map?
<#assign map={"1":"张三","2":"李四"}/>
${map["1"]}--${map["2"]}
如何循环map呢?
<#assign mapKey=map?keys/>
<#list mapKey as k>
${map[k]}
#list>
(四)自定义指令
就是一个自定义函数,用来多个地方共同调用。
<#macro hello>
hello world
#macro>
<@hello/><@hello/><@hello/>
刚才我们说了,自定义指令就是自定义函数,既然是函数,肯定可以传参吧。
<#macro hello num ok>
<#list 1..num as n>
hello ${ok},这是第${n}个
#list>
#macro>
<@hello num=3 ok="傻逼"/>
<@hello num1=3 ok1="傻逼"/> error
说明调用的时候的参数指定要和定义函数的参数名称完全一致,否则会报错
再试想,如果我在调用的时候省略参数呢,同样也会报错,怎么样才能不报错呢?
可以给定义函数指定初始值。
<#macro hello1 num=3 ok="SB">
<#list 1..num as n>
hello ${ok},这是第${n}个
#list>
#macro>
<@hello1/>
附注:
<#macro test>
<#nested/>
<#nested/>
#macro>
<@test>
你好
@test>
这个用法我还不知道有什么用,所以暂且不论
现在补充一点,就是为什么要这么回圈的调用?有的时候,我们共同使用这个指令方法的地方还有一些地方是不同的,并不是完全相同的,那么相同的地方我们放到指令函数中去解决,不同的地方各自在调用的时候解决。
另外,基于以上写法,我们还可以对调用的时候,指定参数,如:
<#macro test1>
<#nested 11 12/>
<#nested 23 33/>
#macro>
<@test1;x,y>
你好${x}${y}
@test1>
相互调用形成一个回调圈。