Struts2 标签库 Struts2 Taglib抽象了不同表示技术,现在Struts2主要支持三种表示技术:JSP,FreeMarker和Velocity。但部分的Tag在三种表示技术下都可以使用,但是也有部分只能在某一种情况下使用。
Tab可以分为两类:通用标签和UI标签。
4.1节 通用标签 通用标签用来在页面表示的时候控制代码执行的过程,这些标签也允许从Action或者值堆栈中取得数据。例如地域,JavaBeans,URLs,和action。
控制标签控制程序执行,例如:if,else,iterator 数据标签管理数据的取得和创建,例如:bean,push,i18n
控制标签
if标签 描述 If标签用来控制基本的条件处理流程,通常和else标签或者elseif标签连用。
参数
例子 <s:if test="%{false}"> <div>Will Not Be Executed</div> </s:if> <s:elseif test="%{true}"> <div>Will Be Executed</div> </s:elseif> <s:else> <div>Will Not Be Executed</div> </s:else>
elseIf 标签 参考if标签
else 标签 参考if标签
append标签 描述 用来做iterator标签的辅助,将不同iterator中的内容合在一个iterator中。
参数
例子 Action类 public class AppendIteratorTagAction extends ActionSupport {
private List myList1; private List myList2; private List myList3;
public String execute() throws Exception {
myList1 = new ArrayList(); myList1.add("1"); myList1.add("2"); myList1.add("3");
myList2 = new ArrayList(); myList2.add("a"); myList2.add("b"); myList2.add("c");
myList3 = new ArrayList(); myList3.add("A"); myList3.add("B"); myList3.add("C");
return "done"; }
public List getMyList1() { return myList1; } public List getMyList2() { return myList2; } public List getMyList3() { return myList3; }
标签使用 <s:append id="myAppendIterator"> <s:param value="%{myList1}" /> <s:param value="%{myList2}" /> <s:param value="%{myList3}" /> </s:append> <s:iterator value="%{#myAppendIterator}"> <s:property /> </s:iterator>
generator 标签(JSP Tag) 描述 从val属性生成一个iterator。
参数 例子 例1: 生成一个简单的iterator,并且使用iterator标签打印出内容。 <s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator> <s:property /><br/> </s:iterator> </s:generator>
例2: 生成一个iterator,使用count属性。因为count属性值为3,所以只有前三个内容(aaa,bbb,ccc)在生成的iterator中。 Generate an iterator with count attribute <s:generator val="%{'aaa,bbb,ccc,ddd,eee'}" count="3"> <s:iterator> <s:property /><br/> </s:iterator> </s:generator>
例3: 生成iterator,使用了id属性,之后生成的对象放在pageContext中,可以通过指定的id来访问。 <s:generator val="%{'aaa,bbb,ccc,ddd,eee'}" count="4" separator="," id="myAtt" /> <% Iterator i = (Iterator) pageContext.getAttribute("myAtt"); while(i.hasNext()) { String s = (String) i.next(); %> <%= s %> <br/> <% } %>
例4: 生成iterator,使用converter属性,这里的convertor仅仅将每一个对象添加了一个"converter-"前缀。 <s:generator val="%{'aaa,bbb,ccc,ddd,eee'}" converter="%{myConverter}"> <s:iterator> <s:property /><br/> </s:iterator> </s:generator>
public class GeneratorTagAction extends ActionSupport {
....
public Converter getMyConverter() { return new Converter() { public Object convert(String value) throws Exception { return "converter-"+value; } }; }
...
}
iterator 标签 描述 迭代处理一个java.util.Connection或者java.util.Iterator对象
参数
例子 例1: <s:iterator value="days"> <p>day is: <s:property/></p> </s:iterator>
例2: <s:bean name="org.apache.struts2.example.IteratorExample" id="it"> <s:param name="day" value="'foo'"/> <s:param name="day" value="'bar'"/> </s:bean> <p/> <table border="0" cellspacing="0" cellpadding="1"> <tr> <th>Days of the week</th> </tr> <p/> <s:iterator value="#it.days" status="rowstatus"> <tr> <s:if test="#rowstatus.odd == true"> <td style="background: grey"><s:property/></td> </s:if> <s:else> <td><s:property/></td> </s:else> </tr> </s:iterator> </table>
例3: <s:iterator value="groupDao.groups" status="groupStatus"> <tr class="<s:if test="#groupStatus.odd == true ">odd</s:if><s:else>even</s:else>"> <td><s:property value="name" /></td> <td><s:property value="description" /></td> <td> <s:iterator value="users" status="userStatus"> <s:property value="fullName" /> <s:if test="!#userStatus.last">,</s:if> </s:iterator> </td> </tr> </s:iterator>
merge 标签(同append?) 描述 参数 例子
sort 标签(JSP-Tag) 描述 对一个可以迭代的对象进行排序操作。
参数
例子 例1: <s:sort comparator="myComparator" source="myList"> <s:iterator> <!-- do something with each sorted elements --> <s:property value="..." /> </s:iterator> </s:sort>
例2: <s:sort id="mySortedList" comparator="myComparator" source="myList" /> <% Iterator sortedIterator = (Iterator) pageContext.getAttribute("mySortedList"); for (Iterator i = sortedIterator; i.hasNext(); ) { // do something with each of the sorted elements } %>
subset 描述 递归iterator的一部分
参数
例子 Java类
public class MySubsetTagAction extends ActionSupport { public String execute() throws Exception { l = new ArrayList(); l.add(new Integer(1)); l.add(new Integer(2)); l.add(new Integer(3)); l.add(new Integer(4)); l.add(new Integer(5)); return "done"; }
public Integer[] getMyArray() { return a; }
public List getMyList() { return l; }
public Decider getMyDecider() { return new Decider() { public boolean decide(Object element) throws Exception { int i = ((Integer)element).intValue(); return (((i % 2) == 0)?true:false); } }; } } <!-- s: List basic --> <s:subset source="myList"> <s:iterator> <s:property /> </s:iterator> </s:subset> <!-- B: List with count --> <s:subset source="myList" count="3"> <s:iterator> <s:property /> </s:iterator> </s:subset> <!-- C: List with start --> <s:subset source="myList" count="13" start="3"> <s:iterator> <s:property /> </s:iterator> </s:subset> <!-- D: List with id --> <s:subset id="mySubset" source="myList" count="13" start="3" /> <% Iterator i = (Iterator) pageContext.getAttribute("mySubset"); while(i.hasNext()) { %> <%=i.next() %> <% } %> <!-- D: List with Decider --> <s:subset source="myList" decider="myDecider"> <s:iterator> <s:property /> </s:iterator> </s:subset>
数据标签 @TODO 完成如下数据标签 数据标签包括 a action bean date debug i18n include param push set text url property
4.2节 UI标签 UI标签主要是指Form相关的标签,UI标签又分为两部分:form标签和构成form内部字段的其他标签。 每一个UI标签都是基于模板的,即:每一个标签都有一个对应的模板用来生成UI标签的样式,详细内容参看模板节。
所有的UI标签都有着共通的祖先UIBean,UIBean提供了这些UI标签的一系列共通的属性,这些属性可以分为三类:模版相关的属性,JavaScript相关的属性和其他通用属性。
模版相关属性:
JavaScript相关属性:
Tooltip相关属性:
通用属性:
对于name和value的说明: name用来说明Form字段的名字,和Action类的属性对应。 value用来记录Form字段的值,和Action类中属性的值对应。 所以在修改一个字段的内容的时候应该使用如下的标签: <s:form action="updateAddress"> <s:textfield label="Postal Code" name="postalCode" value="%{postalCode}"/> ... </s:form> 但是,由于name和value的关系,struts2标准标签可以自动对应,所以也可以使用如下标签: <s:form action="updateAddress"> <s:textfield label="Postal Code" name="postalCode" /> ... </s:form>
UI标签说明: Form部分 autocompleter checkbox checkboxlist combobox datetimepicker doubleselect head file form hidden label optiontransferselect optgroup password radio reset select submit textarea textfield token updownselect
非Form部分: actionerror actionmessage component div fielderror table tabbedPanel tree treenode
4.3节 主题和模板 概念说明: 标签(tag):一小段代码,在JSP,Velocity或者FreeMarker中执行。程序开发的最小单位,用来生成HTML对应的元素。 模板(template):一些代码,通常使用FreeMarker写成,可以被某些Tag表示出来(通常是UI Tag)。 主题(theme):一组模板打包在一起,提供通用功能的模版
主题和模板主要针对可视化的标签(Tag)而言,使用以下例子来说明三者之间的关系。 假如我们要开发如下的一个画面: 我们使用如下的代码:
<s:url action="login" id="loginUrl"></s:url> <s:form action="%{loginUrl}"> <s:textfield label="Name" name="name"/> <s:password label="Password" name="password" /> <s:submit></s:submit> <s:reset></s:reset> </s:form>
这里<s:form>,<s:textfield>,<s:password>,<s:submit>,<s:reset>每一个都是一个标签(tag)。
我们在看看这些标签在一起生成的HTML源代码: <form id="login" οnsubmit="return true;" action="/login/login/login.action" method="post"> <table class="wwFormTable"> <tr> <td class="tdLabel"> <label for="login_name" class="label"> Name: </label> </td> <td> <input type="text" name="name" value="" id="login_name" /> </td> </tr>
<tr> <td class="tdLabel"> <label for="login_password" class="label"> Password: </label></td> <td> <input type="password" name="password" id="login_password" /> </td> </tr>
<tr> <td colspan="2"> <div align="right"><input type="submit" id="login_0" value="Submit" /></div> </td> </tr>
<tr> <td colspan="2"> <div align="right"><input type="reset" value="Reset" /></div> </td> </tr>
</table> </form>
在由标签生成HTML代码的时候,例如: <s:textfield label="Name" name="name"/> 生成的代码为: <tr> <td class="tdLabel"> <label for="login_name" class="label"> Name: </label> </td> <td> <input type="text" name="name" value="" id="login_name" /> </td> </tr> 我们可以看到,<s:textfield>标签提供的有效信息只有Name和name,而其余的部分,例如<tr>,<td>,<label>等代码都根据一个固定的模板文件生成,这个模板文件为:
标签使我们开发JSP画面的时候使用的最小组件单元,我们根据客户的需要组合各种Tag达到客户的需求。模板是生成这些Tag时候使用的,使用模板可以定义Tag的基本形式,在使用tag的时候,我们只需要指定该Tag的不同属性,即可根据Tag指定的特殊属性,结合模板的基本属性生成可视化的HTML元素。主题是不同tag结合在一起而形成的。 <input type="text"<#rt/> name="${parameters.name?default("")?html}"<#rt/> <#if parameters.get("size")?exists> size="${parameters.get("size")?html}"<#rt/> </#if> <#if parameters.maxlength?exists> maxlength="${parameters.maxlength?html}"<#rt/> </#if> <#if parameters.nameValue?exists> value="<@s.property value="parameters.nameValue"/>"<#rt/> </#if> <#if parameters.disabled?default(false)> disabled="disabled"<#rt/> </#if> <#if parameters.readonly?default(false)> readonly="readonly"<#rt/> </#if> <#if parameters.tabindex?exists> tabindex="${parameters.tabindex?html}"<#rt/> </#if> <#if parameters.id?exists> id="${parameters.id?html}"<#rt/> </#if> <#if parameters.cssClass?exists> class="${parameters.cssClass?html}"<#rt/> </#if> <#if parameters.cssStyle?exists> style="${parameters.cssStyle?html}"<#rt/> </#if> <#if parameters.title?exists> title="${parameters.title?html}"<#rt/> </#if> <#include "/${parameters.templateDir}/simple/scripting-events.ftl" /> <#include "/${parameters.templateDir}/simple/common-attributes.ftl" /> />
我们考虑标签(Tag)使用模板(Template)生成HTML的过程,根据不同的模板,坑顶可以生成不同的HTML画面,这样我们可以把不同tag的,视觉效果一致的模板放在一起: 例如: <s:form> TemplateForm_A, TemplateForm_B <s:textfield> TemplateTextField_A, TemplateTextField_B <s:password> TemplatePassword_A, TemplatePassword_B <s:submit>, TemplateSubmit_A, TemplateSubmit_B <s:reset> TemplateReset_A, TemplateReset_B
这样将_A的模板放在一起叫做A主题(Theme),将_B的模板放在一起叫B主题。这样我们在分别使用A主题,B主题的时候可以得到同一个Tag的不同的视觉效果。
模版和主题的概念处在Struts Tag的核心位置。
Struts2默认提供了四种主题: Simple 主题:最简单的主题 XHTML 主题:默认主题,使用常用的HTML技巧 CSS XHTML主题: 使用CSS实现的XHTML主题 AJAX 主题:基于XHTML主题,但是同工了AJAX功能
相关配置: 在struts.properties文件中有如下项目: struts.ui.theme=xhtml struts.ui.templateDir=template struts.ui.templateSuffix=ftl
struts.ui.theme的值表示的是使用哪个主题,可选项位:xhtml,simple,css_html,ajax其中xhtml为默认值。 struts.ui.templateDir的值表示模板的存放目录。 struts.ui.templateSuffix的值表示模板文件明的后缀,因为Struts2默认使用FreeMarker来编写模板,所以这里我们基本使用ftl。 另外也可以使用vm(Velocity)和jsp(Java Server Page),但是所有的Template和Theme要我们自己开发。
关于模板文件的存放目录我们需要详细说明,如上述说明,模板文件的存放位置位template,那么系统在那里寻找template目录呢, 首先,在web应用程序中查找,如果应用程序中存在一个叫做template的目录(跟WEB-INF目录平级),那么所有的文件从这个目录中取得,具体的路径还要加上主题的名字。 然后,如果在web应用程序中没有找到template目录,那么struts2会在classpath中寻找,由于struts2-core-2.0.9.jar文件中存在template目录,其中内置了四种主题,所以会使用这里变的模板。 例如: 如果我们使用了ajax主题,那么会在如下位置超找<s:textfield>的主题
修改或者扩展模板: 有些时候Struts提供的模板不一定能够满足我们的需求,这时候我们需要修改或者扩展现有模板。重新做新的模板是不明智的,如果是在需要全新的模板,可以考虑基于simple扩展。
修改: 根据模板的装载机制,可以考虑将模板从struts2-core-2.0.9.jar文件中解压缩到web项目目录,之后修改对应的文件。
包装: XHTML提供了一个很好的例子,simple主题提供了基本的功能,XHTML将它包括起来,例如: 以下是template/xhtml/xxx.ftl(xxx表示模板名字)文件内容: <#include "/${parameters.templateDir}/xhtml/controlheader.ftl" /> <#include "/${parameters.templateDir}/simple/xxx.ftl" /> <#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />
扩展(extend): 使用棉线对象的特性可以扩展一个主题,扩展一个主题的时候不需要实现所有的模板,只需要实现需要变化的标签。 扩展需要在目录中新建一个叫做theme.properties的文件,这个文件只有一行,表明了继承而来的主题的名字,例如: /template/ajax/theme.properties文件内容为: parent = xhtml
4.4节 AJAX标签(试验阶段) Struts2内置了Dojo 0.4 来提供对Ajax的支持。 想要使用AJAX标签需要做到两点: 1 使用Ajax主题 2 在JSP画面中使用了head标签配置Ajax属性
AJAX标签主要有: <s:div> <s:submit> <s:a> <s:tabbedPanel> <s:autocompleter>
AJAX标签的一些通用属性:
Indicator <img style="display:none" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading..."/>
Topic 监听一个Topic: dojo.event.topic.subscribe("/refresh", function(param1, param2) { //this function will be called everytime "/refresh" is published }); 向一个Topic发布内容: dojo.event.topic.publish("/refresh", "foo", "bar");
URL Href属性对应的URL必须使用URL标签定义,例如: <s:url id="ajaxTest" value="/AjaxTest.action" /> <s:div theme="ajax" href="%{ajaxTest}"> Initial Content </s:div>
DIV标签: Div主要用来异步的显示数据, PageLoad会出发Div中数据的显示,除非把AutoStart设置为False。 另外,Div的数据显示可以使用Topic来触发。使用listenTopic来定义触发器。
例如: <s:url id="ajaxTest" value="/AjaxTest.action" /> <s:div theme="ajax" href="%{ajaxTest}" listenTopics="/refresh0,/refresh1"/> 每次想/refresh0,/refresh1发布内容的时候,上面代码定义的div都会刷新。
使用updateFreq可以让Div周期性的触发,在autoStart设置位true的情况下,可以使用delay来延迟首次画面加载的出发时间,例如: <s:url id="ajaxTest" value="/AjaxTest.action" /> <s:div theme="ajax" href="%{ajaxTest}" updateFreq="2000" delay="3000"/> 上述代码说明,每隔2秒该div触发内容更新一次,但是首次画面加载完成之后3秒div出发内容更新。
@todo 其他标签
4.5节 OGNL OGNL是Object Graph Navigation Language的简称,详细相关的信息可以参考:http://www.ognl.org。这里我们只涉及Struts2框架中对OGNL的基本支持。
OGNL是一个对象,属性的查询语言。在OGNL中有一个类型为Map的Context(称为上下文),在这个上下文中有一个根元素(root),对根元素的属性的访问可以直接使用属性名字,但是对于其他非根元素属性的访问必须加上特殊符号#。
在Struts2中上下文为ActionContext,根元素位Value Stack(值堆栈,值堆栈代表了一族对象而不是一个对象,其中Action类的实例也属于值堆栈的一个)。ActionContext中的内容如下图: | |--application | |--session context map---| |--value stack(root) | |--request | |--parameters | |--attr (searches page, request, session, then application scopes) | 因为Action实例被放在Value Stack中,而Value Stack又是根元素(root)中的一个,所以对Action中的属性的访问可以不使用标记#,而对其他的访问都必须使用#标记。
引用Action的属性 <s:property value="postalCode"/> ActionContext中的其他非根(root)元素的属性可以按照如下的方式访问: <s:property value="#session.mySessionPropKey"/> or <s:property value="#session["mySessionPropKey"]"/> or <s:property value="#request["mySessionPropKey"]/>
Action类可以使用ActionContext中的静态方法来访问ActionContext。 ActionContext.getContext().getSession().put("mySessionPropKey", mySessionObject);
OGNL与Collection(Lists,Maps,Sets)
生成List的语法为: {e1,e2,e3}. <s:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" /> 上面的代码生成了一个HTML Select对象,可选的内容为: name1,name2,name3,默认值为:name2。
生成Map的语法为:#{key1:value1,key2:value2}. <s:select label="label" name="name" list="#{'foo':'foovalue', 'bar':'barvalue'}" /> 上面的代码生成了一个HTML Select对象,foo名字表示的内容为:foovalue,bar名字表示的内容为:barvalue。
判断一个对象是否在List内存在: <s:if test="'foo' in {'foo','bar'}"> muhahaha </s:if> <s:else> boo </s:else>
<s:if test="'foo' not in {'foo','bar'}"> muhahaha </s:if> <s:else> boo </s:else>
取得一个List的一部分: ? – 所有满足选择逻辑的对象 ^ - 第一个满足选择逻辑的对象 $ - 最后一个满足选择逻辑的对象 例如: person.relatives.{? #this.gender == 'male'} 上述代码取得这个人(person)所有的男性(this.gender==male)的亲戚(relatives)
Lambda 表达式
OGNL支持简单的Lambda表达式语法,使用这些语法可以建立简单的lambda函数。
例如: Fibonacci: if n==0 return 0; elseif n==1 return 1; else return fib(n-2)+fib(n-1); fib(0) = 0 fib(1) = 1 fib(11) = 89
OGNL的Lambda表达式如何工作呢? Lambda表达式必须放在方括号内部,#this表示表达式的参数。例如: <s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" />
#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)]定义了一个Lambda表达式, #fib(11) 调用了这个表达式。
所以上述代码的输出为:89
在JSP2.1中#被用作了JSP EL(表达式语言)的特殊记好,所以对OGNL的使用可能导致问题, 一个简单的方法是禁用JSP2.1的EL特性,这需要修改web.xml文件: <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>true</el-ignored> </jsp-property-group> </jsp-config>
4.6节 Tag 语法 代码示例:
|