課程回顧:Struts2框架的次日session
1. Servlet的API * ActionContext對象 * ServletActionContext對象 2. 結構類型的跳轉 * 全局結果 * 局部結構,type屬性 3. 數據的封裝 * 屬性驅動方式 * 模型驅動方式 4. 攔截器(自定義攔截器)
今天的課程內容app
1. OGNL表達式(瞭解) 2. Struts2框架的值棧(值棧、存入值、取值) 3. OGNL的特殊符號
需求分析框架
1. 使用Struts2框架查詢全部的客戶功能
技術分析之OGNL表達式概述(瞭解)jsp
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()"/>
技術分析之值棧的概述this
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");
技術分析之值棧的內部結構spa
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來獲取到值棧對象
技術分析之獲取到值棧的對象debug
4. 問題四 : 如何得到值棧對象 * 得到值棧對象 有三種方法 * ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack"); * ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); * ValueStack vs3 = ActionContext.getContext().getValueStack();
技術分析之向值棧中保存數據code
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>