FreeMarker使用总结
1.FreeMarker概述
1)FreeMarker是一个模板引擎: 一个基于模板生成文本输出的通用工具,使用纯Java编写。
模板+数据模型=输出
2)FreeMarker被设计用来生成HTML Web页面,适合于作为Web应用程序的一个组件,特别适合于MVC应用程序的视图组件。
======================================================================================================================
2.数据模型 - Data Model
1)典型的数据模型是树性结构,具有任意复杂和深度的层次
(root)
|
+- test = "It is a test"
|
+- whatnot
| |
| +- because = "don't know"
|
+- animals
|
+- (1st)
| |
| +- name = "elephant"
| |
| +- price = 5000
|
+- (2st)
|
+- name = "cat"
|
+- price = 100
2)数据模型中变量的种类
i) Scalars - 存储单一的值,类型可以为字符串/数值/日期时间/布尔型。
Example. test、because、name、price都是Scalar
ii) Hashes - 用于存储其余的变量(subvariables,子变量),类似于目录,包含保存下级变量的唯一查询名字。
Example. (root)、whatnot都是Hashes,访问because的语法:${whatnot.because}
iii) Sequences - 子变量顺序存放,子变量通过序号(从0开始)访问。
Example. animals就是Sequences,访问子变量name的语法: ${animals[0].name}
======================================================================================================================
3. 模板 - Templates
最简单的模板文件可以是一个简单的HTML文件(或者任意的文本文件),模板文件通常包含以下部分:
1)Comments - 注释,包含在<#--和-->之间
2)${...} - Inerpolations(插值),FreeMarker会在输出时使用实际值进行替代。
Example1. test.ftl
<html>
<head>
<title>${test}</title>
</head>
<body>
<h1>The most popular animal</h1>
<p>
<#-- the first animal elephant is more popular-->
${animals[0].name} - price:${animals[0].price}
</p>
</body>
</html>
插值的类型:通用Interpolation - ${expr}
数字Interpolation - #{expr}或#{expr;format}
3) FTL tags - FreeMarker Template Language tags,FTL标记,也称为指令
i) FTL标记的语法:
开始标记: <#directive_name parameters>
结束标记: </#directive_name>
空标记: <#directive_name parameters/>
ii) 指令的类型:预定义指令和用户定义指令(使用@替换#)
======================================================================================================================
4.Value值、Types类型、Expression表达式、操作符
1)值的类型有:
Scalars:
String
Number
Boolean
Date
Containers:
Hash
Sequence
Collection
Subroutines:
Methods and functions
User-defined directives
Miscellaneous/seldom used:
Node
2)Expression:
(1) 字符串:使用单引号或双引号限定,包含特殊字符需转义。
有一类特殊的字符串称为raw字符串,被认为是纯文本,该类字符串在引号前面加r。Example. ${r"${foo}"}
连接操作 - Example:${"Hello " + user + "!"}
取子串- Example:<#assign var1="dangdang2">
<a href="#">${var1[0..3]}</a>
(2)数字:不需要引号,不支持科学计数法,不能省略小数点前面的0。
算术运算符有:+、-、×、/、%
使用内建的int获得整数部分
Example:${1.1?int} - 返回1
${1.999?int} - 返回1
${-1.1?int} - 返回-1
${-1.999?int} - 返回-1
(3)布尔值:true 和false
(4)序列:由逗号分隔的子变量列表,由方括号限定。
Example. ["spring","summer","autumn","winter"]
[2+2,[1,2,3,4],"whatnot"] - 列表项目是表达式
2..5 - 等同于[2,3,4,5],可以使用数字范围定义数字序列,注意数字范围没有方括号
5..2 - 可以定义反递增的数字范围
序列的连接操作:
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
</#list>
(5)散列:由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔。
Example. {"name":"dog","price":120}
散列的连接操作:和 字符串一样,使用+,如果具有相同的key,右边的值替代左边的值
Example:<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
-------------------------------------------------------------------------------
3)获取变量
(1)顶层变量:${variable}
(2) 从散列中获取数据:${whatnot.because}或者${whatnot["because"]}
(3) 从序列获取数据:${animals[0].name}
(4) 获取序列片段:使用[startIndex..endIndex]语法
(5) 特殊变量:FreeMarker内定义的变量,使用.variable_name语法访问。
======================================================================================================================
5.Interpolation(插值)的使用
通用Interpolation
1)插入字符串值:直接输出表达式结果
2)插入数字值:根据缺省值(由#setting指令设置)将表达式结果转换为文本输出。
Example:
<#setting number_format="currency"/>
<#assign answer=42>
${answer} - 输出$42.00
${answer?string} - 输出$42.00
${answer?string.number} - 输出42
${answer?string.currency} - 输出$42.00
${answer?string.percent} - 输出4,200%
3)插入日期值:
Example:${lastUpdated?string("yyyy-MM-dd HH:mm:ss")
4)插入布尔值:
Example:<#assign foo=true>
${foo?string("yes","no")}
-------------------------------------------------------------------------
数字Interpolation - #{expr;format}
format的格式:mX 小数部分最小X位,MX 小数部分最大X位
Example:<#assign x=2.582/>
<#assign y=4/>
#{x; M2} <#-- 2.58 -->
#{y; M2} <#-- 4 -->
#{x; m1} <#-- 2.6 -->
#{y; m1} <#-- 4.0 -->
#{x; m1M2} <#-- 2.58 -->
#{y; m1M2} <#-- 4.0 -->
======================================================================================================================
6. 常用指令
1)if,else,elseif
语法:<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
2)switch, case, default, break
语法:<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
3)list
语法: <#list sequence as item>
...
</#list>
List指令中的隐含变量:
item_index:当前迭代项的位置,从0开始。
item_has_next:用于判断当前迭代项是否有下一项。
-------------------------------------------------------------------------------------
Example1:
<#-- 在循环中使用隐含变量 -->
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
Example2:
<#-- 固定次数的循环-->
<#assign x=3>
<#list 1..x as i>
${i}
</#list>
Example3:
<#-- 散列的循环 -->
<#assign items={"k1":"one","k2":"two"}>
<select>
<#list items?keys as itemKey>
<option value="${itemKey}">${items[itemKey]}</option>
</#list>
</select>
--------------------------------------------------------------------------------------
4)include:用于包含其他的模板文件
语法:<#include path> or <#include path options>
path: The path of the file to include; an expression that evaluates to a string. (With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".)
options: One or more of these: encoding=encoding, parse=parse
encoding: Expression evaluates to string
parse: Expression evaluates to boolean (also accepts a few string values for backward compatibility)
example1:
<#-- struts2中主题xhtml下的select.ftl文件 -->
<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/select.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />
5) assign:用于定义变量或者替换存在的变量
语法:<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
name: name of the variable. It is not expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}").
value: the value to store. Expression.
namespacehash: a hash that was created for a namespace (by import). Expression.
6)import: 导入一个库到模板中,FreeMarker为导入库创建新的命名空间
语法:<#import path as hash>
path: The path of a template. This is an expression that evaluates to a string.
(With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".)
hash: The unquoted name of hash variable by which you can access the namespace. Not an expression.
Example1:
<#--使用命名空间-->
<#import "/template/simple/test.ftl" as my>
<#assign var1="dangdang2" in my>
<a href="${my.url}">${my.var1}</a>
========================================================================
7.内置函数 - 参阅FreeMarker Manual
8.杂项
1)宏 - 宏是和某个变量关联的模板片段,以便在模板中通过用户定义指令使用该变量。
Example1:<#macro greet>
<font size="2">Hello world!</font>
</#macro>
<#--使用宏-->
<@greet></@greet>
-----------------------------------------------------------------------------------------
(1) 嵌套内容 - 用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板片段
Example2:<#macro border>
<table border=1>
<tr><td><#nested></td></tr>
</table>
</#macro>
<!--使用宏-->
<@border>The bordered text</@border>
-------------------------------------------------------------------------
(2)在宏定义中使用循环变量:
用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的
参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定
循环变量的名字
Example3:
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
输出结果:
1. 0.5
2. 1
3. 1.5
4. 2 Last!
-------------------------------------------------------------------------
2)在模板中定义变量
(1)plain变量:使用assign指令创建和替换,可以在模板任何地方访问,包括使用include指令插入的模板。
(2)局部变量:使用local指定创建和替换,只在宏定义体中有效。
(3)循环变量:只能存在于指令的嵌套内容中,由指令(如list)自动创建。
3)名字空间
通常情况下,只使用一个名字空间,称为主名字空间。
为了创建可重用的宏或其他变量的集合(通常称为库),必须使用多名字空间,以防止命名冲突。
使用名字空间的步骤:
Step1.创建库
Example:《#-- 保存在模板文件inc.ftl-->
<#macro copyright date>
<p>Copyright (C) ${date} Bill Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "billsmith@xxx.com">
Step2.使用import指令将库导入到模板中
<#import "/lib/inc.ftl" as my>
<#assign mail="fred@xxx.com> <#--定义同名变量,并没有冲突-->
<@my.copyright date="2010-2011"/>
${my.mail}
${mail}
======================================================================================================================
9.FreeMarker综合案例 - 分页标签模板文件
<#-- 分页标签模板文件pager.ftl-->
<div class="paginating">
<div class="pageform">
<form name="formPager" action="${parameters.url}" method="post">
<a href="javascript:document.formPager.submit();">确定</a>
<span>页</span>
<input name="pageno" type="text" value="1"/>
<span>共${parameters.pageCount}页 转到</span>
</form>
</div>
<div class="pagepanel">
<#-- 下一页 -->
<#if parameters.pageno==parameters.pageCount>
<a class="pagebtn disabled" href="#"><span>下一页</span></a>
<#else>
<a href="${parameters.url}?pageno=${parameters.pageno+1}" class="pagebtn"><span>下一页</span></a>
</#if>
<#-- 页码 -->
<#list parameters.pageCount..1 as x>
<#assign url=parameters.url+'?pageno='+x/>
<#if parameters.pageno==x>
<a href="#" class="pagenum current"><span>${x}</span></a>
<#else>
<a href="${url}" class="pagenum"><span>${x}</span></a>
</#if>
</#list>
<#-- 上一页 -->
<#if parameters.pageno==1>
<a class="pagebtn disabled" href="#"><span>上一页</span></a>
<#else>
<a href="${parameters.url}?pageno=${parameters.pageno-1}" class="pagebtn"><span>上一页</span></a>
</#if>
</div>
</div>
======================================================================================================================
(END)
1.FreeMarker概述
1)FreeMarker是一个模板引擎: 一个基于模板生成文本输出的通用工具,使用纯Java编写。
模板+数据模型=输出
2)FreeMarker被设计用来生成HTML Web页面,适合于作为Web应用程序的一个组件,特别适合于MVC应用程序的视图组件。
======================================================================================================================
2.数据模型 - Data Model
1)典型的数据模型是树性结构,具有任意复杂和深度的层次
(root)
|
+- test = "It is a test"
|
+- whatnot
| |
| +- because = "don't know"
|
+- animals
|
+- (1st)
| |
| +- name = "elephant"
| |
| +- price = 5000
|
+- (2st)
|
+- name = "cat"
|
+- price = 100
2)数据模型中变量的种类
i) Scalars - 存储单一的值,类型可以为字符串/数值/日期时间/布尔型。
Example. test、because、name、price都是Scalar
ii) Hashes - 用于存储其余的变量(subvariables,子变量),类似于目录,包含保存下级变量的唯一查询名字。
Example. (root)、whatnot都是Hashes,访问because的语法:${whatnot.because}
iii) Sequences - 子变量顺序存放,子变量通过序号(从0开始)访问。
Example. animals就是Sequences,访问子变量name的语法: ${animals[0].name}
======================================================================================================================
3. 模板 - Templates
最简单的模板文件可以是一个简单的HTML文件(或者任意的文本文件),模板文件通常包含以下部分:
1)Comments - 注释,包含在<#--和-->之间
2)${...} - Inerpolations(插值),FreeMarker会在输出时使用实际值进行替代。
Example1. test.ftl
<html>
<head>
<title>${test}</title>
</head>
<body>
<h1>The most popular animal</h1>
<p>
<#-- the first animal elephant is more popular-->
${animals[0].name} - price:${animals[0].price}
</p>
</body>
</html>
插值的类型:通用Interpolation - ${expr}
数字Interpolation - #{expr}或#{expr;format}
3) FTL tags - FreeMarker Template Language tags,FTL标记,也称为指令
i) FTL标记的语法:
开始标记: <#directive_name parameters>
结束标记: </#directive_name>
空标记: <#directive_name parameters/>
ii) 指令的类型:预定义指令和用户定义指令(使用@替换#)
======================================================================================================================
4.Value值、Types类型、Expression表达式、操作符
1)值的类型有:
Scalars:
String
Number
Boolean
Date
Containers:
Hash
Sequence
Collection
Subroutines:
Methods and functions
User-defined directives
Miscellaneous/seldom used:
Node
2)Expression:
(1) 字符串:使用单引号或双引号限定,包含特殊字符需转义。
有一类特殊的字符串称为raw字符串,被认为是纯文本,该类字符串在引号前面加r。Example. ${r"${foo}"}
连接操作 - Example:${"Hello " + user + "!"}
取子串- Example:<#assign var1="dangdang2">
<a href="#">${var1[0..3]}</a>
(2)数字:不需要引号,不支持科学计数法,不能省略小数点前面的0。
算术运算符有:+、-、×、/、%
使用内建的int获得整数部分
Example:${1.1?int} - 返回1
${1.999?int} - 返回1
${-1.1?int} - 返回-1
${-1.999?int} - 返回-1
(3)布尔值:true 和false
(4)序列:由逗号分隔的子变量列表,由方括号限定。
Example. ["spring","summer","autumn","winter"]
[2+2,[1,2,3,4],"whatnot"] - 列表项目是表达式
2..5 - 等同于[2,3,4,5],可以使用数字范围定义数字序列,注意数字范围没有方括号
5..2 - 可以定义反递增的数字范围
序列的连接操作:
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
</#list>
(5)散列:由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔。
Example. {"name":"dog","price":120}
散列的连接操作:和 字符串一样,使用+,如果具有相同的key,右边的值替代左边的值
Example:<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
-------------------------------------------------------------------------------
3)获取变量
(1)顶层变量:${variable}
(2) 从散列中获取数据:${whatnot.because}或者${whatnot["because"]}
(3) 从序列获取数据:${animals[0].name}
(4) 获取序列片段:使用[startIndex..endIndex]语法
(5) 特殊变量:FreeMarker内定义的变量,使用.variable_name语法访问。
======================================================================================================================
5.Interpolation(插值)的使用
通用Interpolation
1)插入字符串值:直接输出表达式结果
2)插入数字值:根据缺省值(由#setting指令设置)将表达式结果转换为文本输出。
Example:
<#setting number_format="currency"/>
<#assign answer=42>
${answer} - 输出$42.00
${answer?string} - 输出$42.00
${answer?string.number} - 输出42
${answer?string.currency} - 输出$42.00
${answer?string.percent} - 输出4,200%
3)插入日期值:
Example:${lastUpdated?string("yyyy-MM-dd HH:mm:ss")
4)插入布尔值:
Example:<#assign foo=true>
${foo?string("yes","no")}
-------------------------------------------------------------------------
数字Interpolation - #{expr;format}
format的格式:mX 小数部分最小X位,MX 小数部分最大X位
Example:<#assign x=2.582/>
<#assign y=4/>
#{x; M2} <#-- 2.58 -->
#{y; M2} <#-- 4 -->
#{x; m1} <#-- 2.6 -->
#{y; m1} <#-- 4.0 -->
#{x; m1M2} <#-- 2.58 -->
#{y; m1M2} <#-- 4.0 -->
======================================================================================================================
6. 常用指令
1)if,else,elseif
语法:<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
2)switch, case, default, break
语法:<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
3)list
语法: <#list sequence as item>
...
</#list>
List指令中的隐含变量:
item_index:当前迭代项的位置,从0开始。
item_has_next:用于判断当前迭代项是否有下一项。
-------------------------------------------------------------------------------------
Example1:
<#-- 在循环中使用隐含变量 -->
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
Example2:
<#-- 固定次数的循环-->
<#assign x=3>
<#list 1..x as i>
${i}
</#list>
Example3:
<#-- 散列的循环 -->
<#assign items={"k1":"one","k2":"two"}>
<select>
<#list items?keys as itemKey>
<option value="${itemKey}">${items[itemKey]}</option>
</#list>
</select>
--------------------------------------------------------------------------------------
4)include:用于包含其他的模板文件
语法:<#include path> or <#include path options>
path: The path of the file to include; an expression that evaluates to a string. (With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".)
options: One or more of these: encoding=encoding, parse=parse
encoding: Expression evaluates to string
parse: Expression evaluates to boolean (also accepts a few string values for backward compatibility)
example1:
<#-- struts2中主题xhtml下的select.ftl文件 -->
<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/select.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />
5) assign:用于定义变量或者替换存在的变量
语法:<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
name: name of the variable. It is not expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}").
value: the value to store. Expression.
namespacehash: a hash that was created for a namespace (by import). Expression.
6)import: 导入一个库到模板中,FreeMarker为导入库创建新的命名空间
语法:<#import path as hash>
path: The path of a template. This is an expression that evaluates to a string.
(With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".)
hash: The unquoted name of hash variable by which you can access the namespace. Not an expression.
Example1:
<#--使用命名空间-->
<#import "/template/simple/test.ftl" as my>
<#assign var1="dangdang2" in my>
<a href="${my.url}">${my.var1}</a>
========================================================================
7.内置函数 - 参阅FreeMarker Manual
8.杂项
1)宏 - 宏是和某个变量关联的模板片段,以便在模板中通过用户定义指令使用该变量。
Example1:<#macro greet>
<font size="2">Hello world!</font>
</#macro>
<#--使用宏-->
<@greet></@greet>
-----------------------------------------------------------------------------------------
(1) 嵌套内容 - 用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板片段
Example2:<#macro border>
<table border=1>
<tr><td><#nested></td></tr>
</table>
</#macro>
<!--使用宏-->
<@border>The bordered text</@border>
-------------------------------------------------------------------------
(2)在宏定义中使用循环变量:
用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的
参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定
循环变量的名字
Example3:
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
输出结果:
1. 0.5
2. 1
3. 1.5
4. 2 Last!
-------------------------------------------------------------------------
2)在模板中定义变量
(1)plain变量:使用assign指令创建和替换,可以在模板任何地方访问,包括使用include指令插入的模板。
(2)局部变量:使用local指定创建和替换,只在宏定义体中有效。
(3)循环变量:只能存在于指令的嵌套内容中,由指令(如list)自动创建。
3)名字空间
通常情况下,只使用一个名字空间,称为主名字空间。
为了创建可重用的宏或其他变量的集合(通常称为库),必须使用多名字空间,以防止命名冲突。
使用名字空间的步骤:
Step1.创建库
Example:《#-- 保存在模板文件inc.ftl-->
<#macro copyright date>
<p>Copyright (C) ${date} Bill Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "billsmith@xxx.com">
Step2.使用import指令将库导入到模板中
<#import "/lib/inc.ftl" as my>
<#assign mail="fred@xxx.com> <#--定义同名变量,并没有冲突-->
<@my.copyright date="2010-2011"/>
${my.mail}
${mail}
======================================================================================================================
9.FreeMarker综合案例 - 分页标签模板文件
<#-- 分页标签模板文件pager.ftl-->
<div class="paginating">
<div class="pageform">
<form name="formPager" action="${parameters.url}" method="post">
<a href="javascript:document.formPager.submit();">确定</a>
<span>页</span>
<input name="pageno" type="text" value="1"/>
<span>共${parameters.pageCount}页 转到</span>
</form>
</div>
<div class="pagepanel">
<#-- 下一页 -->
<#if parameters.pageno==parameters.pageCount>
<a class="pagebtn disabled" href="#"><span>下一页</span></a>
<#else>
<a href="${parameters.url}?pageno=${parameters.pageno+1}" class="pagebtn"><span>下一页</span></a>
</#if>
<#-- 页码 -->
<#list parameters.pageCount..1 as x>
<#assign url=parameters.url+'?pageno='+x/>
<#if parameters.pageno==x>
<a href="#" class="pagenum current"><span>${x}</span></a>
<#else>
<a href="${url}" class="pagenum"><span>${x}</span></a>
</#if>
</#list>
<#-- 上一页 -->
<#if parameters.pageno==1>
<a class="pagebtn disabled" href="#"><span>上一页</span></a>
<#else>
<a href="${parameters.url}?pageno=${parameters.pageno-1}" class="pagebtn"><span>上一页</span></a>
</#if>
</div>
</div>
======================================================================================================================
(END)