Struts2入門(三)
阿新 • • 發佈:2018-11-20
Struts2第三天
課程回顧:Struts2框架的第二天
1. Servlet的API
* ActionContext物件
* ServletActionContext物件
2. 結構型別的跳轉
* 全域性結果
* 區域性結構,type屬性
3. 資料的封裝
* 屬性驅動方式
* 模型驅動方式
4. 攔截器(自定義攔截器)
今天的課程內容
1. OGNL表示式(瞭解)
2. Struts2框架的值棧(值棧、存入值、取值)
3. OGNL的特殊符號
案例一:使用Struts2框架查詢所有的客戶功能
需求分析
1. 使用Struts2框架查詢所有的客戶功能
技術分析之OGNL表示式概述(瞭解)
1. OGNL是Object Graphic Navigation Language(物件圖導航語言)的縮寫 * 所謂物件圖,即以任意一個物件為根,通過OGNL可以訪問與這個物件關聯的其它物件 * 通過它簡單一致的表示式語法,可以存取物件的任意屬性,呼叫物件的方法,遍歷整個物件的結構圖,實現欄位型別轉化等功能。它使用相同的表示式去存取物件的屬性 2. Struts2框架使用OGNL作為預設的表示式語言 * OGNL是一種比EL強大很多倍的語言 * xwork提供 OGNL表示式 * ognl-3.0.5.jar 3. OGNL 提供五大類功能 * 支援物件方法呼叫 * 支援類靜態的方法呼叫和值訪問 * 訪問OGNL上下文(OGNL context)和ActionContext * 支援賦值操作和表示式串聯 * 操作集合物件 4. 測試的程式碼 // 訪問物件的方法 @Test public void run1() throws OgnlException{ OgnlContext context = new OgnlContext(); // 獲取物件的方法 Object obj = Ognl.getValue("'helloworld'.length()", context, context.getRoot()); System.out.println(obj); } // 獲取OGNL上下檔案的物件 @Test public void run3() throws OgnlException{ OgnlContext context = new OgnlContext(); context.put("name", "美美"); // 獲取物件的方法 Object obj = Ognl.getValue("#name", context, context.getRoot()); System.out.println(obj); } // 從root棧獲取值 @Test public void demo3() throws OgnlException{ OgnlContext context = new OgnlContext(); Customer c = new Customer(); c.setCust_name("haha"); context.setRoot(c); String name = (String) Ognl.getValue("cust_name", context, context.getRoot()); System.out.println(name); }
技術分析之在Struts2框架中使用OGNL表示式
1. Struts2引入了OGNL表示式,主要是在JSP頁面中獲取值棧中的值 2. 具體在Struts2中怎麼使用呢?如下步驟 * 需要先引入Struts2的標籤庫 > <%@ taglib prefix="s" uri="/struts-tags" %> * 使用Struts2提供的標籤中的標籤 > <s:property value="OGNL表示式"/> 3. 在JSP頁面使用OGNL表示式 * 訪問物件方法 <s:property value="'hello'.length()"/>
技術分析之值棧的概述
1. 問題一:什麼是值棧?
* 值棧就相當於Struts2框架的資料的中轉站,向值棧存入一些資料。從值棧中獲取到資料。
* ValueStack 是 struts2 提供一個介面,實現類 OgnlValueStack ---- 值棧物件 (OGNL是從值棧中獲取資料的 )
* Action是多例的,有一起請求,建立Action例項,建立一個ActionContext物件,代表的是Action的上下文物件,還會建立一個ValueStack物件。
* 每個Action例項都有一個ValueStack物件 (一個請求 對應 一個ValueStack物件 )
* 在其中儲存當前Action 物件和其他相關物件
* Struts 框架把 ValueStack 物件儲存在名為 “struts.valueStack” 的請求屬性中,request中 (值棧物件 是 request一個屬性)
* ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");
技術分析之值棧的內部結構
2. 問題二 : 值棧的內部結構 ?
* 值棧由兩部分組成
> root -- Struts把動作和相關物件壓入 ObjectStack 中--List
> context -- Struts把各種各樣的對映關係(一些 Map 型別的物件) 壓入 ContextMap 中
* Struts會預設把下面這些對映壓入ContextMap(context)中
* 注意:request代表的是Map集合的key值,value的值其實也是一個Map集合。
> parameters: 該 Map 中包含當前請求的請求引數 ?name=xxx&password=123
> 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中還存在 request、 session、application、 attr、 parameters 物件引用
> OGNL表示式訪問值棧中的資料
* 訪問root中資料時 不需要 #
* 訪問 request、 session、application、 attr、 parameters 物件資料 必須寫 #
> 操作值棧 預設指 操作 root 元素
技術分析之值棧的建立和ActionContext物件的關係
3. 問題三 : 值棧物件的建立,ValueStack 和 ActionContext 是什麼關係?
* 值棧物件是請求時建立的
* ActionContext是繫結到當前的執行緒上,那麼在每個攔截器或者Action中獲取到的ActionContext是同一個。
* ActionContext中存在一個Map集合,該Map集合和ValueStack的context是同一個地址。
* ActionContext中可以獲取到ValueStack的引用,以後再開發,使用ActionContext來獲取到值棧物件
技術分析之獲取到值棧的物件
4. 問題四 : 如何獲得值棧物件
* 獲得值棧物件 有三種方法
* ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
* ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
* ValueStack vs3 = ActionContext.getContext().getValueStack();
技術分析之向值棧中儲存資料
5. 問題五: 向值棧儲存資料 (主要針對root棧)
> valueStack.push(Object obj);
* push方法的底層呼叫root物件的push方法(把元素新增到0位置)
> valueStack.set(String key, Object obj);
* 原始碼獲取map集合(map有可能是已經存在的,有可能是新建立的),把map集合push到棧頂,再把資料存入到map集合中。
> 在jsp中 通過 <s:debug /> 檢視值棧的內容
技術分析之從值棧中獲取值
6. 問題六: 在JSP中獲取值棧的資料
* 總結幾個小問題:
> 訪問root中資料 不需要#
> 訪問context其它物件資料 加 #
> 如果向root中存入物件的話,優先使用push方法。
> 如果向root中存入集合的話,優先要使用set方法。
* 在OgnlContext中獲取資料
> 在Action中向域物件中存入值
> 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"/>
6.1 程式碼如下
<!--
// vs.push("美美");
// 獲取到棧頂的值
<s:property value="[0].top"/>
-->
<!--
// 棧頂是map集合,通過key獲取值
vs.set("msg", "小鳳");
<s:property value="[0].top.msg"/>
-->
<!--
vs.push(user);
// 棧頂放user物件
<s:property value="[0].top.username"/>
<s:property value="[0].top.password"/>
// [0].top 關鍵字是可以省略的 findValue()
<s:property value="username"/>
-->
<!--
vs.set("user", user);
<s:property value="[0].top.user.username"/>
<s:property value="[0].top.user.password"/>
// 省略關鍵字
<s:property value="user.username"/>
-->
<!--
// 在ValueStack1Action提供了成員的屬性
private User user = new User("小澤","456");
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
User user = new User("小蒼","123");
vs.set("user", user);
// 從棧頂開始查詢,找user的屬性,顯示名稱 返回的小蒼
<s:property value="user.username"/>
// [1].top獲取ValueStack1Action [1].top.user返回user物件 [1].top.user.username獲取物件的屬性名稱
<s:property value="[1].top.user.username"/>
-->
<!--
棧頂是list集合
vs.push(ulist);
<s:property value="[0].top[0].username"/>
<s:property value="[0].top[1].username"/>
-->
<!--
vs.set("ulist", ulist);
<s:property value="ulist[0].username"/>
-->
<!-- 迭代的標籤
屬性
* value 要迭代的集合,需要從值棧中獲取
* var 迭代過程中,遍歷的物件
* var編寫上,把迭代產生的物件預設壓入到context棧中,從context棧取值,加#號
* var不編寫,預設把迭代產生的物件壓入到root棧中
for(User user:ulist){}
// 編寫var的屬性
<s:iterator value="ulist" var="u">
<s:property value="#u.username"/>
<s:property value="#u.password"/>
</s:iterator>
// 沒有編寫var關鍵字
<s:iterator value="ulist">
<s:property value="username"/>
<s:property value="password"/>
</s:iterator>
-->
<!-- 從context棧中獲取值,加#號
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("msg", "美美");
request.getSession().setAttribute("msg", "小風");
<s:property value="#request.msg"/>
<s:property value="#session.msg"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.msg"/>
-->
<!-- 在JSP頁面上,檢視值棧的內部結構 -->
<s:debug></s:debug>
技術分析之EL表示式也會獲取到值棧中的資料
7. 問題七:為什麼EL也能訪問值棧中的資料?
* StrutsPreparedAndExecuteFilter的doFilter程式碼中 request = prepare.wrapRequest(request);
> 對Request物件進行了包裝 ,StrutsRequestWrapper
> 增強了request的 getAttribute
Object attribute = super.getAttribute(s);
if (attribute == null) {
attribute = stack.findValue(s);
}
> 訪問request範圍的資料時,如果資料找不到,去值棧中找
> request物件 具備訪問值棧資料的能力 (查詢root的資料)
總結OGNL表示式的特殊的符號
1. # 符號的用法
* 獲得contextMap中的資料
> <s:property value="#request.name"/>
> <s:property value="#session.name"/>
> <s:property value="#application.name"/>
> <s:property value="#attr.name"/>
> <s:property value="#parameters.id"/>
> <s:property value="#parameters.name"/>
* 構建一個map集合
* 例如:
* <s:radio name="sex" list="{'男','女'}"></s:radio>
* <s:radio name="sex" list="#{'0':'男','1':'女'}"></s:radio>
2. % 符號的用法
* 強制字串解析成OGNL表示式。
> 例如:在request域中存入值,然後在文字框(<s:textfield>)中取值,現在到value上。
> <s:textfield value="%{#request.msg}"/>
* { }中值用''引起來,此時不再是ognl表示式,而是普通的字串
> 例如:<s:property value="%{'#request.msg'}"/>
3. $ 符號的用法
* 在配置檔案中可以使用OGNL表示式,例如:檔案下載的配置檔案。
<action name="download1" class="cn.itcast.demo2.DownloadAction">
<result name="success" type="stream">
<param name="contentType">${contentType}</param>
<param name="contentDisposition">attachment;filename=${downFilename}</param>
</result>
</action>