Struts2标签库和OGNL
學習內容
?Struts 2標簽庫
?OGNL
能力目標
?熟練使用Struts 2常用標簽
?熟練使用OGNL
?
本章簡介
前面我們編寫的案例使用的都是HTML標簽,這些標簽并不能很好的與Struts 2框架結合,Struts 2和Struts 1一樣都自帶了功能強大、成熟完善的標簽庫供我們使用,通過使用這些標簽庫可以大大提高開發效率和代碼的可維護性。
其實Struts 2的標簽庫是建立在OGNL基礎上的,OGNL是一種功能強大的表達式語言,通過簡單的語法即可存取對象的屬性、調用對象的方法、遍歷等功能。
本章將學習OGNL和Struts 2標簽庫,包括數據訪問標簽、控制標簽
核心技能部分
6.1?OGNL
6.1.1?ActionContext
Struts 2中的ActionContext、ValueStack和StackContext對象與OGNL密切相關,理解這三個對象時學習OGNL的前提。
在前面的學習中,我們已經在使用ActionContext、ValueStack和StackContext對象了,這三個對象的作用及其之間的關系如圖6.1.1所示。
圖6.1.1 ActionContext
1.?ActionContext對象
ActionContext(com.opensymphony.xwork.ActionContext)是Action執行時的上下文。我們可以把上下文看作是一個容器,用于存放Action執行時需要使用的對象信息,例如請求的參數(Parameter)、會話(Session)、Servlet上下文(ServletContext)等。在每次請求執行Action之前都會創建新的ActionContext。保存到ActionContext對象中的數據可以通過Struts2標簽和OGNL表達式語言進行訪問。
2.?StackContext對象
StackContext對象是ActionContext上下文中的一個類型為java.utiI.Stack的實例。上面提到的請求參數(Parameter)、會話(Session)、Servlet上下文(ServletContext)等對象,實際上都存儲在ActionContext上下文中的StackContext對象中。
3.?ValueStack對象
Struts2會為每一次Action的請求創建與之對應的ValueStack,并將所有Action屬性數據存儲到ValueStack中,再將ValueStack 暴露給視圖頁面,這樣頁面就可以直接訪問Action中的屬性值。
?
6.1.2?使用OGNL
OGNL即(Object-Graph Navigation Language),是對象圖導航語言的縮寫,它是一個開源項目,工作在視圖層,用來取代頁面中的Java腳本,簡化數據訪問操作。
OGNL是一種比EL功能更強大的表達式語言。通過其簡單一致的表達式語法,可以存取對象的屬性、調用對象的方法、遍歷以及進行類型轉換等功能。Struts 2框架默認使用OGNL作為表達式語言。
1.?訪問上下文中的數據
ActionContext是Struts?2中OGNL的上下文環境,即ActionContext中的數據(實際存儲在StackContext中)都可以通過OGNL來訪問。而ActionContext又包括Request、Session、ValueStack等對象,所以通過OGNL也可以訪問存儲在這些對象中的數據。
ValueStack是OGNL的根,同時由于OGNL上下文中的根對象可以直接訪問,所以通過OGNL訪問ValueStack中的數據時,不需要使用任何特殊的標記,而訪問ActionConext中的其他對象時則需要使用“#”標記。Struts?2中提供了<s:property>標簽來顯示OGNL上下文中的數據,在實際應用中通常分為以下四種情況:
(1)<s:property??value=”uid”/>: Struts2會在ValueStack中查找名為uid的項,并輸出其值。
(2)<s:property ?value=”#uid”/>: Struts2會在StackContext中查找名為uid的項,并輸出其值。
(3)<s:property ?value=”#session.uid”/>: Struts2會在StackContcxt中的Session作用域中查找名為uid的項,并輸出其值。這里的session也可以更換為request和application,以便在Request和Application作用域中查找指定的項。
(4) <s:property ?value =”#attr.uid”/>: Struts2會依次在StackContext的Page、 Request、Session、Application作用域內查找對應的uid中的值。
2.?訪問JavaBean屬性
通過OGNL可以非常方便的訪問JavaBean,假設現在ValueStack中存在StudentAction,該Action的屬性有name、age等。
(1) <s:property value=”name”/>:Struts2會執行StudentAction對象的getName()方法來獲得并輸出name屬性的值
(2) <s:property value=”age”/>:Struts2會執行StudentAction對象的getAge()方法來獲得并輸出age屬性的值
由于ValueStack是OGNL的根,所以此時在使用<s:property>標簽時無需“#”標記。
3. ?執行JavaBean方法
OGNL不僅可以自動執行getter方法,而且能夠執行JavaBean的其他方法。更重要的是,還能夠在執行方法的時候傳入參數,OGNL執行的方法可以是靜態方法和非靜態方法。執行靜態方法的格式為:@類的全類名@方法名(參數)。為了能夠讓OGNL執行靜態方法,還必須在struts.xml配置文件中配置常量參數,才可以開啟OGNL調用靜態方法的功能,配置代碼如下:
<constantname="struts.ognl.allowStaticMethodAccess" value="true" />
示例6.1演示了使用OGNL執行JavaBean方法。
示例6.1
(1)創建JavaBean ,命名為“OgnlInfo.java”。
public class OgnlInfo { //定義靜態方法 public static String sayBye(String name) { return name + "再見!"; } //定義非靜態方法 public String sayHello(String name) { return name + "你好!"; } }(2)創建index.jsp。
?
<body><%//實例化ognl對象OgnlInfo ognlInfo = new OgnlInfo();//將ognlinfo對象存入request作用域內request.setAttribute("ognlInfo",ognlInfo); %><!-- 執行ognl對象非靜態方法 --><s:property value="#request.ognlInfo.sayHello('jack')"/><!-- 執行ognl對象靜態方法 --><s:property value="@com.zzab.entity.OgnlInfo@sayBye('tom')"/></body>4. ??OGNL操作符
OGNL表達式中能使用的操作符基本與Java中的操作符相同,除了能使用+、—、*、/、==、!=、=等操作符之外,還能使用mod(取余)、in、not in等操作符。
5. “%”號
“%”號用于對屬性為字符串類型的OGNL表達式的值進行計算,“%”符號在OGNL中的使用方法如下:
<body>
<%
String value="確定";
pageContext.setAttribute("val", value);
%>
不使用%符號,會按原樣顯示<br>
<s:submit value="#attr.val"/>
<br>
使用%符號,會計算OGNL表達式的值<br>
<s:submit value="%{#attr.val}"/>
</body>
運行結果如圖6.1.2所示。
?
圖6.1.2 %的使用
6. OGNL的集合操作
(1)生成List類型的集合。具體語法為{e1,e2,e3,...}。此語法將直接生成一個list類型集合,該集合包含3個元素:e1,e2,e3。如果需要更多的元素,則多個元素之間以英文逗號隔開。
(2)生成Map類型的集合。具體語法為#{key1,key2,key3...}。此語法將直接生成一個Map類型集合,該Map中每個key-value對象之間以英文冒號隔開,如果需要更多的元素,則多個元素之間以英文逗號隔開。
(3)使用in和not in 運算符。對于集合,OGNL提供元素符in與not in。其中,in用于判斷某個元素是否在指定集合內;not in 則用于判斷某個元素是否不在指定的集合中。In和 not in 的用法如下:
<!-- 判斷java是否在指定集合中-->
<s:if test="'java' in {'java','jsp','html'}">
存在
<s:else>
不存在
</s:else>
</s:if>
(4) ??獲取集合的子集。OGNL允許通過某個規則取得集合的子集,取得子集時有以下三種操作符:
1)“?”操作符:取出所有符合選擇邏輯的元素。
2)“^”操作符:取出符合選擇邏輯的第一個元素。
3)“$”操作符:取出符合選擇邏輯的最后一個元素。
假設現在Session中存在名為StudentList的集合,該集合存儲了多個Student對象。Student類中存在一個age屬性,這三種操作的語法如下:
#session.StudentList.{?#this.age>20}用于取出年齡大于20的子集合。
#session.StudentList.{^#this.age>20}用于取出第一個年齡大于20的Student對象。
#session.StudentList.{$#this.age>20}用于取出最后一個年齡大于20的Student對象。
6.2?Struts 2的標簽庫
Struts 2作為一個優秀的MVC框架,它為開發人員提供了一個功能強大、支持廣泛、高擴展性的標簽庫,完全能滿足Web頁面復雜、多變的需求。
Struts 2的標簽庫大大簡化了視圖頁面的代碼編輯工作,提高了視圖頁面的維護效率。與Struts 1的標簽庫相比,Struts 2的標簽庫不但功能強大,而且更加簡單易用。
在Struts 1的標簽庫中,它分別提供了html、bean、logic等幾個標簽庫。Struts 2標簽庫并沒有嚴格的對標簽進行分類,而是把所有標簽整合到了一個標簽庫中。為了使初學者對Struts 2標簽庫能有更加清晰的認識,我們可以將Struts 2的標簽庫分成三大類(如圖6.1.3所示):
?UI標簽:主要用于生成HTML頁面元素。
?非UI標簽:主要用于邏輯控制、數據訪問等操作。
?Ajax標簽:主要用于支持Ajax訪問。
其中又可以把UI標簽分為如下兩類:
表單標簽:主要用于生成HTML中的表單元素。
?非表單標簽:主要包含一些常用的功能標簽,例如顯示日期或樹形菜單。
對于非UI標簽,也可以再細分為如下兩類:
?數據訪問標簽:主要用于獲得或輸出ValueStack中的值。
?邏輯控制標簽:主要用于數據訪問中的條件分支、循環等流程控制。
圖6.1.3 標簽庫分類
使用Struts2標簽庫之前,也需要在JSP頁面中導入。現在的Web應用一般都使用Servlet 2.4以上的規范,因此我們就無須在web.xml文件中對標簽庫進行配置,因為Servlet 2.4以上的規范可以直接讀取標簽庫定義文件(TLD文件),在JSP頁面中直接通過下面一行代碼就可以導入Struts 2標簽庫。
<%@ taglib prefix="s" uri="/struts-tags" %>
?
6.2.1?數據訪問標簽
數據訪問標簽主要用來獲得或輸出各種數據的功能,常應用于顯示Action中的屬性以及國際化輸出等場合。常見的數據標簽主要包含以下幾個:
?action標簽:該標簽用于在JSP頁面中直接調用一個Action 。
include標簽:該標簽用于在JSP頁面中包含其他頁面資源。
?param標簽:該標簽用于設置一個參數,通常用作bean、url標簽的子標簽。
?property標簽:該標簽用于輸出某個值。
?set標簽:該標簽用于設置一個新變量。
?text標簽:該標簽用于輸出國際化消息。
?url標簽:該標簽用于生成一個URL地址。
?date標簽:該標簽用于格式化輸出一個日期。
1.?action標簽
該標簽可以在JSP頁面中直接調用Action,并可以把執行的結果包含在標簽的位置,這時需要指定Action的name和namespace等屬性。下面是該標簽的幾個主要屬性:
?id屬性:該屬性用來指定被調用的Action的引用ID。
?name屬性:該屬性用來指定被調用的Action的名字。
?namespace屬性:該屬性用來指定被調用的Action所在的namespace。
?executeResult屬性:該屬性用來指定是否將Action的處理結果包含到當前頁面中,該
屬性的默認值是false,即不包含。
示例6.2
下面我們通過一個實例來介紹action標簽的具體應用,首先編寫一個簡單的Action類,代碼如下所示。
public class TagAction
{
private String name;
//省略getter和setter方法
public String exec()
{
return "ok";
}
}
通過上述代碼可以看到該Action只包含了一個exec業務方法。下面是該Action在struts.xml文件中的配置:
<struts><package name="struts2_Tags" extends="struts-default"namespace="/tags"> <action name="tag1" class="com.zy.TagAction" method="exec"> <result name="ok">succ.jsp</result> </action></package> </struts>下面是succ.jsp視圖文件的代碼:
<body>
<br>
調用Action!!
</body>
下面是使用action標簽的s-action_Tag.jsp文件,代碼如下所示:
<body>
下面調用Action,并將結果包含到本頁面中。<br>
<s:action name="tag1" executeResult="true" namespace="/tags"/>
</body>
上述代碼使用<s:action />標簽調用了名字為tag1的邏輯action,并通過設置executeResult屬性為true將結果包含到了本頁面中。
?
圖6.1.4 ?action標簽的應用
2.?property標簽
該標簽的作用就是輸出ActionContext中對象的值或者Action、JavaBean的屬性值,通常結合OGNL使用。該標簽有如下幾個屬性:
??value,該屬性用來指定要輸出的屬性或OGNL表達式。
??default,該屬性用來指定當value指定的屬性值為null時輸出的值。
??escape,該屬性用來指定是否生成HTML代碼,默認為true,表示在瀏覽器上輸出表達式的值;如果為false,則把表達式的值作為HTML代碼嵌入。
示例6.3
下面是應用property標簽的簡單示例。
<body>
????<%
???? String url="<a href='index.jsp'>超鏈接</a>";
???? pageContext.setAttribute("su",url);
?????%>
?????<s:property value="#attr.su"/><hr>
?????<s:property value="#attr.su" escape="false"/><hr>
?????<s:property value="#attr.uid" default="找不到uid"/>
</body>
運行效果如圖6.1.5所示。
?
圖6.1.5 property標簽
3.?include標簽
該標簽用來將一個JSP或Servlet等資源包含到當前頁面中,使用起來非常簡單。該標簽主要包含value屬性,用來指定被包含的JSP或Servlet等資源文件。
示例6.4
接下來通過一個簡單的例子來介紹include標簽的具體應用,首先是被包含的include-file.jsp頁面的代碼:
<%@ page contentType="text/html; charset=GBK" language="java"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> </head> <body> --------------------------- <h3>這是被包含的頁面</h3> </body> </html> 下面是包含include-file.jsp這個頁面的s-include_Tag.jsp文件,代碼如下所示: <%@ page contentType="text/html; charset=utf-8" language="java"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>使用include標簽來包含目標頁面</title> </head> <body> <h2>使用include標簽來包含目標頁面</h2> <s:include value="include-file.jsp"/> </body> </html>上述代碼通過使用include標簽包含了include-file.jsp頁面,運行效果如圖6.1.6所示。
?
圖6.1.6 include標簽
4.?set標簽
該標簽用來定義一個變量,并把這個變量放到指定的范圍內,例如application范圍、session范圍等。該標簽有以下一些常用屬性:
??id屬性:該屬性用來定義變量的名字。
??scope屬性:該屬性用來定義變量被放置的范圍,可選的值有application、session、request、response、page和StackContext。
??value屬性:該屬性用來定義將要賦給變量的固定值或者另一個已經定義的變量。
示例6.5
下面我們通過一個示例來介紹set標簽的具體應用,首先我們定義一個變量p,并把“小樣兒”這個字符串賦值給它,然后定義另一個變量user,并把p賦值給user。代碼如下所示:
<body>
<h2>使用set標簽設置一個新變量</h2>
<s:set id="p" value="'小樣兒'"/>
<s:property value="#attr.p"/><br>
將p變量賦值給user變量并放入session范圍內<br>
<s:set value="#p" id="user" scope="session"/>
<s:property value="#session.user"/><br>
</body>
運行效果如圖6.1.7所示。
?
圖6.1.7 set標簽的應用
5.?url標簽
該標簽用來生成一個URL地址,我們也可以通過嵌套param標簽來為URL指定發送參數。該標簽主要有以下一些常用屬性:
??includeParams屬性:該屬性用來指定是否在生成的URL參數中追加本頁面接收到的請求參數,有3個值可供選擇,none, get和all,分別代表“不包含”、“包含get方法傳遞的參數”和“所有的參數”。
??value屬性:該屬性用來指定要生成的URL的地址值。
??action屬性:該屬性用來指定一個Action作為URL地址值。
??namespace屬性:該屬性用來指定命名空間。
??method屬性:該屬性用來指定調用Action的方法名。
??includeContext屬性:該屬性用來指定是否把當前上下文包含在URL地址值中。
在上述屬性中,action和value屬性只需指定其一即可,如果兩個都未指定,就以當前頁面作為URL地址值。下面是一個應用URL標簽的示例。
示例6.6
<body> <h3>使用url標簽</h3> <hr> 指定action屬性,且使用param標簽傳入參數。<br> <s:url action="showPerson"><s:param name="name" value="'Jack'" /> </s:url> <hr> 指定value屬性,且使用param標簽傳入參數。<br> <s:url value="http://localhost:8080/firstStruts2/news.jsp"><s:param name="name" value="'Jack'" /> </s:url> </body>該頁面的運行效果如圖6.1.8所示。
?
圖6.1.8 URL標簽的應用
6.?date標簽
date標簽用來按指定的格式輸出一個日期,還可以計算指定日期到當前時間的時差。該標簽主要有如下一些屬性:
??format屬性:該屬性用來指定日期輸出的格式,例如“yyyy-MM-dd”。
??name屬性:該屬性用來指定要被格式化輸出的日期值。
示例6.7
我們看下面的實例代碼,用“年/月/日”的完整格式顯示當前日期:
<body> <h3>date標簽的使用</h3> <% java.util.Date now = new java.util.Date(); pageContext.setAttribute("now" , now); %> <s:date name="#attr.now" format="yyyy/MM/dd" nice="false"/><hr><br> </body>該頁面的運行效果如圖6.1.9所示。
?
圖6.1.9 date標簽的使用
7. <s:bean>標簽
<s:bean>用來創建JavaBean實例,創建JavaBean實例的時候,可以在該標簽內部使用<param/>標簽為該JavaBean實例傳入屬性。其常見屬性如下:
??Id:指定創建JavaBean的引用id.
??name:指定需要實例化的JavaBean的實現類
<s:bean>標簽用法的如下:
(1)?創建JavaBean,命名為Book.java。
public class Book { private String isbn; private String name; private double price; public Book() { super(); } public Book(String isbn, String name, double price) { super(); this.isbn = isbn; this.name = name; this.price = price; } public String[] getAllBooks() { String[] books = {"JAVA","JSP","ASP.NET","C#"}; return books; } }(2) 創建Jsp頁面.
<!-- 實例化book JavaBean對象,并存儲到StackContext中 -->
<s:bean id="book" name="com.zzab.entity.Book">
<s:param name="isbn" value="'621345'"/>
<s:param name="name" value="'HTML'"/>
</s:bean>
<!--?輸出bean對象的值?-->
book對象屬性值:<br>
isbn:<s:property value="#book.isbn"/><br/>
name:<s:property value="#book.name"/><br/>
調用book對象的getAllBooks方法獲取全部書籍列表:<br/>
<c:forEach var="book" items="${book.allBooks}">
<div>${book }</div>
</c:forEach>
<s:bean id="book" name="com.zzab.entity.Book"> <s:param name="isbn" value="'621345'"/> <s:param name="name" value="'HTML'"/> </s:bean> <!-- 輸出bean對象的值 --> book對象屬性值:<br> isbn:<s:property value="#book.isbn"/><br/> name:<s:property value="#book.name"/><br/> 調用book對象的getAllBooks方法獲取全部書籍列表:<br/> <c:forEach var="book" items="${book.allBooks}"> <div>${book }</div> </c:forEach>
6.2.2?邏輯控制標簽
Struts 2的邏輯控制標簽主要用于程序流程的邏輯控制,例如選擇、分支、循環等操作,常見的邏輯控制標簽主要有以下五個標簽:
??if標簽:用于控制選擇流程的標簽。
??elseif標簽:與if標簽結合使用。
??else標簽:與if標簽結合使用。
??generator標簽,用于將一個字符串解析成一個集合。
??iterator標簽:這是一個迭代器,用于將集合進行循環輸出。
?
1.?if/elseif/else標簽
if/elseif/else這三個標簽通常結合使用,都是用于進行程序分支邏輯控制,跟多數編程語言中的if/elseif/else語句的功能相似,test屬性用來設置比較表達式,具體語法如下所示:
<s:if test="表達式">
標簽體
<s:elseif test="表達式">
標簽體
<s:else>
標簽體
</s:else>
下面是一個實例的代碼片段:
示例6.8
<s:set name="dengji" value="85"/> <s:if test="#dengji>=90">成績優秀 </s:if> <s:elseif test="#dengji>=80">成績良好 </s:elseif> <s:elseif test="#dengji>=60"> 成績合格 </s:elseif> <s:else>成績不合格 </s:else>上述代碼先通過set標簽定義了一個名為dengji的屬性并賦值為85,然后通過if/elseif/else標簽根據dengji屬性的值的范圍來控制輸出成績的評價是“優秀”、“良好”、“合格”或“不合格”。運行效果如圖6.1.10所示。
?
圖6.1.10 if/elseif/else標簽的應用
?
2.?iterator標簽
該標簽主要用于對集合類型的變量進行迭代輸出,這里的集合類型包括List、Set、數組和Map等。該標簽主要有三個屬性:
??value屬性:該屬性用來指定被迭代輸出的集合,被迭代的集合可以由OGNL表達式指
定也可以通過Action返回一個集合類型的變量。
??id屬性:該屬性用來指定集合中元素的ID屬性。
??status屬性:該屬性可以實現一些附加功能,詳見后面講解。
下面是一個實例的代碼片段:
示例6.9
<h3>iterator的用法</h3>
?<%
? List bookList=new ArrayList();
? bookList.add("Spring3.0技術寶典");
? bookList.add("Struts2權威指南");
? bookList.add("JavaScript技術大全");
? bookList.add("JSP技術詳解");
? bookList.add("Ajax實戰");
? pageContext.setAttribute("bookList",bookList);
??%>
?<s:iterator value="#attr.bookList" id="bookname">
?<li><s:property value="bookname" /></li>
?</s:iterator>
上述代碼通過iterator標簽的value屬性指定了一個集合,并指定它的id屬性為bookname,然后就可以通過<s:property value="bookname" />輸出集合中每個元素的值。該頁面的運行效果如圖6.1.11所示。
?
圖6.1.11 iterator標簽的應用
iterator標簽的status屬性很有用,利用它可以實現一些很實用的功能。指定該屬性后,每次迭代都會以此屬性為名稱創建一個IteratorStatus的實例對象,該實例對象包含了以下幾個屬性:
??count:返回當前迭代了幾個元素。
??index:返回當前迭代元素在集合中的索引值。
??even:返回當前迭代元素的索引值是否為偶數。
??odd:返回當前迭代元素的索引值是否為奇數。
??first:返回當前迭代元素是否是第一個元素。
??last:返回當前迭代元素是否是最后一個元素。
我們看下面的代碼片段:
<table border="1" width="200">
?<s:iterator value="#attr.bookList" id="name" status="st">
<tr <s:if test="#st.odd">style="background-color:#bbbbbb"</s:if>>
<td><s:property value="#st.index"/></td>
<td><s:property value="name"/></td>
</tr>
?</s:iterator>
</table>
上述代碼以表格的形式輸出了集合中的每個元素和元素的索引值,并通過iterator標簽的status屬性控制奇數行的背景色,運行效果如圖6.1.12所示。
?
圖6.1.12 status屬性的應用
?
?
3.?generator標簽
?
該標簽可以將一個字符串按指定的分隔符分隔成多個子串,新生成的多個子串可以使用iterator標簽進行迭代輸出。generator標簽常見的屬性如下:
??count屬性:該屬性用來指定所生成集合中元素的總數。
??separator屬性:該屬性用來指定分隔符。
??converter屬性:該屬性指定了一個轉換器,該轉換器負責將集合中的每個字符串轉換成
對象。
??id屬性:如果指定了該屬性,則新生成的集合會以此為名稱,被放在pageContext中。
我們來看下面的代碼片段:
示例6.10
<s:generator val="'Spring技術寶典,Ajax實戰,Struts2權威指南,JSP技術詳解,
JavaScript技術大全'" separator="," id="generList"/>
<table border="1" width="320">
<caption>迭代輸出由generator標簽產生的集合</caption>
?<s:iterator value="#attr.generList" id="name" status="st">
<tr>
<td><s:property value="#st.index"/></td>
<td><s:property value="name"/></td>
</tr>
?</s:iterator>
</table>
上述代碼使用generator標簽把一個字符串按逗號進行了分割,并把產生的集合按照指定的“generList”為id保存在pageContext中,接下來使用iterator標簽迭代輸出generList集合中的元素,運行效果如圖6.1.13所示。
?
圖6.1.13 generator標簽的應用
?
?
本章總結
??ActionContext對象。ActionContext(com.opensymphony.xwork.ActionContext)是Action執行時的上下文。我們可以把上下文看作是一個容器,用于存放Action執行時需要使用的對象信息。
??StackContext對象。請求參數(Parameter)、會話(Session)、Servlet上下文(ServletContext)等對象,實際上都存儲在ActionContext上下文中的StackContext對象中。
??ValueStack對象。Struts2會為每一次Action的請求創建與之對應的ValueStack,并將所有Action屬性數據存儲到ValueStack中,再將ValueStack 暴露給視圖頁面,這樣頁面就可以直接訪問Action中的屬性值。
??OGNL即(Object-Graph Navigation Language),是對象圖導航語言的縮寫,它是一個開源項目,工作在視圖層,用來取代頁面中的Java腳本,簡化數據訪問操作。
(1)訪問上下文中的數據。ValueStack是OGNL的根,同時由于OGNL上下文中的根對象可以直接訪問,所以通過OGNL訪問ValueStack中的數據時,不需要使用任何特殊的標記,而訪問ActionConext中的其他對象時則需要使用“#”標記。
(2)執行JavaBean方法。OGNL不僅可以自動執行getter方法,而且能夠執行JavaBean的其他方法。更重要的是,還能夠在執行方法的時候傳入參數,OGNL執行的方法可以是靜態方法和非靜態方法。
??Struts 2的標簽庫
(1)Struts2標簽庫的分類。我們可以將Struts 2的標簽庫分成三大類:UI、非UI、ajax標簽,其中UI標簽又可分為表單 、非表單標簽,非UI標簽可分為數據訪問、邏輯控制標簽。
(2)數據訪問標簽。常見的數據標簽主要包含action、include、param 、property、set、text、url、date等。
(3)邏輯控制標簽。邏輯控制標簽主要用于程序流程的邏輯控制,例如選擇、分支、循環等操作,常見的邏輯控制標簽主要有五個標簽:if 、elseif、 else 、generator 、iterator。
任務實訓部分
1:查詢管理員
訓練技能點
??OGNL
??property標簽
??iterator標簽
??需求說明
在前面章節的任務實訓部分,我們實現了管理員的增、刪、改、查等功能,現在要求在查詢管理員時,使用OGNL和iterator、property等標簽顯示查詢到的管理員列表,并且只顯示密碼長度小于3的管理員信息。
??關鍵代碼
<s:iterator value="#attr.adminList.{?#this.pwd.length()>3}" id="admin">
?? <tr>
???? <td align="center"><s:property value="id"/></td>
???? <td align="center"><s:property value="name"/></td>
???? <td align="center"><s:property value="pwd"/></td>
?? </tr>
</s:iterator>
2:查詢圖書
訓練技能點
??OGNL
??property標簽
??iterator標簽
??需求說明
在前面章節的任務實訓部分,我們實現了查詢圖書的案例,現在要求使用OGNL和iterator、property等標簽顯示查詢到的圖書列表,并且設置偶數行的背景色為灰色。
3:查找客戶信息
訓練技能點
??OGNL
??數據訪問標簽
??控制標簽
??需求說明
實現輸入客戶編號時,查找對應的客戶是否存在,若不存在,則輸出無法查找到此客戶的提示;若存在,則進一步顯示客戶的訂單信息。
?
?
??實現思路
(1)?創建用于描述訂單的實體類,命名為Order.java。
?
public class Order implements Serializable{
//訂單Id
private String orderId;
//訂單日期
private Date orderDtm;
//訂單狀態 0:禁用 1:啟用
private int state;
//無參構造函數
public Order() {
super();
// TODO Auto-generated constructor stub
}
//有參構造函數
public Order(String orderId, Date orderDtm, int state) {
super();
this.orderId = orderId;
this.orderDtm = orderDtm;
this.state = state;
}
//getter setter省略......
}
(2)?創建用于描述客戶的實體類,命名為Cust.java。
public class Cust implements Serializable{
//客戶編號
private String custId;
//客戶名稱
private String custName;
//電話
private String tel;
//訂單集合
private List<Order> orders = new ArrayList<Order>();
//無參構造函數
public Cust() {
super();
// TODO Auto-generated constructor stub
}
//有參構造函數
public Cust(String custId, String custName, String tel) {
super();
this.custId = custId;
this.custName = custName;
this.tel = tel;
}
//getter setter省略......
}
(3)?創建用于處理業務邏輯的JavaBean,命名為CustService.java。
public class CustService {
//定義客戶列表
private static List<Cust> custList = new ArrayList<Cust>();
//靜態構造器,初始化客戶和訂單信息
static{
try {
//用于格式化日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//創建客戶c1
Cust c1 = new Cust("c001", "張三", "110");
Order c1Order1 ?= new Order("OR001", sdf.parse("2012-01-01"), 0);
Order c1Order2 ?= new Order("OR002", sdf.parse("2012-01-02"), 0);
Order c1Order3 ?= new Order("OR003", sdf.parse("2012-01-03"), 1);
//添加訂單到c1客戶
c1.getOrders().add(c1Order1);
c1.getOrders().add(c1Order2);
c1.getOrders().add(c1Order3);
//創建客戶c2
Cust c2 = new Cust("c002", "李四", "114");
Order c2Order1 ?= new Order("OR004", sdf.parse("2012-01-04"), 0);
Order c2Order2 ?= new Order("OR005", sdf.parse("2012-01-05"), 0);
Order c2Order3 ?= new Order("OR006", sdf.parse("2012-01-06"), 1);
//添加訂單到c2客戶
c2.getOrders().add(c2Order1);
c2.getOrders().add(c2Order2);
c2.getOrders().add(c2Order3);
//創建客戶c3
Cust c3 = new Cust("c003", "王五", "119");
Order c3Order1 ?= new Order("OR007", sdf.parse("2012-01-07"), 0);
Order c3Order2 ?= new Order("OR008", sdf.parse("2012-01-08"), 0);
Order c3Order3 ?= new Order("OR009", sdf.parse("2012-01-09"), 1);
//添加訂單到c3客戶
c3.getOrders().add(c3Order1);
c3.getOrders().add(c3Order2);
c3.getOrders().add(c3Order3);
//把客戶添加到List列表中
custList.add(c1);
custList.add(c2);
custList.add(c3);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//
public static Cust findCustById(String custId){
//循環每個客戶
for (Cust cust : custList) {
//循環每個客戶
if(cust.getCustId().equals(custId)){
return cust;
}
}
//如果找不到則返回空
return null;
}
//
public static List<Order> getCustOrders(String custId){
//循環每個客戶
for (Cust cust : custList) {
//循環每個客戶
if(cust.getCustId().equals(custId)){
//返回對應客戶的訂單
return cust.getOrders();
}
}
//如果找不到則返回空
return null;
}
}
(4)?創建用于處理業務邏輯的控制器Action,命名為CustAction.java。
public class CustAction extends ActionSupport {
//封裝用戶的id
private String custId;
//查找訂單
public String findOrder()throws Exception{
//調用業務層
List<Order> orderList = CustService.getCustOrders(custId);
//將訂單放到request中
ServletActionContext.getRequest().setAttribute("orderList", orderList);
//返回input邏輯視圖
return SUCCESS;
}
/**
?* @return
?*/
public String findCust() {
// TODO Auto-generated method stub
//調用業務邏輯
Cust cust = CustService.findCustById(custId);
if(cust!=null){
//將cust存儲到session中
ServletActionContext.getRequest().getSession().setAttribute("cust", cust);
}
else{
//否則給msg賦值,準備彈出對話框。
ServletActionContext.getRequest().setAttribute("msg","<script>alert('沒有此用戶');</script>");
}
//返回input邏輯視圖
return SUCCESS;
}
//getter setter方法
public String getCustId() {
return custId;
}
public void setCustId(String custId) {
this.custId = custId;
}
}
(5)?創建Jsp頁面,命名為jd1.jsp。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
??<head>
???
????<title>My JSP 'jd1.jsp' starting page</title>
????
??</head>
??
??<body>
??? <h2>
??? <form action="custaction!findCust.action" method="post">
??? 完成客戶查找功能:<hr>
??? 客戶編號:<input type="text" name="custId"> <br/>
??? <input type="submit" value="查找">
??? <!-- 如果找到該用戶 -->
??? <s:if test="#session.cust">
??? <hr/>
??? 編號:${cust.custId}<br/>
??? 姓名:${cust.custName}<br/>
??? 聯系方式:${cust.tel}<br/><a href="custaction!findOrder.action?custId=${cust.custId }">查看訂單</a>
??? <hr/>
??? </s:if>
??? <!-- 如果存在訂單列表 -->
??? <s:if test="#request.orderList">
??? <hr/>
??? <table border="1">
??? <tr>
??? <td>訂單編號</td>
??? <td>訂單日期</td>
??? <td>訂單狀態</td>
??? </tr>
??? <s:iterator id="row" value="#request.orderList">
??? <tr>
??? <td>${row.orderId }</td>
??? <td><s:date name="#row.orderDtm" format="yyyy年MM月dd日"/></td>
??? <td>${row.state==0?"禁用":"啟用" }</td>
???
??? </tr>
??? </s:iterator>
??? </table>
???
??? </s:if>
??? </form>
???
??? </h2>
??? <!-- 執行msg -->
??? ${msg }
??</body>
</html>
(6)?配置Struts.xml文件。
<struts>
<!-- 配置字符集 -->
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<!-- 配置主題 -->
<constant name="struts.ui.theme" value="simple"></constant>
<package name="test" extends="struts-default">
<action name="custaction" class="com.zzzy.web.CustAction">
<result >/jd1.jsp</result>
</action>
</package>
</struts>
(7)?運行jd1.jsp頁面,效果如圖6.2.1所示。
?
圖6.2.1 運行jd1.jsp
在圖6.2.1中輸入需要查找的客戶編號。
若編號不存在,系統將會顯示提示消息。 如圖6.2.2所示。
?
圖6.2.2 用戶不存在
若編號存在,系統將顯示該客戶對應的詳細信息,如圖圖6.2.3所示。
?
圖6.2.3 查找客戶并顯示詳細信息
在圖6.2.3中單擊“查看訂單”按鈕,系統將顯示客戶對應的訂單信息,如圖6.2.4所示。
?
圖6.2.4顯示客戶的訂單信息
鞏固練習
一、選擇題
1. 以下關于OGNL的說法正確的是()。
A.?ActionContext是OGNL的上下文環境
B.?ValueStack是OGNL的根
C.?StackContext是OGNL的上下文環境
D.?ActionContext是OGNL的根
2. 假設session中存在名為uid的屬性,通過OGNL訪問該屬性的代碼是()。
A.?#uid
E.?uid
F.?#session.uid
G.?${session.uid}
3. 關于“#session.users.{?#this.age>20}”的OGNL代碼所表示的意思是()。
A.?從users集合中取出第一個年齡大于20的對象
H.?從users集合中取出所有年齡大于20的對象
I.?從users集合中取出最后一個年齡大于20的對象
J.?該代碼有語法錯誤
4. 假設頁面中存在這樣一行代碼“<s:property />”,則下面說法正確的是()。
A.?編譯錯誤
K.?頁面不顯示任何內容
L.?輸出ValueStack中最上面的對象
M.?以上說法都不正確
5. 以下()不屬于Struts 2的數據訪問標簽。
A.?set
B.?date
C.?text
D.?textfield?
總結
以上是生活随笔為你收集整理的Struts2标签库和OGNL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts 2配置详解
- 下一篇: Struts2 表单和非表单标签