Expresso表示层的深入使用研究
修订历史记录
日期 | 版本 | 说明 | 作者 |
2005-08-19 | 1.0 | 初建 | 唐家平 |
2005-08-26 | 1.1 | 修改部分内容 | 唐家平 |
|
|
|
|
2 Struts tag和Extended Struts tag思想... 2
3 Expresso Extended Struts Tags 2
1 前言
表示层的内容主要是描述标签库,在Expresso框架中网页的标签库主要包括如下5类:
HyperText Markup Language (HTML)
Java Standard Tag Library (JSTL)
Struts Tags
Expresso Extended Struts Tags
Expresso Tag Library
前两种就不必说了,后三种其实是一种继承关系。如果说JSTL描述的是一个对象的定义的话(如<jsp:usebean property="controllerResponse">),则第三种和第四种则是着重描述对象的属性。最后一种,则是对Expresso对象的一种定制。
下文将着重描述Expresso Extended Struts Tags和Expresso Tag Library,对于其他标签库,只是一笔带过,具体使用细节请读者查阅相关文档。
2 Struts tag和Extended Struts tag思想
在我们编写Java bean时,我们采用get/set的命名模式来完成属性的定义。在这种模式里,我们采用'get'或'set'加上属性名称的首字母大写的方式来定义一个属性。例如,我们要读取一个对象的Name属性时,则实质是需要调用该对象的getName()方法。Struts tag和Expresso Extended Struts tag的核心思想正是源自这种对对象属性的操作方法,但要记住的是,这里的属性并不是对象的属性本身,而是对象作为包含在别的对象之内使,该对象作为包含对象的属性看待。
Expresso Extended Struts tag针对Expresso的对象读取进行了定制,使用之来显示Expresso的对象变得更简单,它们之间的异同请看下表:
| 访问属性对象方式 | 嵌套 | 读取Output的属性* |
Struts tag | id="" name="" property="" | . | attribute() |
Extended Struts tag | id="" name="" property="" | /和. | @ |
Id:定义在JSP页面的访问该对象的名称;
Name:标明访问的是哪个对象,该名称是非本标签内id所定义的;
Property:标明访问的是对象的哪个属性,属性有嵌套特性,相当于我们编写程序时使用“.”访问;Expresso Extended Struts tag里“/”表示对象嵌套,“.”表示对象本身属性的引用,通常可使用“.”引用的属性有label、description、type、url等。
Type:定义在JSP页面的访问该对象的类型;
3 Expresso Extended Struts Tags
在使用Expresso扩展Struts标签库时,需要在.jsp的页面头部申明如下:
<%@ taglib uri="/WEB-INf/tld/expresso-logic.tld" prefix="logic"%>
<%@ taglib uri="/WEB-INF/tld/expresso-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/tld/expresso-bean.tld" prefix="bean"%>
一个隐含的规则是:读取位于controllerResponse根下的对象,name="controllerResponse"项是省去不写的。
1)可用iterate访问的几类特殊的“属性”:
outputs:在ControllerResponse 或Block对象里的所有Output对象;
inputs:在ControllerResponse 或Block对象里的所有Input对象;
transitions:在ControllerResponse 或Block对象里的所有Transition对象;
blocks:在ControllerResponse 或Block对象里的所有Block对象;
nested:在ControllerResponse 或Block对象里的所有嵌套的对象;
2)嵌套访问:
a/b 引用嵌套在"a"对象的"b"对象;
a/b.label 引用嵌套在"a"对象的"b"对象的"label"属性,即调用getLabel()方法;
a/b.@something 引用嵌套在"a"对象的"b"对象的"something"*attribute*。没有“/@”、或级联的“@”形式;
3)存在判断:
<logic:present property="@multiValued">
</logic:present>
4)定义一个对象引用:
<bean:define id="url" name="oneTra" property="url" type="java.lang.String"/>
该功能有点相当于我们熟悉的标签:
<jsp:usebean id=”url” class=”xx.oneTra.url” scope="request" />
3.1 读取Output对象
读取一个名为“hello”的Output对象,我们可以使用如下标签:
<bean:write property="hello"/>
<bean:write property="hello.@xx"/>
<bean:write property="hello.label"/>
3.2 读取Input对象
根据输出的对象类型不同,分为以下几种形式:
<html:text name="oneInput"/>
<html:select name="oneInput"/>
<html:checkbox name="oneInput"/>
<html:file name="oneInput"/>
<html:textarea name="oneInput" rows="7" cols="50"/>
Input的label值来自于它的setLabel()方法设置的值。
<label for="<%=inputName%>">
<bean:write name="oneInput" property="label"/>:
</label>
3.3 创建一个输入form页面
本例包含对Input对象、Transition对象的读取。
<html:form action="/tags.do" method="post">
<html:text property="input1"/>
<html:submit property="process"/>
</html:form>
3.4 产生一个Url连接
作为按钮请看上例,以下对Transition的另外2种读取方式。事实上,Transition对象有着一个url特殊属性(getUrl())。
<html:exLink property="logout"/>
<bean:define id="url" name="oneTra" property="url" type="java.lang.String"/>
<html:link page="<%= url %>">
<bean:write name="oneTra" property="label"/>
</html:link>
3.5 遍历Block对象内的对象
若我们要显示一个列表,则需要遍历显示Block对象里的内容,例子如下:
<logic:iterate id="eachPrisoner" property="aBlock"/>
<bean:write name="eachPrisoner"/>
<bean:write name="eachPrisoner" property="@CellNumber"/>
</logic:iterate>
比较遗憾的是,该地方输出结果并不是我们意料的那样,而只显示了一个Output内容,其余信息丢失。
对于这种只有一层Block的对象嵌套Output对象的显示,通常是采用如下方式:
<bean:write property="aBlock/prisonHelloA"/>
<bean:write property="aBlock/prisonHelloA.@CellNumber"/><br/>
<bean:write property="aBlock/prisonHelloB"/>
<bean:write property="aBlock/prisonHelloB.@CellNumber"/><br/>
对于这种只有一层Block的对象嵌套Transition对象的显示,则可采用上面的显示结构:
<logic:iterate id="oneTra" property="details">
<bean:define id="det" name="oneTra" property="url" type="java.lang.String"/>
<html:link page="<%= det %>">
<bean:write name="oneTra" property="label"/>
</html:link>
</logic:iterate>
通常情况下,Block用于传递一张表的数据,使用例子如下:
<table border="1" cellspacing="0" cellpadding="1">
<tr bgcolor="#000099">
<td width="15%"><font color="#FFFFFF"> 1 </font></td>
<td><font color="#FFFFFF"> 2 </font></td>
</tr>
<logic:iterate id="oneRow" property="table" >
<tr>
<logic:iterate id="oneCol" name="oneRow" property="outputs">
<logic:present name="oneCol" property="/detail">
<bean:define id="url" name="oneCol" property="/detail.url"
type="java.lang.String"/>
<td>
<html:link page="<%= url %>">
<bean:write name="oneCol"/>
</html:link>
</td>
</logic:present>
<logic:notPresent name="oneCol" property="/detail">
<td>
<bean:write name="oneCol"/>
</td>
</logic:notPresent>
</logic:iterate>
</tr>
</logic:iterate>
</table>
注:由于DBMaint所使用的标签90%都是Expresso Extended Struts tag,所以以上的大部分例子均来自于DBMaint的表示层,读者可到那里找到对应的影子。
4 Expresso Tag Library
Expresso Tag是面对展现Expresso控制层输出对象的定制,进一步方便操作,相对于前面几类标签库,常用操作更简洁明了、更易理解。只是定制带来了限制,在得到优越性的同时,牺牲了灵活性。
Expresso Tag最明显的优点是:对Input对象的强大表现力、采用结构上的包含关系表示嵌套关系。
缺点是:读取对象的属性、展现Transition成Url等方面就没有Expresso Extended Struts tags好。我们通常需要对Input字段进行说明描述,可是Expresso Tag却没有提供读取description的标签。不能自由地定义一个用以在页面里操作的对象。可见Expresso Tag并不完善,希望在高版本的得到补充。
4.1 读取Output对象
<expresso:OutputTag name="Hendrix" >
<expresso:ContentTag/>
<expresso:AttributeTag name="fullname" />
</expresso:OutputTag>
4.2 读取Input对象
<expresso:LabelTag name="input1" type="input"/><br/>
<expresso:InputTag name="input1" /><br/>
<!--由于Expresso的一个Bug,此处type="INPUT"的Input必须大写-->
<expresso:AttributeTag name="desc" controllerElement="input1" type="INPUT"/><br/>
4.3 创建一个输入form页面
<form action="/Demo.do?cmd=button" method="post">
<expresso:LabelTag name="input1" type="input"/><br/>
<expresso:InputTag name="input1" /><br/>
<expresso:TransitionTag name="process" />
</form>
4.4 遍历Block对象内的对象
对于这种只有一层Block的对象嵌套Output、Input对象的显示,通常是采用如下方式:
<expresso:Block name="aBlock">
<expresso:ElementCollection type="output">
<expresso:ElementIterator>
<expresso:OutputTag name="xxx">
<expresso:ContentTag />---
<expresso:AttributeTag name="CellNumber" /><br/>
</expresso:OutputTag>
</expresso:ElementIterator>
</expresso:ElementCollection>
</expresso:Block>
<expresso:Block name="inputBlock">
<expresso:ElementCollection type="input">
<expresso:ElementIterator>
<expresso:LabelTag name="xx" type="input"/><br/>
<expresso:InputTag name="xxx"/><br/>
</expresso:ElementIterator>
</expresso:ElementCollection>
</expresso:Block>
显示一张表格:
<table border="1" cellspacing="0" cellpadding="1">
<expresso:TableHead value="1|2|3"/>
<expresso:Block name="table">
<expresso:ElementCollection type="block">
<expresso:ElementIterator>
<tr>
<expresso:ElementCollection type="output">
<expresso:ElementIterator>
<expresso:OutputTag name="xxx">
<td><expresso:ContentTag /></td>
</expresso:OutputTag>
</expresso:ElementIterator>
</expresso:ElementCollection>
<expresso:ElementCollection type="transition">
<expresso:ElementIterator>
<form
action="/Demo.do?cmd=button"
method="get">
<td><expresso:TransitionTag name="detail" /></td>
</form>
</expresso:ElementIterator>
</expresso:ElementCollection>
</tr>
</expresso:ElementIterator>
</expresso:ElementCollection>
</expresso:Block>
</table>
4.5 显示错误信息
可以智能地显示由页面传来的ErrorCollection对象所包含的错误信息。
<expresso:ErrorTag />
4.6 判断对象是否存在
<expresso:IfElementExists name="inputBlock" type="block">
…
</expresso:IfElementExists>
5 表格隔行颜色显示原理
简单的方法可以编写如下代码实现,这里主要是使用了Expresso Extend Struts tag的indexId="rowCount"。
<logic:iterate id="oneRow" property="table" indexId="rowCount" >
<tr bgcolor="<%= (rowCount.intValue()) % 2 == 1 ? "white" : "#FFFFCC"%>">
…
</tr>
</logic:iterate>
在DBMaint的实现中,其实是牵涉到一个风格的实现,原理如下:
1)在Expresso系统表Setup表里,存在着风格的设置:defaultCSS;
2)在ROOT/expresso/style/目录下则存在着各种各样的风格CSS文件;
3)在JSP页面有<expresso:stylesheet/>引用该映射表;
4)在每一个<TR >等标签有形如<TR class="jc-row-alt">的引用。
6 总结
各种标签库都有着自己的优势和缺点,我们需要结合着使用。有时候,我们找遍了已有标签库,就是找不到我们想要的功能,也许只有我们自己开发了。若开发,则带来一个如何开发的问题,怎样开发既扩展了我们想要的功能,又不破坏Expresso框架的封装性?
原则上,我们不开发标签库,而需要总结出一套适合我们表达习惯的标签使用方法,满足我们展现页面的需要,也规范了我们的界面设计人员。一般情况下,Expresso Extended Struts Tag是灵活性和智能性结合点较好的一个标签库,也许这也正是DBMaint大部分使用该标签库的一个主要原因吧。
本次研究侧重于Expresso的研究,对于Struts标签库部分则是轻描淡写。事实上,由于Expresso是对Struts进行了一次封装,我们面对还没能得到解决的问题,也许使用Struts标签库已可以很好解决了。因此,我们还是建议对Struts进行一些必要的研究。
作为一个副产品,本人发现如下标签和本地化、国际化有关,该问题需要得到继续研究:
<label for=""></label>
<html:submit name="oneTransition"/>
7 参考资料
Orange Trader Example Web Application
Expresso 5.5 Developer's Guide