Struts2第三天
文章目錄
課程回顧:Struts2框架的第二天
1. Servlet的API
* ActionContext對象
* ServletActionContext對象(提供靜態方法)
2. 結構類型的跳轉
* 全局結果
* <global-results>
<result name="success" type="redirect">/demo1/suc.jsp</result>
* </global-results>
* 局部結果,type屬性
3. 數據的封裝
* 屬性驅動方式
* 模型驅動方式
4. 攔截器(自定義攔截器)
*只能對Action的方法進行攔截
*在struts.xml配置中的action中引入自定義攔截器時,還需要引入默認攔截器defaultStack
今天的課程內容
1. OGNL表達式(瞭解)(主要是使用它來取值棧)
2. Struts2框架的值棧(值棧、存入值、取值)
3. OGNL的特殊符號
**案例一:使用Struts2框架查詢所有的客戶功能 **
需求分析
1. 使用Struts2框架查詢所有的客戶功能
* 現在:Struts2框架提供值棧,把查詢到的數據,存入到值棧中,轉發到JSP頁面上
在JSP頁面上就可以從值棧中獲取值,提供標籤
2.查詢所有的客戶 List
request域對象,轉發JSP頁面
Struts2框架提供值棧,list存入到值棧中,轉發到JSP頁面,使用OGNL表達式從值棧中獲取值
技術分析之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的標籤庫(在<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">前邊)
<%@ taglib prefix="s" uri="/struts-tags" %>
* 使用Struts2提供的標籤中的標籤
* 默認情況下指從值棧中獲取值的value=" "引號中編寫的就是Ognl表達式 ,從值棧中獲取值,找到則返回值
* 若無則返回空字符串(網頁面上什麼都沒有)
<s:property value="OGNL表達式(例如:#name)"/>
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 中
>如果從root棧中獲取值,OGNL表達式默認情況下不寫#,若是從context棧中獲取值默認需要#
>只要說操作值棧,默認就是指操作root棧,context棧默認是struts2框架幫忙壓好的
* 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棧)
**Push**
> valueStack.push(Object obj);
* push方法的底層調用root對象的push方法(把元素添加到0位置)
*用push存入值時,將上一個值壓入到下邊,當前存入的值佔用root棧頂0位置。
**Set**
set(key,obj)
> valueStack.set(String key, Object obj);
* 源碼獲取map集合(map有可能是已經存在的,有可能是新創建的),把map集合push到棧頂,再把數據(key和obj)存入到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"/>
(在JSP上編寫,若不加.top表示獲取root棧中全部值,若是value="[1].top"表示獲取棧中第二個對象,value="[2].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的數據)
>表達式在JSP頁面上可以使用EL和JSTL標籤庫取值,用裝飾者模式,連接池,全站編碼
引入標籤庫:<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
jsp中編寫代碼 <c:forEach items="${ulist}" var="user">
${user.username }--${user.password }
</c:forEach>
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>