freemarker教程之list循环

来源:互联网 发布:北京seo外包服务 编辑:程序博客网 时间:2024/05/19 20:00

一、流程list循环指令基础

<#list productList as p>

${p.id}--${p.name}

</#list>

测试类:

public static void test_list(){

Map<String,Object> map = new HashMap<String,Object>();

FreemarkerUtil fu = new FreemarkerUtil();

Session session = null;

Transaction trans = null;

try{

session = HibernateUtil.getCurrentSession();

trans = session.getTransaction();

trans.begin();

List<Product> proList = session.createQuery("from Product as p where p<5").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">

</c:forEach>

在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>

<br/>

</#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>

<br/>

</#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<String,Object> map = new HashMap<String,Object>();

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.<format> or ?string(format) built-in with this date.

需要日期格式指定${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>

相互调用形成一个回调圈。

0 0
原创粉丝点击