Expsoft CMS内容管理系统标签使用手册2009
3.2.2 取得指定栏目下的内容列表ExpGetContentInfoList
3.2.3取得栏目最新信息的详细内容ExpCategoryNewInfoContent
3.2.3取得指定信息的详细内容ExpGetInfoContent
3.2.4取得指定栏目的访问地址ExpGetCategoryLinkURL
3.2.5取得指定信息的访问地址ExpContentLink
1、简要介绍
Expsoft CMS内容管理系统采用Nvelocity语言构造网站模板。Nvelocity是一个基于.NET的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由.NET代码定义的对象。当Nvelocity 应用于web开发时,界面设计人员可以和.NET程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由.NET程序开发人员关注业务逻辑编码。Nvelocity将.NET代码从web页面中分离出来,这样为web站点的长期维护提供了便利。
Expsoft CMS内容管理系统使用Nvelocity为web开发架构提供模板服务(template service)。我们的系统就提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。
2、Velocity模板语言(VTL):说明
VTL意味着提供最简单、最容易并且最整洁的方式合并页面动态内容。VTL使用references来在web site内嵌套动态内容,一个变量就是一种类型的reference。变量是某种类型的refreence,它可以指向java代码中的定义,或者从当前页面内定义的VTL statement得到值。下面是一个VTL statement的例子,它可以被嵌套到HTML代码中:
#set( $a = "Velocity" ),和所有的VTL statement一样,这个statement以#字符开始并且包含一个directive:set。当一个在线用户请求你的页面时,Velocity 模板引擎将查询整个页面以便发现所有#字符,然后确定哪些是VTL statement,哪些不需要VTL作任何事情。
#字符后紧跟一个directive:set时,这个set directive使用一个表达式(使用括号封闭)――一个方程式分配一个值给变量。变量被列在左边,而它的值被列在右边,最后他们之间使用=号分割。在上面的例子中,变量是$a,而它的值是Velocity。和其他的references一样以$字符开始,而值总是以双引号封闭。Velocity中仅有String可以被赋值给变量。
使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么。在上面的例子中,#set是分配一个值给变量。变量$a 在模板中输出 "Velocity"。
2.1、 Hello Velocity World!
一旦某个变量被分配了一个值,那么你就可以在HTML文件的任何地方引用它。在下面的例子中,一个值被分配给$foo变量,并在其后被引用。
<html>
<body>
#set( $foo = "Velocity" )
Hello $foo World!
</body>
<html>
上面的实现结果是在页面上打印“Hello Velocity World!”
为了使包含VTL directives的statement更具有可读性,我们鼓励你在新行开始每个VTL statement,尽管你不是必须这么作。Set的用法将在后面详细描述。
2.2、注释
注释是描述文本是不会出现在模板引擎生成页面中的。注释一个主要用处是提醒自己和解释出现在VTL中的声明,或是其他用途。下面是一个在VLT中的注释例子。
## This is a single line comment.
单行注释以##开始,结束在这行的结尾。如果你要写几行注释,这没有必要写几个单行注释。
多行注释,以#*开始*#结束,可以解决这个问题。
This is text that is outside the multi-line comment.
Online visitors can see it.
#*
Thus begins a multi-line comment. Online visitors won't
see this text because the Velocity Templating Engine will
ignore it.
*#
2.3、References
在VTL中有三种类型的references:变量(variables)、属性(properties)、方法(methods)。作为一个使用VTL的页面设计者,你和你的工程师必须就references的名称达成共识,以便你可以在你的template中使用它们。
所有的 reference被作为一个String对象处理。如果有一个对象$foo是一个Integer对象,那么Velocity将调用它的toString()方法将这个对象转型为String类型。
2.3.1变量
非正式变量是由“$”开头,接着是VTL标识符。VLT标识符必须以字母(a..z,A..Z)开头。剩下的部分限于以下几种:
字母(a..z,A..Z)
数字(0..9)
连字符(“-”)
下划线(“_”)
这里是几个在VTL中有效的变量reference。
$foo
$mudSlinger
$mud-slinger
$mud_slinger
$mudSlinger1
当VLT定义一个变量,例如$foo,变量能或者通过模板中的set 方法,或者通过Java 代码获得值。
例如,Java 变量 $foo 的值是 bar ,在这个模板被请求时,在网页上 bar 会替代所有 $foo 。选择地,假如包括了下面的声明:
#set( $foo = "bar" )
按照这样的设置,输出就会跟之前的一样。
2.3.2属性
第二种有趣的VTL reference就是属性,而且属性有一种与众不同的格式。非正式变量是由“$”开头,接着是VTL标识符,再接着就是字符(“.”)和其他的VLT标识符。这里是一些在VLT中有效属性的定义:
$customer.Address
2.3.3方法
一个方法就是系统提供的数据访问的访求,并且它有完成某些有用工作的能力,例如一个执行计算和判断条件是否成立、满足等。方法是一个由$开始并跟随VTL标识符组成的References,一般还包括一个VTL方法体。一个VTL方法体包括一个VLT标识接着一个左括号(“(”),接着是参数列表,再接着是右括号(“)”)。这里是一些在VTL中有效的方法定义:
${ExpValue.ExpGetContentInfoList(${SiteID},"018","",1,0,"","",10)},其中ExpValue就是系统提供的对象,ExpGetContentInfoList就是方法,表示取得栏目下面的内容信息列表。
2.4、正式reference标记
非正式references用于上述的例子中。但是同样有正式的references,如下面所示:
${mudSlinger}
${customer.Address}
${purchase.getTotal()}
在几乎所有场合你都可以使用非正式references,但是在某些场合,只能使用正式reference 才能正确处理。
设想你创建一个句子:$vice 作为句子的名词 。目标是为了使某些人选择不同的词,产生下面两种结果之一:"Jack is a pyromaniac." 或者 "Jack is a kleptomaniac."。使用非正式定义不太适合用于这种情况。看一下下面的例子:
Jack is a $vicemaniac.
本来变量是$vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用正是格式书写
Jack is a ${vice}maniac.
现在Nvelocity就知道reference 是$vice,而不是$vicemaniac。正式定义经常用于模板中refernces与文本连接在一起的情况。
2.5、转义
某些情况使用Nvelocity可能会觉得很烦恼。逃避特殊符是处理出现在你的模板中VTL特殊符有效方法,就是使用反斜杠(“\”)。
#set( $email = "foo" )
假如Velocity在你的模板中遇到 $email ,它会搜索上下文,得到相应的值。这里的输出是 foo ,因为 $email 被定义了。假如 $email 没有被定义,输出会是 $email 。
设想 $email 被定义了(例如,它的值是 foo ),而且你想输出 $email 。最简单的是使用转义符,例:\$email,Nvelocity就不会解析$email,而直接输出。
2.6、赋值
Reference允许设计者使用动态的内容,而directive使得你可以应用java代码来控制你的显示逻辑,从而达到你所期望的显示效果。
#set
#set标志是用于对一个reference赋值。值会赋给一个变量或者一个属性,而且赋值会在括号里出现:
#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )
左边(LHS) 一定是一个变量或者一个属性。右边(RHS)可以是下面中的一个类型:
变量
字符串
属性
方法
数字
数组
这些例子显示上述的每一种类型:
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = "monica" ) ## string literal
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
#set( $monkey.Number = 123 ) ##number literal
#set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList
注意:最后一个例子的取值方法为:$monkey.Say.get(0)。
RHS也可以是一个简单的算术表达式:
#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )
如果你的RHS是一个null,VTL的处理将比较特殊:它将指向一个已经存在的reference,这对初学者来讲可能是比较费解的。例如:
#set( $result = $query.criteria("name") )
The result of the first query is $result
#set( $result = $query.criteria("address") )
The result of the second query is $result
如果$query.criteria(“name”)返回一个“bill”,而$query.criteria(“address”)返回的是null,则显示的结果如下:
The result of the first query is bill
The result of the second query is bill
这容易使新手糊涂:创建一个#foreach循环,企图想通过一个属性或者一个方法 #set一个reference,然后马上就用 #if 测试。例如:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
在上面的例子中,程序将不能智能的根据$result的值决定查询是否成功。在$result被#set后(added to the context),它不能被设置回null(removed from the context)。打印的结果将显示两次查询结果都成功了,但是实际上有一个查询是失败的。
为了解决以上问题我们可以通过预先定义的方式:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
不像其他Velocity指示符号,#set 没有一个#end 结束。
2.7、条件语句If / ElseIf / Else
当一个web页面被生成时使用Velocity的#if directrive,如果条件成立的话可以在页面内嵌入文字。例如:
#if( $foo )
<strong>Velocity!</strong>
#end
上例中的条件语句将在以下两种条件下成立:(i)$foo是一个boolean型的变量,且它的值为true;(ii)$foo变量的值不为null。这里需要注意一点:Velocity context仅仅能够包含对象,所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值,Velocity也会利用内省机制将它转换为一个Boolean的相同值。
如果条件成立,那么#if和#end之间的内容将被显示。在这个例子中,如果 $foo的值为true,输出为“Velocity!”。相反地,如果 $foo 是一个 null值,或者是一个 false 值,表达式值为 false,没有输出。
#elseif和#else元素可以同#if一同使用。注意:Velocity 模板引擎遇到一个为true值的表达式就会停止。在下面的例子,假设 $foo=15,$bar=6:
#if( $foo < 10 )
<strong>Go North</strong>
#elseif( $foo == 10 )
<strong>Go East</strong>
#elseif( $bar == 6 )
<strong>Go South</strong>
#else
<strong>Go West</strong>
#end
在这个例子中,$foo比10大,所以在开始的两个比较中都失败。接着 $bar跟6比较是真的所以输出为 GO South。
注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false,但是与java不同它使用“==”来比较两个值,而且velocity要求等号两边的值类型相同。
2.8、关系、逻辑运算符
Velocity中使用等号操作符判断两个变量的关系。这里有个简单例子关于等于号的使用:
#set ($foo = "deoxyribonucleic acid")
#set ($bar = "ribonucleic acid")
#if ($foo == $bar)
In this case it's clear they aren't equivalent. So...
#else
They are not equivalent and this will be the output.
#end
Velocity有AND、OR和NOT逻辑运算符。想得到更多信息,请看VTL Reference Guide。下面的例子是说明AND、OR和NOT逻辑运算符的用法:
## logical AND
#if( $foo && $bar )
<strong> This AND that</strong>
#end
只有当$foo 和 $bar 都为true,#if 才会得到true值。如果$foo=false ,表达式的值为 false,$bar 就不会求值。如果 $foo的值为 true ,Velocity模板引擎会检查 $bar的值,如果$bar=true,整个表达式的值为true,输出为“This AND that”。如果$bar=false,整个表达式的值为false,没有输出。
逻辑OR 的工作方式一样,除了只要有一个值为true ,整个表达式的值就为true。考虑一下下面的例子。
## logical OR
#if( $foo || $bar )
<strong>This OR That</strong>
#end
如果$foo=true,Velocity模板引擎就没有必要查找 $bar,无论 $bar 是true 还是 false ,表达式的值为 true ,输出为“This OR That”。如果$foo=flase,$bar的值就一定要检查,在这个例子中,如果 $bar 同样是false,表达式的值为 false ,没有输出。从另外一个角度看,如果$bar 的值为true ,整个表达式的值为 true ,输出为 “This OR That”。
关于逻辑NOT ,只有一个疑问:
##logical NOT
#if( !$foo )
<strong>NOT that</strong>
#end
如果 $foo=true, !$foo 的值为 false,没有输出。如果$foo=false,!$foo的值为true,输出为“NOT that”。注意不要跟 quiet reference $!foo 混为一谈,那是完全不一样的。
2.9、 循环
#foreach 用于循环。例子:
<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
</ul>
每次循环$allProducts中的一个值都会赋给$product变量。
$allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象,并且可以通过变量被引用。例如:如果$product是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
现在我们假设$allProducts是一个Hashtable,如果你希望得到它的key应该像下面这样:
<ul>
#foreach( $key in $allProducts.keySet() )
<li>Key: $key -> Value: $allProducts.get($key)</li>
#end
</ul>
Velocity还特别提供了得到循环次数的方法,以便你可以像下面这样作:
<table>
#foreach( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end
</table>
$velocityCount变量的名字是Velocity默认的名字,计数从“1”开始。
2.10、 子模板parse
#parse script element允许模板设计者一个包含VTL的本地文件。Velocity将解析其中的VTL并render模板。
#parse( "me.vm" )
就像#include,#parse接受一个变量而不是一个模板。任何由#parse指向的模板都必须包含在TEMPLATE_ROOT目录下。与#include不同的是,#parse只能指定单个对象。
你可以通过修改velocity.properties文件的parse_direcive.maxdepth的值来控制一个template可以包含的最多#parse的个数――默认值是10。#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
Count down.
#set( $count = 8 )
#parse( "parsefoo.vm" )
All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
$count
#set( $count = $count - 1 )
#if( $count > 0 )
#parse( "parsefoo.vm" )
#else
All done with parsefoo.vm!
#end
在显示“Count down”后,Velocity通过parsefoo.vm,从8往下数。当计数到了0,它就会显示“All done with parsefoo.vm!”。在这时,Velocity 会返回到dofoo.vm ,输出信息:“All done with dofoo.vm!”。
2.11、 包含include
#include script element允许模板设计者引入本地文件。被引入文件的内容将不会通过模板引擎被render。为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
#include( "one.txt" )
#include 引用的文件用引号括起来。
如果您需要引入多个文件,可以用逗号分隔就行:
#include( "one.gif","two.txt","three.htm" )
在括号内可以是文件名,但是更多的时候是使用变量的。这用于根据页面提交的需求而输出。这里有一个例子同时有文件名和变量。
#include( "greetings.txt", $seasonalstock )
2.12、 停止
#stop 标签允许模板设计者停止执行模板引擎并返回。把它应用于debug是很有帮助的。
3、CMS系统提供标签对象
3.1公共对象
公共对象是模板解析引擎在解析每个页面时,都会初始化数据的对象,所以在每个模板页面上都可以调用。
3.1.1 站点编号${SiteID}
调用方式:${SiteID},主要使用在各种方法的参数传递中。
3.1.2 站点名称${SiteName}
3.1.2 站点目录名${SiteFolder}
调用方式:${SiteFolder}。
3.1.3 站点域名${SiteDomain}
3.1.4 站点编码方式${SiteCode}
3.1.5 站点创建日期${SiteCreateDate}
3.1.6 当前页面位置${CurrentPosition}
调用方式:${SiteFolder},此标签效果类似与3.2.7,但是不灵活。
3.1.7 开始解析时间${ StartParseTime}
此标签主要用于调试,因为IE访问静态页面时会有缓存,调试模板时,可以把此标签放在<Title>中,这样生成后的页面如果是最新的时间,那就说明是最新生成的页面。
3.2 模板解析对象ExpValue
3.2.1取得栏目列表ExpGetCategoryList
函数原型:ArrayList ExpGetCategoryList(string SiteID,string CategoryCode,int Level,int isImage,int isDisplayIfEmpty,int order,int totalNum,int startNum,int titleWordNum,int columns,int direction)
3.2.2 取得指定栏目下的内容列表ExpGetContentInfoList
函数原型:ExpContentInfo ArrayList ExpGetContentInfoList(string SiteID, string CategoryCode, string InfoType, int Level, int totalNum, string IsHot, string OrderBy, int titleWordNum)
标签说明:
此标签通过传入的各种参数,返回内容列表对象数组
参数说明:
Ø CategoryCode,栏目编号
Ø SiteID,站点编号
Ø InfoType,信息类型,主要有:news、link、
Ø Level
Ø totalNum
Ø IsHot
Ø OrderBy
Ø titleWordNum
调用方法:
#set( $ContentInfoList = 此处因篇幅问题换行
${ExpValue.ExpGetContentInfoList(${SiteID},"018","",1,0,"","",10)})
使用场合:
此标签主要使用在各页面上显示新闻列表的区块,如首页面上显示一个公告列表,如下:
3.2.3取得栏目最新信息的详细内容ExpCategoryNewInfoContent
函数原型:string ExpCategoryNewInfoContent(string SiteID, string CategoryCode, string OrderBy)
标签说明:
此标签通过传入的各种参数,返回指定栏目中按排序方式的第一条信息的详细内容。
调用方法:
${ExpValue. ExpCategoryNewInfoContent (${SiteID },"","")}
使用场合:
主要使用在首页面上的图片广告中。
3.2.3取得指定信息的详细内容ExpGetInfoContent
函数原型:string ExpGetInfoContent(string InfoID)
标签说明:
此标签通过传入的各种参数,返回内容列表对象数组,
调用方法:
${ExpValue. ExpGetInfoContent ("")}
使用场合:
3.2.4取得指定栏目的访问地址ExpGetCategoryLinkURL
函数原型:
string ExpGetCategoryLinkURL(string CategoryCode, string SiteID)
标签说明:
此标签通过传入的各种参数,返回内容列表对象数组。
参数说明:
Ø CategoryCode,栏目编号
Ø SiteID,站点编号
调用方法:
${ExpValue.ExpGetCategoryLinkURL('017',${SiteID})}
使用场合:
此标签主要使用各页面上取得栏目首页面的链接,如网站首页面菜单上,栏目区块中的[更多]链接,如下两个图:
点更多,进入工作动态栏目的首页面。
3.2.5取得指定信息的访问地址ExpContentLink
函数原型:string ExpContentLink(string InfoID, string SiteID, string SiteDomain)
3.2.6首页面flash新闻控件ExpFlashPic
函数原型:string ExpFlashPic(string SiteID, string CategoryCode, int width, int height, string flashPath, string titlebgcolor)
3.2.7取得当前页面位置GetPosition
函数原型:string GetPosition(string SiteID, string CategoryCode, string separator, string target, string linkClass, int wordNum)
标签说明:
此标签通过传入的各种参数,返回当前页面位置。
参数说明:
Ø CategoryCode,栏目编号
Ø SiteID,站点编号
Ø Separator,分隔符
Ø Target,打开链接时的方式
Ø linkClass,链接使用的CSS
Ø wordNum,栏目名称最大文字数
调用方法:
${ExpValue.GetPosition($SiteID,$CategoryCode,">>","_self","link",20)}
使用场合:
此标签主要使用各页面上取得栏目首页面的链接,如网站首页面菜单上,栏目区块中的[更多]链接,如下两个图:
3.3私有对象
私有对象是模板解析引擎在解析每个页面时,根据不同的解析对象,初始化其特有的数据对象,所以在只能在特定的模板中调用。
3.3.1首页面
3.3.2栏目页面
1. ${FirstPage}
2. ${LastPage}
3. ${PrevPage}
4. ${NextPage}
3.3.3内容页面
1. ${InfoTitle}
取得当前页面内容的标题。
2. ${InfoContent}
取得当前页面内容。
3. ${InfoDate}
取得当前页面内容的发布日期
4、常见问题
1. 明明模板中有调用函数,但是就是页面不解析。
检查调用函数参数个数和类型是否正确。
2.