Java中的值棧


OGNL表示式使用 和 值棧

OGNLObject Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。 Struts2框架使用OGNL作為默認的表達式語言。

* xwork 提供 OGNL表達式

* ognl-3.0.5.jar

OGNL 是一種比EL 強大很多倍的語言

 

OGNL 提供五大類功能

   1、支持對象方法調用,如xxx.doSomeSpecial()

   2、支持類靜態的方法調用和值訪問

   3、訪問OGNL上下文(OGNL context)和ActionContext; (重點 操作ValueStack值棧 )

   4、支持賦值操作和表達式串聯

   5、操作集合對象。

 

1、 使用OGNL訪問 對象方法 和 靜態方法

* OGNL jsp 結合 struts2 標簽庫 使用 , <s:property value="ognl表達式" /> 執行 ognl表達式

調用 實例方法 對象.方法()  ----  <s:property value="'hello,world'.length()"/>

調用 靜態方法 @[類全名(包括包路徑)]@[方法名]  --- <s:property value="@java.lang.String@format('您好,%s','小明')"/>

* 使用 靜態方法調用 必須 設置 struts.ognl.allowStaticMethodAccess=true

 

2、 訪問OGNL上下文(OGNL context)和ActionContext

OGNL上下文(OGNL context) 對象 ----- 值棧 ValueStack

 

什么是值棧 ValueStack ?

值棧:簡單的說,就是存放action的堆棧,當我們提交一個請求到服務器端 action時,就有個堆棧,如果action在服務器端進行跳轉,所有action共用一個堆棧,當需要保存在action中的數據時,首先從棧頂開始 搜索,若找到相同的屬性名(與要獲得的數據的屬性名相同)時,即將值取出,但這種情況可能出現找到的值不是我們想要的值,那么解決此問題需要用TOP語法 和N語法來進行解決。

0

ValueStack struts2 提供一個接口,實現類 OgnlValueStack ---- 值棧對象 (OGNL是從值棧中獲取數據的 )

每個Action實例都有一個ValueStack對象 (一個請求 對應 一個ValueStack對象 )

在其中保存當前Action 對象和其他相關對象 (值棧中 是有Action 引用的 

Struts 框架把 ValueStack 對象保存在名為 “struts.valueStack” 的請求屬性中,request中 (值棧對象 request一個屬性

valueStack vs = request.getAttribute("struts.valueStack");

問題二 值棧的內部結構

    值棧由兩部分組成

ObjectStack  (root): Struts  把動作和相關對象壓入 ObjectStack --List

ContextMap   (context): Struts 把各種各樣的映射關系(一些 Map 類型的對象) 壓入 ContextMap

Struts 會把下面這些映射壓入 ContextMap

parameters: Map 中包含當前請求的請求參數  ?name=xxx

request: Map 中包含當前 request 對象中的所有屬性

session: Map 中包含當前 session 對象中的所有屬性

application:Map 中包含當前 application  對象中的所有屬性

attr: Map 按如下順序來檢索某個屬性: request, session, application

 

ValueStack中 存在root屬性 (CompoundRoot) context 屬性 (OgnlContext

* CompoundRoot 就是ArrayList

* OgnlContext 就是 Map

context 對應Map 引入 root對象

* context中還存在 requestsessionapplicationattrparameters 對象引用

* OGNL表達式,訪問root中數據時 不需要 #, 訪問 requestsessionapplicationattrparameters 對象數據 必須寫 #

* 操作值棧 默認指 操作 root 元素

 

問題三 值棧對象的創建 ValueStack ActionContext 是什么關系 ?

值棧對象 是請求時 創建的

doFilterprepare.createActionContext(request, response);

* 創建ActionContext 對象過程中,創建 值棧對象ValueStack

* ActionContext對象 對 ValueStack對象 有引用的 (在程序中 通過 ActionContext 獲得 值棧對象 )

DispatcherserviceAction 方法中 將值棧對象保存到 request范圍

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

 

問題四 如何獲得值棧對象

獲得值棧對象 有兩種方法

ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

ValueStack valueStack2 = ActionContext.getContext().getValueStack();

 

問題五: 向值棧保存數據 (主要針對 root

兩種方式

// 將數據保存root的索引0位置,放置到第一個元素 ArrayList add(0,element);

valueStack.push("itcast");

 

// 在值棧創建參數map, 將數據保存到map

valueStack.set("company", "數據");

 

jsp中 通過 <s:debug /> 查看值棧的內容

 

問題六: JSP中獲取值棧的數據

    訪問root中數據 不需要#

    訪問 其它對象數據 #

 

通過下標獲取root中對象

   <s:property value="[0].top"/> //取值棧頂對象

直接在root中查找對象屬性 (自上而下自動查找)

  valueStack:<s:property value="username"/>

 

OgnlContext中獲取數據

request:<s:property value="#request.username"/>

session:<s:property value="#session.username"/>

application:<s:property value="#application.username"/>

attr:<s:property value="#attr.username"/>

parameters:<s:property value="#parameters.cid[0]"/>

 

valueStack對象 保存在request范圍, 值棧生命周期 就是 request的生命周期 ,值棧的內部結構(rootognlContext

 

3、 值棧在開發中應用

主流應用 值棧 解決 Action JSP 傳遞 數據問題

 

Action JSP 傳遞數據處理結果 ,結果數據有兩種形式

1) 消息 String類型數據

this.addFieldError("msg", "字段錯誤信息");

this.addActionError("Action全局錯誤信息");

this.addActionMessage("Action的消息信息");

 

* fieldError 針對某一個字段錯誤信息 (常用於表單校驗)、actionError (普通錯誤信息,不針對某一個字段 登陸失敗)actionMessage 通用消息

 

jsp中使用 struts2提供標簽 顯示消息信息

<s:fielderror fieldName="msg"/>

<s:actionerror/>

<s:actionmessage/>

 

2) 數據 (復雜類型數據)

使用值棧  valueStack.push(products);

 

哪些數據默認會放入到值棧 ???

1)每次請求,訪問Action對象 會被壓入值棧 ------- DefaultActionInvocation init方法 stack.push(action);

* Action如果想傳遞數據給 JSP,只有將數據保存到成員變量,並且提供get方法就可以了 

2ModelDriven 接口 有一個單獨攔截器

<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>

在攔截器中 ,將model對象 壓入了 值棧 stack.push(model);

  user.usernae ---------------?><input name="username"/>

* 如果Action 實現ModelDriven接口,值棧默認棧頂對象 就是model對象

 

4、 值棧的數據 通過EL訪問

問題七:為什么 EL也能訪問值棧中的數據

    ActionContext.getContext().getSession().setAttribute("key","value");

 

    ${requestScope.username}----------->requst.getAttribute("username");------>重寫getAttribute()方法,沒有找到數據的情況下,繼續找ValueStack

 

StrutsPreparedAndExecuteFilterdoFilter代碼中 request = prepare.wrapRequest(request);

* Request對象進行了包裝 ,StrutsRequestWrapper

* 重寫requestgetAttribute

Object attribute = super.getAttribute(s);

if (attribute == null) {

   attribute = stack.findValue(s);

}

      訪問request范圍的數據時,如果數據找不到,去值棧中找

* request對象 具備訪問值棧數據的能力 (查找root的數據)

 

5OGNL表達式 常見使用

#% $ 符號使用

1# 的 使用

用法一  # 代表 ActionContext.getContext() 上下文

  <s:property value="#request.name" />  ------>  ActionContext().getContext().getRequest().getAttribute("name");

  #request

  #session

  #application

  #attr

  #parameters

 

用法二 不寫# 默認在 值棧中root中進行查找

   <s:property value="name" /> root中查找name屬性

* 查詢元素時,從root的棧頂元素 開始查找, 如果訪問指定棧中元素    <s:property value="[1].top.name" />  訪問棧中第二個元素name屬性

* 訪問第二個元素對象 <s:property value="[1].top" />

 

用法三 :進行投影映射 (結合復雜對象遍歷

     s:iterator標簽在進行遍歷時,會將var中保存的這個對象,在root中,和context中都放一份

        所以在<s:property  value=""/>  value屬性加不加#都可以訪問

   1)集合的投影(只輸出部分屬性

   <h1>遍歷集合只要name屬性</h1>

<s:iterator value="products.{name}" var="pname">

<s:property value="#pname"/>

</s:iterator>

   2)遍歷時,對數據設置條件

<h1>遍歷集合只要price大於1500商品</h1>

<s:iterator value="products.{?#this.price>1500}" var="product">

<s:property value="#product.name"/> --- <s:property value="#product.price"/>

</s:iterator>

   3)綜合

   <h1>只顯示價格大於1500 商品名稱</h1>

<s:iterator value="products.{?#this.price>1500}.{name}" var="pname">

<s:property value="#pname"/>

</s:iterator>   

 

用法四: 使用#構造map集合

經常結合 struts2 標簽用來生成 selectcheckboxradio

<h1>使用#構造map集合 遍歷</h1>

                  #{key:value,kye1:value1}

<s:iterator value="#{'name':'aaa','age':'20', 'hobby':'sport' }" var="entry">

key : <s:property value="#entry.key"/> , value:  <s:property value="#entry.value"/> <br/>

</s:iterator>

 

2) %的使用

   用法一: 結合struts2 表單標簽使用, 通過%通知struts%{}中內容是一個OGNL表達式,進行解析

   <s:textfield name="username" value="%{#request.username}"/>

   <s:textfield name="username" value="<s:property value='#request.username'/>"  />是錯誤的

   用法二: 設置ognl表達式不解析 %{'ognl表達式'}

   <s:property value="%{'#request.username'}"/>

 

3$的使用

   用法一 :用於在國際化資源文件中,引用OGNL表達式

properties文件 msg=歡迎您, ${#request.username}

在頁面

    <s:i18n name="messages">

<s:text name="msg"></s:text>

</s:i18n>

* 自動將值棧的username 結合國際化配置信息顯示

   用法二 :在Struts 2配置文件中,引用OGNL表達式

<!-- Action 提供 getContentType方法 -->

<param name="contentType">${contentType}</param>

       *  ${contentType} 讀取值棧中contentType數據,在Action提供 getContentType 因為Action對象會被壓入值棧,

      contentTypeAction屬性,從值棧獲得

 

結論: #用於寫ognl表達式獲取數據,% 控制ognl表達式是否解析 ,$ 用於配置文件獲取值棧的數據

 

五、 struts2 標簽庫

tag-reference.html 就是 struts2 標簽規范

1、 通用標簽庫 的學習

<s:property> 解析ognl表達式,設置默認值,設置內容是否HTML轉義

<s:set> 對比c:set向四個數據范圍保存數據

<s:iterator> 遍歷值棧中數據 <c:forEach  />

<s:if> <s:elseif> <s:else> 進行條件判斷 -------- elseif 可以有多個

<s:url> 進行URL重寫(追蹤Session ) ,結合s:param 進行參數編碼

*   <s:url action="download" namespace="/" var="myurl">

<s:param name="filename" value="%{'MIME協議簡介.txt'}"></s:param>

    </s:url>

    <s:property value="#myurl"/>

<s:a> 對一個鏈接 進行參數編碼

    * <s:a action="download" namespace="/" >下載MIME協議簡介.txt

<s:param name="filename" value="%{'MIME協議簡介.txt'}"></s:param>

  </s:a>

 

2UI標簽庫的學習 (Form標簽)

    使用struts2 form標簽 好處 : 支持數據回顯 , 布局排版(基於Freemarker 模板定義 )

struts2 表單標簽 value屬性。 必須寫 %{} 進行設值

 使用struts2表單標簽前, 必須配置 StrutsPrepareAndExecuteFilter

 

<s:form> 表單標簽

<s:form action="regist" namespace="/" method="post" theme="xhtml">  ---   theme="xhtml" 默認布局樣式

<s:textfield> 生成 <input type="text" >

<s:password > 生成 <input type="password" >

 

<s:submit type="submit" value="注冊"/> 生成 <input type="submit" >

<s:reset type="reset" value="重置" /> 生成 <input type="reset" >

 

* struts2 除了支持JSP之外,支持兩種模板技術 Velocity (擴展名 .vm ) Freemarker (擴展名 .ftl

 

<s:textarea> 生成 <textarea> 多行文本框

 

<s:checkboxlist> 生成一組checkbox

* 使用ognl構造 Map (看到值和提交值 不同時)

* <s:checkboxlist list="#{'sport':'體育','read':'讀書','music':'音樂' }" name="hobby"></s:checkboxlist>

<s:radio> 生成一組radio

* 使用 ognl構造 List  (看到內容和提交值 相同時)

* <s:radio list="{'',''}" name="gender"></s:radio>

<s:select> 生成一個<select>

* <s:select list="{'北京','上海','南京','廣州'}" name="city"></s:select>

 

struts2 開發 密碼框 默認不回顯

      <s:password name="password" id="password" showPassword="true"/>

 

3、 頁面元素主題設置

    default.properties  ----  struts.ui.theme=xhtml 設置struts2 頁面元素使用默認主題

                          struts.ui.templateSuffix=ftl 默認模板引擎 Freemarker

修改主題

     方式一 <s:textfield name="username"  label="用戶名“ theme="simple"></s:textfield> 只對當前元素有效

 方式二 <s:form  action="" method="post" namespace="/ui“    theme="simple"> form中所有元素有效

 方式三 struts.xml

     <constant name="struts.ui.theme" value="simple"></constant>  修改默認主題樣式,頁面所有元素都有效

     優先級 方式一 > 方式二  > 方式三

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM