說明:本文大部分內容翻譯自struts-2.0.8-all\struts-2.0.8\docs\docs\using-tags.html,并將struts2的標簽作為附錄補充,標簽尚有部分未補充完。
在上篇(Hello World篇)中,我們呈現了一個簡單的歡迎界面。在本篇中,我們將創建鏈接到應用其他Action的鏈接。
Web應用程序與傳統的Web站點有所不同,在Web應用程序中我們可以創建動態的返回。為了更容易的在頁面上獲得動態數據,本框架提供了一些標簽集。其中有些標簽模擬了標準的HTML標簽,但是提供了一些額外功能。還有一些框架提供了非標準的、但非常有用的控制功能。
Struts標簽的一個使用是創建一個到另外的Web資源的訪問鏈接,特別是到本地的其他資源的鏈接。
說明:雖然HTML為創建超鏈接提供了簡單的標簽,HTML標簽常常需要我們包括一些冗余的信息。并且HTML標簽不能很容易的得到本框架的動態數據。
一. 鏈接標簽
在Web應用程序中的一個常用的功能是鏈接到其他頁面,現在讓我們為前面章節的歡迎界面添加到其他Action的鏈接。
二. 代碼
顯示注冊與登錄的jsp的代碼如下:
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Welcome</title>
<link href="<s:url value="/css/tutorial.css"/>" rel="stylesheet"
type="text/css"/>
</head>
<body>
<h3>Commands</h3>
<ul>
<li><a href="<s:url action="Register"/>">Register</a></li>
<li><a href="<s:url action="Logon"/>">Sign On</a></li>
</ul>
</body>
</html>
運行效果如下:
另一個常用的功能是使用鏈接來改變語言,在前章的HelloWorld頁面中,讓我們改變用戶的語言,并根據對應的應用程序資源來呈現信息。代碼如下:
<body>
<h2><s:property value="message"/></h2>
<h3>Languages</h3>
<ul>
<li>
<s:url id="url" action="HelloWorld">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}">English</s:a>
</li>
<li>
<s:url id="url" action="HelloWorld">
<s:param name="request_locale">es</s:param>
</s:url>
<s:a href="%{url}">Espanol</s:a>
</li>
</ul>
</body>
運行效果如下:
一. 代碼是如何工作的?
上述例子中的“%{url}”將會被s:url標簽來求得對應的值。在Welcome和HelloWorld頁中,我們使用了兩種不同的鏈接標簽。我們可以創建如下標簽:
l 資源鏈接
l 直接的鏈接
l 帶參數的鏈接
下面讓我們分別看一下它們的使用:
1. 資源鏈接
首先在jsp的HEAD元素中,我們使用url標簽來將資源引入到頁面中,代碼如下:
<link href="<s:url value="/css/tutorial.css"/>"
rel="stylesheet" type="text/css"/>
注意:引用時絕對的。我們可以移動該頁面到其他路經而不用擔心相對路徑。
2.直接鏈接
我們可以使用鏈接標簽來定向到Action,實例代碼如下:
<li><a href="<s:url action="Register"/>">Register</a></li>
當鏈接運作的時候,鏈接標簽能夠自動追加正確的擴展,因此我們不需要在應用程序中嵌入。這個標簽也將會用會話id來編碼鏈接的URL,因此Java的會話在請求之間能夠保持。
3.帶有參數的鏈接
在上述的有關改變語言的HelloWorld頁中,我們可以使用帶有參數信息的url標簽來創建帶有參數的鏈接,該段代碼如下:
<s:url id="url" action="Welcome">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}">English</s:a>
param標簽將會在Welcome的Action的url后增加信息:“?request_locale=en”。這個標簽接著將“url”引用注入到超鏈接中。
說明:通過增加param標簽能夠增加任意數量的標簽。
二. 通配符映射
在上述例子的Welcome頁面中,除了鏈接之外尚未添加任何內容,我們不需要添加Action類。但是,我們仍然需要添加一個映射,以便我們可以使用action URI(如果我們向映射到action,而不是頁面,我們在后面也可以很容易的添加Action類),映射代碼如下:
<action name="Welcome" >
<result>/tutorial/Welcome.jsp</result>
</action>
當我們創建應用程序的時候,我們常常需要直接鏈接到頁頁面,為了使原型更加容易,我們可以將Welcome的進入改為通配符,修改后的映射如下:
<action name="*" >
<result>/tutorial/{1}.jsp</result>
</action>
這是代碼是如何工作的呢?
如果找不到映射,本框架將會做如下工作:
l 將“Welcome”映射為星號
l 將“Welcome”代替result中對應的“{1}”
同樣的,如果在映射文件中找不到“Login”的映射,將會映射到“/tutorial /Login.jsp”頁面。
說明:通配符映射能夠使得你能夠創建你自己的規約,以便你能夠避免冗余的配置。
三. 數據輸入表單
大多數應用程序都使用一些數據進入表單。Struts標簽使得輸入表單更加容易,代碼如下:
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<s:form action="Logon">
<s:textfield label="User Name" name="username"/>
<s:password label="Password" name="password" />
<s:submit/>
</s:form>
</body>
</html>
執行效果如下:
代碼是如何工作的呢?
l JSP標簽在頁面頂部引入了Struts的標簽庫
l Struts標簽:textfield、password和submit,每一個都寫出了正確的Lable和控制類型
四. 需要記住的東西
編寫web應用程序的最難的一部分是編寫頁面。本框架通過提供一系列的Struts標簽使得編寫頁面更加容易。Struts標簽能夠獲得框架提供的動態數據。標簽減少了用來創建頁面所需做的工作。
附錄一
——標簽使用指南
一. 通用標簽
通用標簽被用來在頁面執行的時候,來控制執行流。這些標簽同樣允許數據不是從Action或者值棧中提取,例如本地化、JavaBeans、包括額外的URL或action執行。
l 控制類標簽提供了控制流,例如if,else和iterator
l 數據類標簽允許數據操作或創建,例如bean、push和i18n
控制類標簽有if、elseIf、 else、append、generator、iterator、merge、sort、subset。
數據類標簽有a、action、bean、date、debug、i18n、include、param、push、set、text、url、property。
分別介紹如下:
1. 控制類標簽
1)if、elseif和else
描述:執行基本的控制流,if能單獨使用,也可與else、elseif標簽搭配使用。
參數:
名稱
|
必選
|
默認值
|
求值
|
類型
|
描述
|
id
|
否
|
|
是
|
String
|
id用來引用元素。對于UI或者form標簽,它的意義等同于HTML的id屬性
|
test
|
是
|
|
是
|
Boolean
|
用來決定標簽體師是否顯示的表達式
|
使用舉例:
<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>
2)append
該標簽的工作是追加迭代器來,
例如,如果有三個迭代器(每個迭代器有三個元素)需要追加,下面展示了這個追加迭代器是如何排列的。
首先是進入第一個迭代器的第一個元素;
第二步是進入第一個迭代器的第二個元素;
第三步是進入第一個迭代器的第三個元素;
第四步是進入第二個迭代器的第一個元素;
第五步是進入第二個迭代器的第二個元素;
第六步是進入第二個迭代器的第三個元素;
第七步是進入第三個迭代器的第一個元素;
第八步是進入第三個迭代器的第二個元素;
第九步是進入第三個迭代器的第三個元素。
參數:
名稱
|
必選
|
默認值
|
求值
|
類型
|
描述
|
id
|
否
|
|
是
|
String
|
如果提供了該id的值,將會具有追加迭代器存儲到堆棧上下文中的合成結果
|
使用舉例:
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; }

jsp
頁面的代碼:
<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>
3)generator
描述:創建一個基于提供的值的迭代器。
注意:產生的迭代器將常常被推入堆棧頂部,而在標簽結束的時候被推出。
參數:
名稱
|
必選
|
默認值
|
求值
|
類型
|
描述
|
converter
|
否
|
|
是
|
org.apache.struts2.util.IteratorGenerator.Converter
|
將從值中分析的字符串轉換為一個對象的轉換器
|
count
|
否
|
|
是
|
Integer
|
在迭代器中的最大值
|
id
|
否
|
|
是
|
String
|
如果提供了id,它將會用來存儲產生的迭代器到頁面上下文
|
separator
|
是
|
|
是
|
String
|
分隔符用來將迭代器中的值分開
|
val
|
是
|
|
是
|
String
|
用來解析成迭代器的源
|
舉例:
例1:
<pre>
例一:
產生一個簡單的迭代器
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}">
<s:iterator>
<s:property /><br/>
</s:iterator>
</s:generator>
</pre>
這里產生了一個迭代器,并且使用iterator標簽將它打印出來
例二:
<pre>
產生一個帶有count屬性的迭代器
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}" count="3">
<s:iterator>
<s:property /><br/>
</s:iterator>
</s:generator>
</pre>
這里產生了一個迭代器,但是只有其中的三個元素是可用的,這三個分別是aaa、bbb和ccc
例三:
<pre>
產生一個帶有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/>
<% }
%>
</pre>
產生了一個迭代器,并且將它存入頁面上下文的指定的id(myAtt)屬性中。
例四:
<pre>
帶有converter屬性的generator標簽
<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;
}
};
}
...
}
</pre>
產生的這個迭代器,它的每個元素由提供的轉換器獲得。在這個轉換器中,只是為每個元素增加了“converter-”。
this converter, it simply add "converter-" to each entries.
4)iterator
描述:迭代器將會迭代值。一個可迭代的值可以是java.util.Collection,也可以是java.util.Iterator。
參數:
名稱
|
必選
|
默認值
|
求值
|
類型
|
描述
|
id
|
否
|
|
是
|
String
|
id用來引用元素。對于UI和表單標簽,它與HTML的id標簽相當
|
status
|
否
|
否
|
是
|
Boolean
|
如果該值被指定,一個迭代狀態的實例將會在每一個迭代中被推入堆棧中
|
value
|
否
|
|
是
|
String
|
用來進行迭代的迭代源,否則對象本身將會被放入新的產生的列表中
|
舉例:
下面的例子取回在值棧中的當前對象的getDays()所返回的值,<s:property/>標簽打印出當前迭代器的值,代碼如下:
<s:iterator value="days">
<p>day is: <s:property/></p>
</s:iterator>
在下面的例子中使用Bean標簽并且將它存入ActionContext中。iterator標簽將會從ActionContext中取回對象而后調用它的getDays()方法。狀態屬性常常用來創建IteratorStatus對象,在這個例子中,它的odd()方法用來改變行的顏色。
<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>
下個例子將進一步展示status屬性的使用,使用通過OGNL從action類取得的DAO,成員的迭代以及它們的使用(在安全的上下文中),last()方法中指明了當當前的對象是迭代器的最后一個可用的對象,如果不是,我們需要使用逗號來分隔用戶,代碼如下:
<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>
下一個例子在一個action collection上迭代,并且將每一個迭代的值傳給另一個action。這里的訣竅在于使用”[0]”。它獲得當前的值并且將值傳入edit action。使用”[0]”與使用<s:property/>具有相同的效果(但是,后者,在param標簽內部不起作用)。代碼如下所示:
<s:action name="entries" id="entries"/>
<s:iterator value="#entries.entries" >
<s:property value="name" />
<s:property />
<s:push value="...">
<s:action name="edit" id="edit" >
<s:param name="entry" value="[0]" />
</s:action>
</push>
</s:iterator>
下例使用iterator標簽來模擬一個簡單的循環,循環了5次,代碼如下:
<s:iterator status="stat" value="{1,2,3,4,5}" >
<!—獲得當前的index(從0開始) -->
<s:property value="#stat.index" />
<!— 獲得當前堆棧的值 -->
<!—當前的迭代值(0, 1, ... 5) -->
<s:property value="top" />
</s:iterator>
5)merge
描述:它是MergeIterator標簽的組件,它的工作是合并迭代器和對合并后的迭代器的后續調用,它將使得每一個合并的迭代器有機會展示它的元素,接著下一個調用將會允許下一個迭代器來展示它的元素。一旦最后一個迭代器已展示完它的所有元素,第一個迭代器又能夠開始展示它的元素(除非元素已經用盡)。
從內部來說,任務將委托給MergeIteratorFilter去做。
下面展示了3個列表的合并,其中每個列表有3個元素,步驟如下:
1. 展示第一個列表的第一個元素;
2. 展示第二個列表的第一個元素;
3. 展示第三個列表的第一個元素;
4. 展示第一個列表的第二個元素;
5. 展示第二個列表的第二個元素;
6. 展示第三個列表的第二個元素;
7. 展示第一個列表的第三個元素;
8. 展示第二個列表的第三個元素;
9. 展示第三個列表的第三個元素;
參數:
名稱
|
必選
|
默認值
|
求值
|
類型
|
描述
|
id
|
否
|
|
是
|
String
|
合并后的迭代器的值將會存儲在堆棧上下文的id
|
舉例:
Action類代碼:
public class MergeIteratorTagAction extends ActionSupport {
private List myList1;
private List myList2;
private List myList3;
public List getMyList1() {
return myList1;
}
public List getMyList2() {
return myList2;
}
public List getMyList3() {
return 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";
}
}
jsp頁代碼:
<s:merge id="myMergedIterator1">
<s:param value="%{myList1}" />
<s:param value="%{myList2}" />
<s:param value="%{myList3}" />
</s:merge>
<s:iterator value="%{#myMergedIterator1}">
<s:property />
</s:iterator>
二. UI標簽
三. 主題與模板標簽
四. 標簽引用
五. Ajax標簽
六. 標簽語法
標簽被設計用來顯示動態的數據。為了創建輸入域來顯示屬性“postalCode”,我們需要將“postalCode”傳給textfield標簽。
下面創建了一個動態的輸入域:
<s:textfield name="postalCode"/>
如果在值棧中存在“postalCode”屬性,它的值將會被放入該輸入域中。當輸入被提交到框架之后,它的值將會被放置到“postalCode”屬性中。
有時候,我們想要傳動態的數據到標簽中。例如,我們可能需要用輸入域來顯示一個label,我們可能想要從應用程序的message資源中。相應地,框架將會解析在標簽屬性中的表達式。因此在運行時我們能夠合并動態的數據到標簽的屬性中。表達式是像“%{…}”這樣的。任何一個在其中嵌入的文本被作為表達式來計算。
使用一個表達式來設置label的例子:
<s:textfield key="postalCode.label" name="postalCode"/>
表達式語言(OGNL)使得我們能夠調用方法和計算屬性。getText()方法由ActionSupport(大多數Action的基類)提供。我們可以調用任何一個表達式提供的方法,包括getText方法。
非String型的屬性
HTTP協議是基于文本的,但是有一些標簽時非String類型的,例如bool和int。為了能夠直接使用非String型的屬性,本框架將所有的非String類型的屬性作為一個表達式處理,在這種情況下,你不需要使用任何轉義符(但是,如果你使用了轉義符,框架也會將其跳過)。
計算boolean型的例子:
<s:select key="state.label" name="state" multiple="true"/>
一旦multiple屬性跟一個boolean屬性對應起來,框架不會將它作為一個String來解釋,這個值將會被作為一個表達式來計算并且自動地將其轉換為boolean值。
因為很容易忘記哪個屬性是String,哪個屬性是非String型的,你仍然可以使用轉義符。
計算boolean值(帶有轉義符的):
<s:select key="state.label" name="state" multiple="%{true}"/>
帶有屬性的:
<s:select key="state.label" name="state" multiple="allowMultiple"/>
既帶有轉義符又帶有屬性的:
<s:select key="state.label" name="state" multiple="%{allowMultiple}"/>
值是一個對象
更通常的情況是,屬性值是自動放入的,因為name屬性通常告訴框架哪個屬性來調用方法來set值。但是,如果需要直接設置值,建議那個值是Object型而不是String型。
注意:因為值是非String型的,無論傳入什么,都是將他作為表達式來處理——而不是一個字面的String。
可能導致錯誤的例子:
<s:textfield key="state.label" name="state" value="CA"/>
如果textfield被傳入 “CA”,本框架將會名字為getCa的屬性。通常情況下,這不是我們的本意,我們想要做的是傳送一個字符串。在表達式語言中,文字需要被置為單引號之間。
以正確的方式傳入一個文字值:
<s:textfield key="state.label" name="state" value="%{'CA'}" />
另一種方法是使用value=”’CA’”,但是在這種情況下,推薦使用表達式符號。
標簽屬性使用如下三種規則計算:
1. 所有的String屬性都被解析成“%{…}”符號;
2. 所有的非String屬性沒有被解析,而是直接按照表達式來算;
3. 規則2的異常情況是非String型的屬性使用轉義符號“{%{}”,符號被作為多余的符號被忽略,而只是計算內容。
表示式語言符號
1.在Freemarker、Velocity或者JSTL的表達式語言的JavaBean對象的標準文本
<p>Username: ${user.username}</p>
2.在值棧中的一個username屬性
<s:textfield name="username"/>
3. 引用值棧中的屬性的另一種方式
<s:url id="es" action="Hello">
<s:param name="request_locale">
es
</s:param>
</s:url>
<s:a href="%{es}">Espanol</s:a>
4. 在Session Context中獲得user對象的userName屬性
<s:property name="#session.user.username" />
5. 在一個靜態map中,像("username","trillian")一樣
<s:select label="FooBar" name="foo" list="#{'username':'trillian', 'username':'zaphod'}" />
下一篇:編寫Action
上一篇:HelloWorld篇
posted on 2007-07-29 10:10
阿蜜果 閱讀(16486)
評論(7) 編輯 收藏 所屬分類:
Struts2