OGNL表達(dá)相當(dāng)于JSP+Servlet模式中JSTL的地位,但是它的功能要比JSTL強(qiáng)大,在學(xué)習(xí)OGNL表達(dá)式時(shí),你需要忘掉JSTL.
OGNL能夠訪問系統(tǒng)中OgnlContext中的對(duì)象, OgnlContext對(duì)象是OGNL表達(dá)式的下上文對(duì)象,即所有通過OGNL表達(dá)式取出的數(shù)據(jù)都是從上下文對(duì)象取出來(lái)的, OGNL的上下文環(huán)境是一個(gè)Map結(jié)構(gòu),稱之為OgnlContext。
OgnlContext中包括以下幾個(gè)內(nèi)置對(duì)象
ValueStack:
存放在OgnlContext的第一位,是根對(duì)象,訪問這里面的內(nèi)容有點(diǎn)特殊,不用指定范圍, Struts2框架總是把Action實(shí)例放在棧頂。因?yàn)锳ction在值棧中,而值棧又是OGNL中的根,所以引用Action的屬性可以省略“#”標(biāo)記,這也是為什么我們?cè)诮Y(jié)果頁(yè)面中可以直接訪問Action的屬性的原因。
request:
模擬了HttpServletRequest對(duì)象,取這里面的值就相當(dāng)于調(diào)用了request.getAttribute(“key”),訪問這里面的屬性形式: #request['user']或#request.user
session:
模擬了HttpServletSession對(duì)象,取這里面的值就相當(dāng)于調(diào)用了session.getAttribute(“key”),
訪問這里面的屬性形式: #session['user']或#session.user
application:
模擬了HttpServletApplication對(duì)象,取這里面的值就相當(dāng)于調(diào)用了servletContext.getAttribute(“key”),訪問這里面的屬性形式: #application['user']或#application.user
attr:
如果PageContext可用,則訪問PageContext,否則依次搜索request、session和application對(duì)象。訪問形式: #attr['user']或#attr.user
parameters:
用于訪問請(qǐng)求參數(shù),相當(dāng)于調(diào)用了HttpServletRequest對(duì)象的getParameter()方法。也相當(dāng)于JSTL中的 ${ param.id },訪問形式: :#parameters['id']或#parameters.id
記住一點(diǎn),不要和EL表達(dá)式混用,如果你用了EL表達(dá)式,就全用EL表達(dá)式,如果用了OGNL,就全用OGNL.
按道理來(lái)說(shuō),EL表達(dá)式只能訪問request/session/page/application中的數(shù)據(jù),但是我們現(xiàn)在又說(shuō)了,Action中的屬性值都是放在ValueStack中的,那為什么我們?cè)谙惹暗氖纠?EL表達(dá)式能夠訪問ValueStack中的數(shù)據(jù)呢?
原因是:Struts2對(duì)request對(duì)象進(jìn)行裝飾,所用的類是org.apache.struts2.dispatcher.StrutsRequestWrapper
查看該類源碼,發(fā)現(xiàn)它重寫了getAttribute()方法:
通過查看源代碼我們找到了原因:
會(huì)先前reuqest中查找屬性值:
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);
如果沒有找到,再?gòu)?ValueStack中查找
if (attribute == null) {
….
attribute = stack.findValue(s); //從ValueStack查找
….
}
這里就說(shuō)明了為什么Struts2中EL表達(dá)式能夠取出Action中的值了,但是一定要記住Action中的值是存儲(chǔ)在ValueStack中的
首先我們來(lái)看看怎么用OGNL表達(dá)式取值
取ValueStack中的值
Action中:
public String method1(){
setMessage("取ValueStack中的值");
return "method1";
}
JSP頁(yè)面:
<s:property value="message"/>
XML配置:
<action name="method1" class="chapter10.action.Chapter10Action" method="method1">
<result name="method1">/WEB-INF/JspPage/chapter10/success.jsp</result>
</action>
取request其它對(duì)象中的值
Action:
public String method1(){
request.setAttribute("message", "request中的值");
session.put("message", "session中的值");
request.getSession().getServletContext().setAttribute("message", "ServletContext中的值");
return "method1";
}
JSP頁(yè)面:
<s:property value="#request.message"/> | <s:property value="#request['message']"/><br />
<s:property value="#session.message"/> | <s:property value="#session['message']"/><br />
<s:property value="#application.message"/> | <s:property value="#application['message']"/><br />
<s:property value="#attr.message"/>
可以看到attr對(duì)象是用來(lái)取值用的,它取出的值是順著pagerequestsessionapplication
取parameters中的值
Action
public String method1() {
setMessage("parameters");
return "method1";
}
XML:
<action name="method1" class="chapter10.action.Chapter10Action" method="method1">
<result name="method1" type="redirect">/success.jsp?message=${message}</result>
</action>
JSP:
<s:property value="#parameters.message"/> | <s:property value="#parameters['message']"/><br />
注意type="redirect"時(shí),JSP頁(yè)面不能放在web-inf下
訪問Action的中的方法
在Action中增加一個(gè)方法
public String test() {
return "Action Method";
}
JSP頁(yè)面:
<s:property value="test()" /><br />
XML:
<action name="method1" class="chapter10.action.Chapter10Action" method="method1">
<result name="method1">/WEB-INF/JspPage/chapter10/success.jsp</result>
</action>
訪問Action中屬性的方法
增加一個(gè)User Model
public class User {
private String userName;
public User() {
super();
}
public User(String userName) {
super();
this.userName = userName;
}
@Override
public String toString() {
return "姓名:" + getUserName();
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
修改Action,增加一個(gè)構(gòu)造:
public Chapter10Action() {
user = new User("wdpc");
}
public String method1() {
return "method1";
}
XML
<action name="method1" class="chapter10.action.Chapter10Action" method="method1">
<result name="method1">/WEB-INF/JspPage/chapter10/success.jsp</result>
</action>
JSP
<s:property value="user.toString()" /><br />
訪問屬性的內(nèi)置方法
Action:
public String method1() {
setMessage("調(diào)用字符串的length方法");
return "method1";
}
JSP:
<s:property value="message" />的長(zhǎng)度是:<s:property value="message.length()" />
OGNL表達(dá)式訪問靜態(tài)屬性和方法
首先加入一個(gè)開關(guān)
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
修改Model,添加一個(gè)靜態(tài)方法,一個(gè)靜態(tài)常量
public static final String CLASSNAME= "wdpc0801";
public static String staticMethod() {
return "Static Method";
}
JSP:
訪問靜態(tài)方法:
<s:property value="@chapter10.model.User@staticMethod()" />
<br />
訪問靜態(tài)屬性或常量:
<s:property value="@chapter10.model.User@CLASSNAME" />
<br />
訪問靜態(tài)方法(默認(rèn)為Math類):@@floor(1.32342):
<s:property value="@@floor(1.32342)" />
<br />
訪問System類的靜態(tài)currentTimeMillis()方法:
<s:property value="@java.lang.System@currentTimeMillis()" />
<br />
就算訪問lang包下面類的靜態(tài)方法都得帶包名,除了Math類可以@@floor這樣用,其它的類都得帶包名.
訪問Model類的構(gòu)造方法
<s:property value="new chapter10.model.User('ZHD')" />
它會(huì)自動(dòng)調(diào)用toString()方法來(lái)顯示model的信息,所以model中最好重寫toString()方法
使用OGNL表達(dá)式訪問集合
修改model:
public class User {
private String userName;
public static final String CLASSNAME = "wdpc0801";
public User() {
super();
}
public User(String userName) {
super();
this.userName = userName;
}
@Override
public boolean equals(Object obj) {
return this.getUserName().equals(((User) obj).getUserName());
}
@Override
public int hashCode() {
return this.getUserName().hashCode();
}
@Override
public String toString() {
return "姓名:" + getUserName();
}
public static String staticMethod() {
return "Static Method";
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
注意,set集合中要判斷兩個(gè)自定義對(duì)象是否是相同的,需要重寫兩個(gè)方法hashCode, equals兩個(gè)方法
Action:
public class Chapter10Action extends BaseAction {
private String message;
private User user;
private List<User> users = new ArrayList<User>();
private Set<User> usersSet = new HashSet<User>();
private Map<String, User> usersMap = new HashMap<String, User>();
public Chapter10Action() {
user = new User("wdpc");
users.add(new User("張三"));
users.add(new User("李四"));
users.add(new User("王五"));
usersSet.add(new User("zhang"));
usersSet.add(new User("hai"));
usersSet.add(new User("hai"));
usersSet.add(new User("dang"));
usersMap.put("u1", new User("趙六"));
usersMap.put("u2", new User("林七"));
usersMap.put("u3", new User("魏八"));
}
public String method1() {
return "method1";
}
public String test() {
return "Action Method";
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Set<User> getUsersSet() {
return usersSet;
}
public void setUsersSet(Set<User> usersSet) {
this.usersSet = usersSet;
}
public Map<String, User> getUsersMap() {
return usersMap;
}
public void setUsersMap(Map<String, User> usersMap) {
this.usersMap = usersMap;
}
}
JSP:
<body>
訪問User Model的構(gòu)造方法 訪問users:
<s:property value="users" />
<br />
訪問指定的元素users[0]:
<s:property value="users[0]" />
<br />
訪問users屬性的userName集合users.{userName}:
<s:property value="users.{userName}" />
<br />
訪問users中指定元素的屬性:
<s:property value="users[0].userName" />
|
<s:property value="users.{userName}[0]" />
<br />
訪問usersSet:
<s:property value="usersSet" />
<br />
訪問usersMap:
<s:property value="usersMap" />
<br />
訪問Map中指定的元素usersMap.u1 | usersMap['u1'](key與變量命名規(guī)則一致):
<s:property value="usersMap.u1" />
|
<s:property value="usersMap['u1']" />
<br />
訪問Map中所有的(usersMap.keys)key:
<s:property value="usersMap.keys" />
<br />
訪問Map中所有的(usersMap.values)values:
<s:property value="usersMap.values" />
<br />
</body>
如果要訪問key集合中的某一個(gè)元素,可以這樣訪問:
<s:property value="usersMap.keys.{#this}[0]" />
使用OGNL表達(dá)式投影(過濾)集合
“?”:投影(過濾)所有符合條件的集合,如:users.{?#this.age > 19};
“^”:投影(過濾)第一個(gè)符合條件的元素,如:users.{^#this.age > 19};
“$”:投影(過濾)最后一個(gè)符合條件的元素,如:users.{$#this.age > 19} 。
#this代表users集合自己本身
Action:
public class Chapter10Action extends BaseAction {
private List<User> users = null;
public Chapter10Action() {
users = new ArrayList<User>();
users.add(new User("張三", 22));
users.add(new User("李四", 23));
users.add(new User("王五", 24));
users.add(new User("趙六", 22));
users.add(new User("林七", 23));
users.add(new User("魏八", 24));
}
public String index() {
return "index";
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
JSP:
<body>
所有符合條件的集合:<s:property value="users.{?#this.age > 22}" /><br />
所有符合條件的集合中指定的元素:<s:property value="users.{?#this.age > 22}[0]" /><br />
第一個(gè)符合條件的元素集合:<s:property value="users.{^#this.age > 22}" /><br />
最后一個(gè)符合條件的元素集合:<s:property value="users.{$#this.age > 22}" /><br />
</body>