1.Ognl表達(dá)式語言
1.1.概述
OGNL表達(dá)式
OGNL是Object Graphic Navigation Language(對象圖導(dǎo)航語言)的縮寫,他是一個開源項(xiàng)目。Struts框架使用OGNL作為默認(rèn)的表達(dá)式語言。
OGNL優(yōu)勢
總結(jié):OGNL 有一個上下文(Context)概念,說白了上下文就是一個MAP結(jié)構(gòu),它實(shí)現(xiàn)了java.utils.Map 的接口。
Struts框架默認(rèn)就支持Ognl表達(dá)式語言。(從struts項(xiàng)目必須引入ognl.jar包可以看出)
Ognl表達(dá)式語言的作用:
- jsp頁面取值用
- EL表達(dá)式語言,也用于頁面取值,是jsp頁面取值的標(biāo)準(zhǔn)(默認(rèn)就可以使用)
- Ognl表達(dá)式語言,Struts標(biāo)簽?zāi)J(rèn)支持的表達(dá)式語言,必須配置Struts標(biāo)簽用,不能離開Struts標(biāo)簽直接使用,就是說Ognl必須在Struts中使用
- 對比來看,EL使用范圍更廣,項(xiàng)目中不限制使用哪一種,哪一種熟悉就使用哪一種
1.2.OgnlContext對象(了解)
OgnlContext對象是ognl表達(dá)式語言的核心。
但是項(xiàng)目中不會要求寫OgnlContext的代碼,Ognl標(biāo)簽其實(shí)是調(diào)用了OgnlContext對象。所以只做了解即可。
OgnlContext對象在源碼中實(shí)現(xiàn)了Map接口:
public class OgnlContext implements Map {……}
Ognl表達(dá)式語言取值,也是用java代碼取值的,原理就是使用OgnlContext和Ognl這兩個類,只需要記住,Ognl取根元素不用#號,取非根元素要使用#號:
OgnlContext類
硬編碼方式,了解OgnlContext對象,因?yàn)镺gnlContext對象實(shí)現(xiàn)是Map接口,所有OgnlContext本質(zhì)就是一個Map,可以使用map方法:
OgnlContext context = new OgnlContext();
context.put("uesr",user);
context.put("address",address);
context.setRoot(address);
Ognl類
Ognl類也是Ognl底層運(yùn)行的代碼,常用的api如下:
Object obj1 = Ognl.parseExpression(“country”); 解析ognl表達(dá)式
Ognl.getValue(obj1, context, context.getRoot()); 獲取ognl的表達(dá)式值,obj1是上面一個api,其他兩個分別是創(chuàng)建的上下文對象以及一個不用修改的參數(shù)
Object obj2 = Ognl.parseExpression(“l(fā)anguage.toUpperCase()”); 方法調(diào)用
Object obj3 = Ognl.parseExpression("@java.lang.Integer@toBinaryString(10)");等同于上面
Object obj4 = Ognl.parseExpression(“@@min(10,4)”); Math類的方法直接調(diào)用,靜態(tài)方法的調(diào)用
代碼示例如下:
package o_ognl;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;
/**
* OgnlContext用法
* 1.使用Ognl表達(dá)式語言取值,如果取非根元素的值,必須用#號
* 2.使用Ognl表達(dá)式語言取值,如果取根元素的值,不用#號
* 3.Ognl可以調(diào)用靜態(tài)方法
*/
public class OgnlDemo {
//非根元素
@Test
public void testOgnl1() throws OgnlException {
//創(chuàng)建一個Ognl上下文對象
OgnlContext context = new OgnlContext();
/**
* 1.OgnlContext放入基本變量數(shù)據(jù)
*/
//放入數(shù)據(jù)
context.put("cn","China");
//獲取數(shù)據(jù)(map)
String value = (String)context.get("cn");
System.out.println(value);
/**
* 2.OgnlContext放入對象數(shù)據(jù)
*/
//創(chuàng)建對象,設(shè)置對象屬性
User user = new User();
user.setId(100);
user.setName("Jack");
//【往非根元素放入數(shù)據(jù),取值的時(shí)候表達(dá)式要用“#”】
context.put("user",user);
//獲取對象屬性
//使用這種方式也可以獲取
Object s = context.get("user");
System.out.println(s);
//使用Ognl表達(dá)式來獲取
//舉例:例如標(biāo)簽<s:a value="#user.id">取值,實(shí)際上就是運(yùn)行了下面的代碼獲取的
//先構(gòu)建一個Ognl表達(dá)式,再解析表達(dá)式
Object ognl = Ognl.parseExpression("#user.id");//構(gòu)建Ognl表達(dá)式
Object value1 = Ognl.getValue(ognl, context, context.getRoot());//解析表達(dá)式
System.out.println(value1);
User user1 = new User();
user1.setId(100);
user1.setName("Jack");
context.setRoot(user1);
Object ognl1 = Ognl.parseExpression("id");//構(gòu)建Ognl表達(dá)式
Object value2 = Ognl.getValue(ognl1, context, context.getRoot());//解析表達(dá)式
System.out.println(value2);
}
//根元素,
@Test
public void testOgnl2() throws OgnlException {
OgnlContext context = new OgnlContext();
User user1 = new User();
user1.setId(100);
user1.setName("Jack");
context.setRoot(user1);
//根元素直接使用id,不需要加#號
Object ognl1 = Ognl.parseExpression("id");//構(gòu)建Ognl表達(dá)式
Object value2 = Ognl.getValue(ognl1, context, context.getRoot());//解析表達(dá)式
System.out.println(value2);
}
//ognl對靜態(tài)方法調(diào)用的支持
@Test
public void testOgnl3() throws Exception{
//創(chuàng)建一個Ognl上下文對象
OgnlContext context = new OgnlContext();
//Ognl表達(dá)式語言,調(diào)用類的靜態(tài)方法
// Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
//由于Math類在開發(fā)中比較常用,所有也可以這樣寫
Object ognl = Ognl.parseExpression("@@floor(10.9)");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
}
1.3.ValueStack對象
1.ValueStack即值棧對象
ValueStack實(shí)際是一個接口,在Struts2中利用Ognl時(shí),實(shí)際上使用的是實(shí)現(xiàn)了該接口的OgnlValueStack類,這個類是Struts2利用Ognl的基礎(chǔ)
2.ValueStack特點(diǎn)
ValueStack貫穿整個Action的生命周期(每個Action類的對象實(shí)例都擁有一個ValueStack對象),即用戶每次訪問struts的action,都會創(chuàng)建一個Action對象、值棧對象、ActionContext對象,然后把Action對象放入值棧中;最后再把值棧對象放入request中,傳入jsp頁面。相當(dāng)于一個數(shù)據(jù)的中轉(zhuǎn)站,在其中保存當(dāng)前Action對象和其他相關(guān)對象。Struts2框架把ValueStack對象保存在名為“struts。valueStack”的request請求屬性中。
3.ValueStack存儲對象
代碼調(diào)試的時(shí)候,發(fā)現(xiàn)有一個root是compundRoot類,繼承ArrayList,保存的是action對象;還有一個OgnlContext是繼承Map,保存數(shù)據(jù)。
所以ValueStack存儲對象時(shí)是分兩個地方來存的,也即ValueStack對象的組成是由List棧和Map棧構(gòu)成的:
ObjectStack :Struts把根元素,即action對象及全局屬性存入ObjectStack中---List
list棧主要存儲:action對象,Map對象(通過vs.set()設(shè)置),通過push方法設(shè)置的對象,以及其他代理對象
根元素的存儲示例:
//存儲值棧對象
ActionContext ac = ActionContext.getContext();
ValueStack vs = ac.getValueStack();
vs.set("user1",new User(100,"Jack1"));//Map
vs.push(new User(100,"Jack2"));//棧頂
ContextMap :Struts把各種各樣的映射關(guān)系(域數(shù)據(jù))存入ContextMap中
Struts會把下面這些映射存入ContextMap中:
- parameter:該Map中包含當(dāng)前請求的請求參數(shù)
- request:該Map中包含當(dāng)前request對象中的所有屬性
- Session:該Map中包含當(dāng)前Session對象中的所有屬性
- application:該Map中包含當(dāng)前application對象中的所有屬性
- attr:該Map按如下順序來檢索某個屬性:request,Session,application
非根元素Map中存放數(shù)據(jù)的方法示例:
//存儲值棧對象
ActionContext ac = ActionContext.getContext();
//映射數(shù)據(jù)
ac.getContextMap().put("request_data", "request_data");
ac.getSession().put("session_data", "session_data");
ac.getApplication().put("application_data","application_data");
從棧中取值的兩種方式:
//一、獲取值棧對象的兩種方式,是等價(jià)的
public void getVs() {
//獲取值棧對象,方式1:
HttpServletRequest request = ServletActionContext.getRequest();
ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
/**************************************************/
//獲取值棧對象,方式2:
ActionContext ac = ActionContext.getContext();
ValueStack vs2 = ac.getValueStack();
System.out.println(vs1==vs2);//true
}
在jsp頁面中,對不同ValueStack中的不同類型取值方法不同,
如果是根元素取值,直接寫表達(dá)式;
非根元素(request,Session,application,att,parmeters)必須用#號,例#request.cn
1.4.JSP頁面中獲取ValueStack數(shù)據(jù)
<%@taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp頁面取值</title>
</head>
<body>
index頁面
<%--頁面,必須要拿到ValueStack--%>
<%--struts的調(diào)試標(biāo)簽,可以觀測值棧數(shù)據(jù)--%>
<s:debug/>
<br/>1.取根元素的值<br/>
<s:property value="user.id"/>
<s:property value="user.name"/>
<br/>2.取非根元素<br/>
<s:property value="#request.cn"/>
<s:property value="#request.request_data"/>
<s:property value="#session.session_data"/>
<s:property value="#application.application_data"/><br/>
<%--attr按順序自動找request/session/application,找到后立刻返回--%>
<s:property value="#attr.application_data"/>
<%--獲取請求參數(shù)數(shù)據(jù)--%>
<s:property value="#parameters.userName"/>
</body>
</html>
2.Struts標(biāo)簽
struts標(biāo)簽取值,就使用到ognl表達(dá)式語言。
2.1.Ognl使用方式
1.4.中使用的就是Ognl表達(dá)式取值。使用方式是:
1.引入<%@taglib prefix="s" uri="/struts-tags" %>
2.使用 <s:property value="user.name"/> 標(biāo)簽獲取取值,取值的時(shí)候要注意根元素(全局變量)不用#號,其他的都用#號
還有一些標(biāo)簽需要學(xué)習(xí):
2.2.迭代標(biāo)簽
Iterator:標(biāo)簽用于對集合進(jìn)行迭代,這里的集合包含List,Set和數(shù)組
代碼示例:
<br/>1.list迭代<br/>
<s:iterator var="user" value="#request.list" status="st">
<s:property value="#user.id"/>
<s:property value="#user.name"/>
<s:property value="#st.even"/><br/>
</s:iterator>
<br/>2.map迭代<br/>
<s:iterator var="en" value="#request.map" status="st">
<s:property value="#en.key"/>
<s:property value="#en.value.name"/>
</s:iterator>
2.3.Ognl動態(tài)建立集合
<%--Ognl表達(dá)式可以取值,也可以構(gòu)建動態(tài)集合--%>
<br/>1.構(gòu)建list集合<br/>
<s:iterator var="str" value="{'a','b','c'}">
<s:property value="#str"/>
</s:iterator>
<br/>2.構(gòu)建map集合<br/>
<s:iterator var="en" value="#{'cn':'China','usa':'America'}">
<s:property value="en.key"/>
<s:property value="en.value"/><br/>
</s:iterator>
2.4.簡單UI標(biāo)簽
<%@taglib prefix="s" uri="/struts-tags" %>
<%--服務(wù)器標(biāo)簽:最終被解析為html標(biāo)簽--%>
<s:form action="/user_login" method="POST" name="frmLogin">
<s:textfield name="user.userName" label="用戶名"/>
<s:textfield name="user.pwd" label="密碼"/>
<s:submit value="登錄"/>
</s:form>
也可以給form指定主題,方法如下:
<!-- 服務(wù)器標(biāo)簽 : 最終別解析為html標(biāo)簽-->
<s:form action="/user_login" method="post" name="frmLogin" id="frmLogin" theme="simple">
用戶名:<s:textfield name="user.name"></s:textfield>
密碼:<s:textfield name="user.pwd"></s:textfield>
<s:submit value="登陸"></s:submit>
</s:form>
注意:
給form指定主題,form下所有的表單元素都應(yīng)用此主題
對Struts標(biāo)簽?zāi)J(rèn)的主題樣式:default.xml/struts.ui.theme=xhtml
可以通過常量修改,改為簡單主題:
<!-- 修改主題 (當(dāng)前項(xiàng)目所有的標(biāo)簽都用此主題)-->
<constant
name="struts.ui.theme" value="simple"></constant>
2.5.Ognl表達(dá)式語言幾個符號
:獲取非根元素,動態(tài)創(chuàng)建map集合
$:配置文件取值
%:提供一個ognl表達(dá)式運(yùn)行環(huán)境
<body>
<br/>獲取request域數(shù)據(jù)<br/>
<!-- property 標(biāo)簽是對象類型的標(biāo)簽,默認(rèn)支持ognl表達(dá)式, 會從根元素去China名稱對應(yīng)的值 -->
<s:property value="China"/> <br/>
<!-- 如果直接賦值,需要用單引號 -->
<s:property value="'China'"/> <br/>
<s:property value="%{#request.cn}"/> <br/>
<!-- 值類型的標(biāo)簽,value值默認(rèn)就是值類型,不支持ognl表達(dá)式 -->
國家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>
</body>
|