Struts推薦使用功能更加強(qiáng)大的Ognl表達(dá)式。El可以完成的功能,Ognl也可以,El不能完成的功能,Ognl也可以。
但是有些程序員,已經(jīng)習(xí)慣了jsp中結(jié)合jstl和el表達(dá)式,我們可以有兩種解決方案:
1.使用struts2自帶的標(biāo)簽庫,jsp中使用ognl進(jìn)行操作。
2.不是用struts2自帶的標(biāo)簽庫,jsp直接結(jié)合jstl+el進(jìn)行操作。
jsp2.0中默認(rèn)啟動(dòng)對(duì)el表達(dá)式的支持的。但從Struts2.0.11起,Struts2標(biāo)簽庫將不再支持El表達(dá)式。
struts2.0.11版本不支持el,因而以前在低版本下寫和程式將不能正常運(yùn)行:
下面是一段分頁所用的循環(huán):
<c:forEach var="i" begin="1" end="${requestScope.page.afterPage}" step="1">
<c:if
test="${requestScope.page.indexPage<requestScope.page.totalPage && requestScope.page.indexPage+i<requestScope.page.totalPage}">
<s:url id="afterUrl" value="/photoItemsList.html">
<s:param name="indexPage" value="${requestScope.page.indexPage+i}" /><!-- struts2.0.11中已不支持el,因而<s:url>將取不到相關(guān)值-->
</s:url>
<s:a theme="ajax" href="%{afterUrl}" indicator="indicator" showLoadingText="false" targets="pageItems">
<c:out value="${requestScope.page.indexPage+i}" /> </s:a>
</c:if>
</c:forEach>
修改成如下:
<c:forEach var="i" begin="1" end="${requestScope.page.afterPage}" step="1">
<c:set value="${i}" var="var"/>
<c:if test="${requestScope.page.indexPage<requestScope.page.totalPage && requestScope.page.indexPage+i<requestScope.page.totalPage}">
<s:url id="afterUrl" value="/photoItemsList.html">
<s:param name="indexPage" value="#request.page.indexPage+#attr.var" />
</s:url>
<s:a theme="ajax" href="%{afterUrl}" indicator="indicator" showLoadingText="false" targets="pageItems">
<c:out value="${requestScope.page.indexPage+i}" /> </s:a>
</c:if>
</c:forEach>
但我們使用第二種方式時(shí),el可以訪問struts2,valuestack中的值。
El表達(dá)式使用,還是像以前一樣的,但是struts2中添加了一個(gè)值棧對(duì)象,所以有些小小的變動(dòng),搜索的順序是Page,Reqeust,ValueStack,Session,Application。
值棧中存儲(chǔ)的是Action類中的全局變量(在servlet,struts中是不支持直接讀取Action類中的值得,要設(shè)置到Request,Session等中,進(jìn)行值得傳遞)。
測(cè)試程序(服務(wù)器端):
package com.helloweenvsfei.struts2.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class OgnlElAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private int i;//來自客戶端,能取得
private String j;//額外定義,能取得
private String c="C";//沒有get,set方法,EL不能獲取
public String getJ() {
j="J";
return j;
}
public void setJ(String j) {
this.j = j;
}
@Override
public String execute() throws Exception {
i=i+100;
String a="wla";//不能獲取,除非設(shè)值到request等范圍
String b="wlb";//不能獲取,除非設(shè)值到request等范圍
HttpServletRequest request=ServletActionContext.getRequest();
// request.setAttribute("a", "locala");
// HttpSession session=request.getSession();
// session.setAttribute("b", "localb");
//要是在取值是沒有響應(yīng)的屬性,就是默認(rèn)值。
request.setAttribute("f", "localf");
request.setAttribute("d", "four local");
HttpSession session=request.getSession();
session.setAttribute("d", "locald");
// 以上三句說明,是按照順序進(jìn)行查找的。
//request.setAttribute("j", "action");
//session.setAttribute("j", "action");
//總結(jié)出EL的訪問順序,Page,Request,ValueStack,Session,Application
return SUCCESS;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
客戶端:
<body>
<%-- <% String j="page"; %>
<% pageContext.setAttribute("j","MLDN") ;
%>
--%>
This is my JSP page. <br>
Action:${i};<br/>
Action:${j};<br/>
Action:${c};<br/>
Execute:${requestScope.a};<br/>
Execute:${sessionScope.b};<br/>
Execute:$c9ozetgccsir;<br/>
Execute:${f};<br/>
<!-- Execute:${requestScope.a};
Execute:${sessionScope.b}; -->
<!--<s:property value="#session.i"/>-->
</body>
關(guān)于OGNL:
OGNL全稱為Object-Graph Navigation Language,是一種表達(dá)式語言(EL)。
EL的支持者認(rèn)為,在JSP頁面中應(yīng)盡可能地避免 <% %> 這樣的標(biāo)記,而代之以Tag,以使頁面更簡(jiǎn)潔,并體現(xiàn)頁面與后臺(tái)代碼分離的設(shè)計(jì)原則。對(duì)此我持保留意見,因?yàn)槲也⒉徽J(rèn)為使用Tag后的頁面的可讀性要高于使用<% %>。
Struts 2支持如下幾種EL:
· OGNL(Object-Graph Navigation Language): 可以方便地操作對(duì)象屬性的開源表達(dá)式語言
· JSTL(JSP Standard Tag Library): JSP 2.0集成的標(biāo)準(zhǔn)的表達(dá)式語言
· Groovy: 基于Java平臺(tái)的動(dòng)態(tài)語言,它具有時(shí)下比較流行的動(dòng)態(tài)語言(如Python、Ruby和Smarttalk等)的一些新特性
· Velocity: 嚴(yán)格來說不是表達(dá)式語言,它是一種基于Java的模板匹配引擎,據(jù)說其性能要比JSP好
Struts 2默認(rèn)的表達(dá)式語言是OGNL,原因是它相對(duì)其它表達(dá)式語言具有下面幾大優(yōu)勢(shì):
· 支持對(duì)象方法調(diào)用,如xxx.doSomeSpecial();
· 支持類靜態(tài)的方法調(diào)用和值訪問,表達(dá)式的格式為@[類全名(包括包路徑)]@[方法名 | 值名],例如: @java.lang.String@format('foo %s', 'bar')或 @tutorial.MyConstant@APP_NAME;
· 支持賦值操作和表達(dá)式串聯(lián),如price=100, discount=0.8, calculatePrice(),這個(gè)表達(dá)式會(huì)返回80;
· 訪問OGNL上下文(OGNL context)和ActionContext;
· 操作集合對(duì)象。
OGNL是通常要結(jié)合Struts 2的標(biāo)志一起使用,如<s:property value="xx" />等。大家經(jīng)常遇到的問題是#、%和$這三個(gè)符號(hào)的使用。下面我講述這個(gè)問題:
4.1 “#”的用途
訪問OGNL上下文和Action上下文
#相當(dāng)于ActionContext.getContext();下表有幾個(gè)ActionContext中有用的屬性:
· parameters:包含當(dāng)前HTTP請(qǐng)求參數(shù)的Map,#parameters.id[0]作用相當(dāng)于request.getParameter("id")
· request:包含當(dāng)前HttpServletRequest的屬性(attribute)的Map,#request.userName相當(dāng)于request.getAttribute("userName")
· session:包含當(dāng)前HttpSession的屬性(attribute)的Ma, #session.userName相當(dāng)于session.getAttribute("userName")
· application:包含當(dāng)前應(yīng)用的ServletContext的屬性(attribute)的Map,#application.userName相當(dāng)于application.getAttribute("userName")
· attr:用于按request > session > application順序訪問其屬性(attribute),#attr.userName相當(dāng)于按順序在以上三個(gè)范圍(scope)內(nèi)讀取userName屬性,直到找到為止
過濾和投影(projecting)集合
如books.{?#this.price<100}
構(gòu)造Map
如#{'foo1':'bar1', 'foo2':'bar2'}
4.2 %的用法
“%”符號(hào)的用途是在標(biāo)志的屬性為字符串類型時(shí),計(jì)算OGNL表達(dá)式的值。例如在Ognl.jsp中加入以下代碼:
<h3>%的用途</h3><p><s:url value="#foobar['foo1']" /></p><p><s:url value="%{#foobar['foo1']}" /></p>
刷新頁面,顯示以下內(nèi)容
%的用途#foobar['foo1']bar1
4.3 $的用法
“$”有兩個(gè)主要的用途:
1. 用于在國(guó)際化資源文件中,引用OGNL表達(dá)式
2. Struts 2配置文件中,引用OGNL表達(dá)式,如
<action name="AddPhoto" class="addPhoto"> <interceptor-ref name="fileUploadStack" /> <result type="redirect">ListPhotos.action?albumId=${albumId}</result></action>