parameters |
包含當前HTTP請求參數的Map |
#parameters.id[0]相當于request.getParameter("id") |
</tr>
</tbody>
</table>
</p>
獲取Action中的屬性值或者Action中的對象的某某屬性值
利用<s:property/>標簽可以直接獲取Action中的引用類型user里面的username屬性
同樣可以通過user.address.addr獲取user中引用類型address中的addr屬性的值
像這種一層一層往下傳遞的訪問方式,即所謂的導航,也就是一步步的往下調用
調用Action的對象里面的普通方法
默認的會把Action放到值棧里面,而值棧在訪問的時候,并不需要值棧的名字
當我們調用<s:property value="user.getVOMethod()"/>的時候
它會自動到值棧里面查找Action對象里面有沒有user對象,然后它就發現有user
然后它就再找user里面有沒有getVOMethod()方法,然后它發現有,于是調用getVOMethod()
實際上調用User中的getVOMethod()方法的過程與獲取表單中的姓名密碼的方式都是相同的
都是到值棧里面查找,找是否存在user對象,如果存在,接著查找user中是否存在某某屬性或方法
調用Action中的靜態方法
同樣我們也可以在JSP頁面中寫一個OGNL表達式調用Action中的靜態方法
調用Action中的靜態方法時,與調用user對象的getVOMethod()方法的過程,是截然不同的
此時value的寫法是固定的,以@開頭,后面跟上具體的包名,然后@加上靜態方法
比如<s:property value="@com.jadyer.action.LoginAction@getStatic()"/>
另外user對象是LoginAction中的一個屬性,這個屬性會自動的放到值棧里面
而值棧調用的時候,不用加上@或者包名等等,所以直接user.getVOMethod()就可以了
調用JDK類中的靜態方法
可以使用<s:property value="@@floor(46.58)"/>輸出floor()的執行結果
這就意味著如果不在@@中指定類的話,默認的就表示java.lang.Math類
當前大多數情況下,我們都不會省略這個類,都會寫全了的,然后在后面加上靜態方法
集合的偽屬性
OGNL能夠引用集合的一些特殊的屬性,這些屬性并不是JavaBean模式,例如size()、length()
當表達式引用這些屬性時,OGNL會調用相應的方法,這就是偽屬性
比如獲取List的大小:<s:property value="testList.size"/>
List的偽屬性:size、isEmpty、iterator
Set的偽屬性:size、isEmpty、iterator
Map的偽屬性:size、isEmpty、keys、values
Iterator的偽屬性:next、hasNext
Enumeration偽屬性:next、hasNext、nextElement、hasMoreElements
獲取集合中元素的實質就是調用它的toString()方法
它還可以直接獲取集合中的元素,事實上是在調用集合的toString()方法
所以我們可以根據實際情況通過重寫集合的toString()方法來實現個性化輸出
甚至它還可以像訪問數組那樣,直接testList[2]獲取集合中的元素
但這種方法只適用于List,不適用于Map。因為Map的索引是key,不是數值
另外,由于HashSet中的元素是沒有順序的,所以也不能用下標獲取單個元素
Lambda表達式
補充一下:使用Lambda表達式可以在OGNL中書寫遞歸式子,在幫助中對它有很詳細的說明
打開幫助中的//struts-2.0.14-all//struts-2.0.14//docs//index.html頁面
在左側的Documentation下面點擊Guides鏈接,然后在這個頁面中點擊OGNL
最后跳轉到//struts-2.0.14-all//struts-2.0.14//docs//docs//ognl.html
將這個頁面右側的下拉條拖放到最下面,就會看到它的說明了,它舉的例子如下所示
<s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" />
Lambda表達式的語法是:[...] ,中括號前面有一個冒號,所有東西都在中括號里面寫
也就是說我們只要看到一個冒號跟著一個中括號,就表示這里使用的是Lambda表達式
#this指的是表達式的參數
所以這個例子可以這樣理解:先判斷這個參數是否等于零,如果等于零,那么它的值最后就是零
如果參數不等于零,就再判斷它是否等于壹。如果參數等于壹,那么它的值最后就是壹
如果參數不等于壹,就繼續調用#fib。注意這里已經用中括號將整體的值賦給了fib
實際上很少能夠用得到Lambda表達式
利用投影獲取屬性
利用投影獲取List中對象的username屬性時,其中{}表示的是一個集合
stus.{username}就表示將suts中所有的username屬性取出組成一個新的列表
利用選擇獲取屬性
OGNL表達式是很靈活的,可以同時使用選擇技術與投影技術獲取屬性
使用選擇技術時,#this代表當前元素,問號?是把所有滿足條件的元素都取出來
上箭頭^是開始的意思,所以stus.{^#this.grade>=60}.{username}輸出的是[張三]
注意,此時輸出文本中包含中括號,這表示它是一個列表
而stus.{?#this.grade>=60}.{username}[0]輸出的是張三,是字符串,二者是不同的
美元符號$是結束的意思,所以stus.{$#this.grade>=60}.{username}輸出的是[王五]
這三個符合:問號、上箭頭、美元符所返回的都是List
補充
1..當OGNL取不到值的時候,它不會報錯,而是什么都不顯示
2..<s:property value="[0]"/>返回的是ValueStack中從上至下的所有的Object
<s:property value="[1]"/>返回的是ValueStack中從上至下的第二個Object
3..<s:property value="[0].username"/>返回的是成員變量username的值
假設ValueStack中存在兩個Action的話,如果第一個Action如果沒有username變量
那么它會繼續找第二個Action。那么在什么情況下ValueStack中會存在兩個Action呢
答案是在struts.xml中配置的是從一個Action通過<result type="chain">跳轉到另一個Action
4..<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
在Struts2.1.6中必須設置struts.ognl.allowStaticMethodAccess為true之后
才允許使用OGNL訪問靜態方法。而在Struts2.0.11則無需設置,即可直接訪問
下面是OGNL測試的工程代碼,這是一個Struts2.0.11應用
首先是web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
然后是用于輸入用戶名和密碼等信息的測試頁面login.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<h1>這是測試OGNL使用的登錄頁面</h1>
<h3><font color="red">提示:</font>程序設定的用戶名和密碼各為<font color="blue"><strong>admin</strong></font>和<font color="blue"><strong>jadyer</strong></font></h3>
<h3><font color="red">注意:</font>用戶名和密碼不正確時將停留在頁面不動</h3>
<form action="<%=request.getContextPath()%>/login.action" method="POST">
<%--這里user.username匹配的是LoginAction中的引用類型user里面的username屬性--%>
<%--查看標簽庫說明的話,就知道name中指定的是對象。這里它不是字符串,而是OGNL表達式--%>
姓名:<input type="text" name="user.username"><br>
密碼:<input type="text" name="user.password"><br>
地址:<input type="text" name="user.address.addr"><br>
<input type="submit" value="測試OGNL的輸出">
</form>
然后是用于顯示OGNL處理結果的loginSuc.jsp頁面
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<h1>這是使用OGNL輸出的結果頁面</h1>
<table border="9">
<tr>
<td align="right">獲取姓名屬性:</td>
<td align="left"><s:property value="user.username"/></td>
<%-- 另外還有兩種寫法也是可以正常輸出值棧中對象的普通屬性的 --%>
<%-- <s:property value="user['username']"/> --%>
<%-- <s:property value="user[/"username/"]"/> --%>
<%-- 但是如果寫成下面這種形式的話,就什么都不會輸出了 --%>
<%-- <s:property value="user[username]"/> --%>
</tr>
<tr>
<td align="right">獲取地址屬性:</td>
<td align="left"><s:property value="user.address.addr"/></td>
</tr>
<tr>
<td align="right">調用值棧中的對象的普通方法:</td>
<td align="left"><s:property value="user.getVOMethod()"/></td>
</tr>
<tr>
<td align="right">調用值棧中Action的普通方法:</td>
<td align="left"><s:property value="getCommon()"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">獲取普通類的靜態屬性:</td>
<td align="left"><s:property value="@com.jadyer.vo.Address@TIPS"/></td>
</tr>
<tr>
<td align="right">訪問普通類的構造方法:</td>
<td align="left"><s:property value="new com.jadyer.vo.Student('張小三',22).username"/></td>
</tr>
<tr>
<td align="right">調用Action中的靜態方法:</td>
<td align="left"><s:property value="@com.jadyer.action.LoginAction@getStatic()"/></td>
</tr>
<tr>
<td align="right">調用JDK中的類的靜態方法:</td>
<td align="left"><s:property value="@java.util.Calendar@getInstance().time"/></td>
</tr>
<tr>
<td align="right">調用JDK中的類的靜態方法:</td>
<td align="left"><s:property value="@java.lang.Math@floor(46.58)"/></td>
</tr>
<tr>
<td align="right">調用JDK中的類的靜態方法:</td>
<td align="left"><s:property value="@@floor(46.58)"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">獲取List中的所有元素:</td>
<td align="left"><s:property value="testList"/></td>
</tr>
<tr>
<td align="right">獲取Set中的所有元素:</td>
<td align="left"><s:property value="testSet"/></td>
</tr>
<tr>
<td align="right">獲取Map中的所有元素:</td>
<td align="left"><s:property value="testMap"/></td>
</tr>
<tr>
<td align="right">獲取Map中的某個元素:</td>
<td align="left"><s:property value="testMap['m22']"/></td>
<%-- 另外還有兩種寫法也是可以正常獲取Map中的某個具體元素的 --%>
<%-- <s:property value="testMap.m22"/> --%>
<%-- <s:property value="testMap[/"m22/"]"/> --%>
</tr>
<tr>
<td align="right">獲取Set中的某個元素:</td>
<%-- 由于Set中的元素是無順序的,所以不能使用下標獲取數據,所以這里什么也得不到 --%>
<td align="left"><s:property value="testSet[2]"/></td>
</tr>
<tr>
<td align="right">獲取List中的某個元素:</td>
<td align="left"><s:property value="testList[2]"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">獲取List的大小:</td>
<td align="left"><s:property value="testList.size"/></td>
</tr>
<tr>
<td align="right">獲取Set的大小:</td>
<td align="left"><s:property value="testSet.size"/></td>
</tr>
<tr>
<td align="right">獲取Map的大小:</td>
<td align="left"><s:property value="testMap.size"/></td>
</tr>
<tr>
<td align="right">獲取Map中所有的鍵:</td>
<td align="left"><s:property value="testMap.keys"/></td>
</tr>
<tr>
<td align="right">獲取Map中所有的值:</td>
<td align="left"><s:property value="testMap.values"/></td>
</tr>
<tr>
<td align="right">Lambda計算4的階乘:</td>
<td align="left"><s:property value="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">獲取List中的所有對象:</td>
<td align="left"><s:property value="stus"/></td>
</tr>
<tr>
<td align="right">利用投影獲取List中對象的名字:</td>
<td align="left"><s:property value="stus.{username}"/></td>
</tr>
<tr>
<td align="right">利用投影獲取List中第二個對象的名字:</td>
<%-- 使用<s:property value="stus[1].{username}"/>獲取到的值為:[李四] --%>
<%-- 二者的區別在于:后者比前者多了一個中括號 --%>
<td align="left">
<s:property value="stus.{username}[1]"/>
<s:property value="stus[1].{username}"/>
</td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的所有對象:</td>
<td align="left"><s:property value="stus.{?#this.grade>=60}"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的第一個對象:</td>
<td align="left"><s:property value="stus.{^#this.grade>=60}"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的最后一個對象:</td>
<td align="left"><s:property value="stus.{$#this.grade>=60}"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">利用選擇獲取List中成績及格的所有對象的名字:</td>
<td align="left"><s:property value="stus.{?#this.grade>=60}.{username}"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的第二個對象的名字:</td>
<td align="left"><s:property value="stus.{?#this.grade>=60}.{username}[1]"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的第一個對象的名字:</td>
<td align="left"><s:property value="stus.{^#this.grade>=60}.{username}"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的最后一個對象的名字:</td>
<td align="left"><s:property value="stus.{$#this.grade>=60}.{username}"/></td>
</tr>
<tr>
<td align="right">利用選擇獲取List中成績及格的第一個對象然后求大小:</td>
<td align="left"><s:property value="stus.{^#this.grade>=60}.{username}.size"/></td>
</tr>
</table>
<hr/>
<table border="9">
<tr>
<td align="right">利用OGNL中的#號獲取attr中的屬性:</td>
<td align="left"><s:property value="#attr.BB"/></td>
</tr>
<tr>
<td align="right">利用OGNL中的#號獲取request范圍中的屬性:</td>
<td align="left"><s:property value="#request.req"/></td>
</tr>
<tr>
<td align="right">利用OGNL中的#號獲取session范圍中的屬性:</td>
<td align="left"><s:property value="#session.ses"/></td>
</tr>
<tr>
<td align="right">利用OGNL中的#號獲取Paraments對象的屬性:</td>
<td align="left"><s:property value="#parameters.netname"/></td>
</tr>
<tr>
<td align="right">使用<%=request.getParameter("")%>或者${param.name}獲取鏈接參數值:</td>
<td align="left">
${param.netname}
<%=request.getParameter("netname")%>
</td>
</tr>
<tr>
<td align="right">查看值棧中的信息:</td>
<td align="left"><s:debug/></td>
</tr>
</table>
然后是struts.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="ognl" extends="struts-default">
<action name="login" class="com.jadyer.action.LoginAction">
<result name="input">/login.jsp</result>
<result name="success">/loginSuc.jsp?netname=hongyu</result>
<!--
<result name="success" type="redirect">/loginSuc.jsp?netname=hongyu</result>
<result name="success" type="redirect">/loginSuc.jsp?netname=${user.username}</result>
-->
</action>
</package>
</struts>
接著是用到的三個VO類
package com.jadyer.vo;
public class User {
private String username;
private String password;
private Address address;
/ 三個屬性的setter和getter略 /
public String getVOMethod(){
return "這是User類中的一個普通方法";
}
}
package com.jadyer.vo;
public class Address {
//如果將TIPS設為private的話,loginSuc.jsp中就無法獲取它的屬性值了
//事實上將一個靜態的final屬性設為private是毫無意義的
//因為既然設置成了靜態,那么就是供他人調用的,如果再設成private的話,別的地方根本就無法調用了
//即使OGNL再怎么強大,它也不可能違反Java的規則,所以不要將靜態的屬性設為私有
public static final String TIPS = "玄玉加油!!";
//addr屬性的setter和getter略
private String addr;
}
package com.jadyer.vo;
public class Student {
private String username;
private int grade;
/ 兩個屬性的setter和getter略 /
//只要是重寫一個類的構造方法,就必須要為這個類保留空的構造方法
//因為框架默認的都會去調用無參的空的構造方法
public Student(){};
public Student(String username,int grade){
this.username = username;
this.grade = grade;
}
@Override
public String toString() {
//如果不重寫它的toString()方法的話,默認調用toString()將輸出【類型+@+內存地址的哈希值】
return "{學生姓名:" + username + ",成績:" + grade + "}";
}
}</strong></pre>
最后是用來提供OGNL測試的數據的LoginAction.java
package com.jadyer.action;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import com.jadyer.vo.Student;
import com.jadyer.vo.User;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings({"serial", "unchecked"})
public class LoginAction extends ActionSupport implements RequestAware,SessionAware {
private User user;
private List testList = new ArrayList();
private Set testSet = new HashSet();
private Map testMap = new HashMap();
private List stus = new ArrayList();
/* 以上五個屬性的setter和getter略 */
private Map request;
private Map session;
public void setRequest(Map request) {
this.request = request;
}
public void setSession(Map session) {
this.session = session;
}
public static String getStatic(){
return "這是LoginAction中的一個靜態方法";
}
public String getCommon(){
return "這是LoginAction中的一個普通方法";
}
@Override
public String execute() throws Exception {
if(user.getUsername().trim().equalsIgnoreCase("admin") && user.getPassword().equals("jadyer")){
testList.add("list11");
testList.add("list22");
testList.add("list33");
testList.add("list44");
testList.add("list55");
testSet.add("set11");
testSet.add("set22");
testSet.add("set33");
testSet.add("set22");
testSet.add("set11");
testMap.put("m11", "map11");
testMap.put("m22", "map22");
testMap.put("m33", "map33");
testMap.put("m44", "map44");
testMap.put("m55", "map55");
stus.add(new Student("張三",88));
stus.add(new Student("李四",77));
stus.add(new Student("王五",66));
stus.add(new Student("馬六",55));
request.put("req", "這是通過OGNL中的#號獲取的request屬性范圍的值");
session.put("ses", "這是通過OGNL中的#號獲取的session屬性范圍的值");
request.put("BB", "這是通過OGNL中的#號獲取的request屬性范圍的BB");
session.put("BB", "這是通過OGNL中的#號獲取的session屬性范圍的BB");
return SUCCESS;
}else{
return INPUT;
}
}
}</strong></pre>
轉自:http://blog.csdn.net/jadyer/article/details/6174555
本文由用戶
jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
淺析值棧 ValueStack對象 相當于一個 棧 ,它貫穿整個Action的生命周期, 每個Action類的對象實例都會擁有一個ValueStack對象 當Struts2接收到一個 *.act...
1.OGNL 表達式語言 OGNL 是 Object Graphic Navigation Language (對象圖導航語言)的縮寫,它是一個開源項目。 Struts 2 框架使用 OGNL ...
我們知道Xwork與Web無關性,我們的Action不用去依賴于任何Web容器,不用和那些JavaServlet復雜的請求(Request)、響應(Response)關聯在一起。對請求(Requ...
學習三大框架,對spring中的IoC和DI并不陌生,但是對struts2中的IoC你又知道多少呢! 現將學習過程的一點小結拿來與大家分享! 在struts2的Action中如何取得reques...
sesese色