1, 當Action設置了某個屬性后,Struts將這些屬性封裝一個叫做Struts.valueStack的屬性里。獲取valueStack對象: ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack"); 調(diào)用ValueStack 的vs.findValue("books")方法(books為Action中的屬性); 2, struts2的Action類是一個普通的POJO類(通常包含一個無參的execute方法)從而很 好的重用代碼。 4,struts2通常直接使用Action來封裝HTTP請求參數(shù),所以Action中要定義與請求參數(shù)對應的屬性,并且為該屬性提供相應的 getter和setter方法。 5,即使Action需要處理的請求name和pass兩個HTTP請求參數(shù),Action類也可以不包含name和pass屬性,因為系統(tǒng)是通過對應的 getter和setter方法來處理請求參數(shù)。而不是通過屬性來處理請求參數(shù)的。所以Action類是否包含name和pass屬性不重要, 重要的是需要setter和getter方法。 6,Action類的屬性,不僅可以封裝請求參數(shù),還可以用于封裝處理結果,通過Struts2標簽來輸出對應的屬性值。如 <s:Property value="tip">。 7,ActionContext類。Struts2的Action并未直接與任何Servlet api耦合,從而更加方便測試該Action(可以通過脫離web容器測試Action)。但是對于Web應用的控制器來說,不訪問Servlet api 幾乎是不能的。例如跟蹤HTTP session狀態(tài)等。訪問的Servlet Api 就 是HttpServeltRequest、HttpSession、ServletContext,這三個類分別jsp內(nèi)置對象中的request、session、application。Web應用中提供了一個ActionContext類,Struts2的Action可以通過該類來訪問Servlet api。 該類的ActionContext提供getContext方法得到ActionContext實例, 該類的方法: ①Object get(Object key),該方法類似于HttpServletRequest的getAttribute(String name)方法; ②Map getApplication(),返回Map對象,該對象模擬了應用的ServletContext的實例 ③static ActionContext getContext(),靜態(tài)方法,獲得系統(tǒng)提供的ActionContext實例。 ④Map getParameters()獲取所有的請求參數(shù),類似于調(diào)用HttpServletRequest對象的getParammeterMap方法。 ⑤Map getSession()該Map對象模擬了HttpSession實例。 ⑥void setApplication(Map application)直接傳入一個Map實例,將該Map實例的key-value對轉換成application的屬性名、屬性值。類似的還有setSession(Map session) ⑦put(Object key, Object value)直接為HttpServletRequest設置屬性。相當于request.setAttribute(key,value).可通過EL表達式輸出。 8,ServletActionContext類(是ActionContext類的子類)。 雖然Struts2提供了ActionContext來訪問Servlet Api,但是這種訪問畢竟不能直接獲得Servlet Api實例,為了Action中 直接訪問Servlet api,Struts2提供了如下的接口:ServletContextAware、ServletRequestAware、ServletResponseAware 。如果Action實現(xiàn)這些接口,能分別直接訪問用戶請求的ServletContext、HttpServletRequest、HttpServletResponse實例。 并且,為了直接訪問Servlet api。Struts2提供了一個ServletAction類。通過ServletActionContext類可以更加方便的地直接訪問Servlet api。這類的主要方法(全是static): ①getActionContext(HttpServletRequest req)得到當前的ActionContext實例。 ②getActionMapping()得到ActionMapping實例(得到 action mapping為context)。 ③getRequest()得到HttpServletRequest實例(Gets the HTTP servlet request object)。 ④getResponse()得到HttpServletResponse實例(Gets the HTTP servlet response object.) ⑤getServletContext()得到ServletAction實例(Gets the servlet context.) ⑥getValueStack(HttpServletRequest req)得到ValueStack實例。 ⑦setRequest(HttpServletRequest request)(Sets the HTTP servlet request object)相應的有setResponse(HttpServletResponse response)、setServletContext(ServletContext servletContext)。 9,雖然可以在Action類獲取HttpServletResponse,但如果希望通過HttpServletResponse來生成服務器響應是不可能的,因為Action只是控制器(它并不直接對瀏覽器生成任何相應)。即如果在Action中寫如下代碼:response.getWriter().println("hello world"); 是沒有意義的。 10,對于使用Struts2框架的應用而言,盡量不要讓超級鏈接鏈接到某個視圖資源, 因為這種方式增加了額外的風險,推薦將所有請求都發(fā)給Struts2框架,讓該框架來處理用戶的請求, 即使是簡單的超級鏈接。 11,邏輯視圖名是指:Action返回的字符串;物理視圖是指:頁面的實際名稱。 Struts2通過配置邏輯視圖名和物理視圖之間的映射關系,一旦系統(tǒng)收到Action返回的某個邏輯視圖,系統(tǒng)就會把相應的物理視圖呈現(xiàn)給用戶。 12,默認值:如果配置<result../>元素時沒有指定location參數(shù),系統(tǒng)將會把<result..>...<result../>中間的字符串當成實際視圖資源。如果沒有配置parse參數(shù),則默認值為true(該參數(shù)指定實際視圖名是否可以使用OGNL表達式);如果沒有指定name屬性則默認值為Struts2的默認處理結果類型(dispacher). 13,歸納起來,Struts2內(nèi)建支持結果類型如下(14): ①chain結果類型:Action鏈式處理結果類型。 ②chart結果類型:用于整合JFreeChart的結果類型。 ③dispatch結果類型:用于jsp整合的結果類型。 ④freemarker結果類型:FreeaMarker整合的結果類型。 ⑤httpheader結果類型:用于控制Http行為的結果類型。 ⑥jasper結果類型:用于JasperReports整合的結果類型。 ⑦jsf結果類型:用于整合JSF整合的結果類型。 ⑧redirect結果類型:用于直接跳轉到其他的URI的結果類型。 ⑨redirectAction結果類型:用于直接跳轉到其他的Action的結果類型。 ⑩stream結果類型:用于向瀏覽器返回一個InputStream(一般用于文件下載)。 ⑾tiles結果類型:用于與Tiles整合的結果類型。 ⑿velocity結果類型:用于與Velocity整合的結果類型。 ⒀xslt結果類型:用于與XML/XSLT整合的結果類型。 ⒁plainText結果類型:用于顯示某個頁面的原始代碼的結果類型。 14,【redirect】結果類型。 這種結果類型與dispatch結果類型相對,dispatch結果類型是將請求Forward(轉發(fā)) 到指定的jsp資源。而redirect結果類型,則意味著將請求Redirect(重定向) 到指定的視圖資源。 dispatch結果類型與redirect結果類型的差別就是轉發(fā)和重定向的差別: 重定向會丟失所有的請求參數(shù)和請求屬性---當然也會丟失Action的處理結果。 使用redirect結果類型的效果是:系統(tǒng)將調(diào)用HttpServletResponse的sendRedirect(String)方法來重定向指定的視圖資源,這種重定向的效果就是重新產(chǎn)生一個請求。所以所有的請求參數(shù)、請求屬性、Action實例和Action中封裝的屬性全部丟失。 15,【redirectAction】結果類型. 使用redirectAction結果類型時,系統(tǒng)將重新生成一個新的請求, 只是該請求的URI不是一個具體的試圖資源,而是一個Action。因此前一個Action處理結果 ,請求參數(shù),請求參數(shù)都會丟失。 16,除了可以通過通配符來配置Action(result),還可以使用OGNL表達式,這種 用法允許讓請求參數(shù)來決定結果。如: <action name="save" class="......." method="save"> <result name="input">/..jsp</result> <result type="redirect" >edit.action?skillName=${currentSkill.name}</result> </action> 對于上面的表達式語法,要求對應的Action實例里應該包含currentSkill屬性,且currentSkill屬性必須包含name屬性--否則,${currentSkill.name}表達式為null。 17,模型驅動: 對于Struts1的ActionForm對象而言。它的唯一作用就是封裝請求參數(shù),當Struts1攔截到用戶的請求后,Struts1負責將請求參數(shù)封裝成ActionForm對象。 如果Struts2的開發(fā)者懷念這種開發(fā)方式,則可以使用Struts2提供的模型驅動模式, 這種模式也通過專門的JavaBean來封裝請求參數(shù)。 相比于Struts1的Action類,Struts2的Action承擔了太多的責任,既用于封裝來回請求的參數(shù),也保護了控制邏輯---這種模式實在不太清晰。出于清晰的考慮,應該采用單獨的Model實例來封裝請求參數(shù)和處理結果,這就是所謂的模型驅動。 作用:Struts2的模型對象可以封裝更多的信息,它不僅可以封裝用戶的請求參數(shù),而且還可以封裝Action的處理結果。用單獨的JavaBean實例來貫穿MVC流程。 使用模型驅動時,Action必須實現(xiàn)ModelDriven接口,且必須實現(xiàn)getModel方法, 該方法用于把Action和與之相對應的Model實例關聯(lián)起來。 簡單的說,模型驅動使用單獨的VO(值對象)來封裝請求參數(shù)和處理結果。 18,【屬性驅動】: 使用屬性(Property)作為貫穿MVC流程的信息攜帶者,當然屬性無法獨立存在,他必須依附于一個對象,這個對象就是Action實例, 簡單的說,屬性驅動使用Action實例來封裝請求參數(shù)和處理結果。 19,Struts2的【處理異常機制】: 在execute方法中手動捕捉異常,當捕捉到特定的異常時,返回特定的視圖--但是 這種方式很是繁瑣,需要在execute中書寫大量的catch塊,最大的缺點 還在于異常與代碼耦合,一旦需要改變異常處理方式,必須修改代碼! Struts2提供了一種聲明式的異常處理方式。 在輸出錯誤信息的jsp頁面,有兩種輸出方式: ①通過struts2標簽輸出異常對象的message屬性。<s:property value="exception.message"/>。 ②通過struts2標簽輸出堆棧信息。<s:property value="exceptionStack"/>。 注意:全局異常映射的result屬性通常不要使用局部結果,局部異常映射的result屬性可以使用全局結果,也可以不使用。 20,對于WEB應用而言,所有的請求參數(shù)都是字符串類型的。 21,【類型轉換器】: struts2的類型轉換器實際上是基于OGNL實現(xiàn)的,在OGNL項目中有一個TypeConverter接口,因其實現(xiàn)的方法過于麻煩,所以OGNL項目還提供了一個該接口的實現(xiàn)類:DefaultTypeConverter,通過繼承該類來實現(xiàn)自己的轉換器。 實現(xiàn)自定義的類型轉換需要重寫DefaultTypeConverter類的convertValue方法。 22,上面的類型轉換器都是基于OGNL的DefaultTypeConverter類實現(xiàn)的,基于 該類實現(xiàn)類型轉換器的時候時,將字符串轉化成符合類型要通過convertValue方法實現(xiàn) 因此我們必須先通過toType參數(shù)來判斷轉換的方向,然后分別實現(xiàn)不同的轉換邏輯。 為了簡化類型轉換的實現(xiàn),struts2提供了一個StrutsTypeConverter抽象類(基于struts2的類轉換器) 這個抽象類是DefaultTypeConverter類的子類. 23,對于以上的類型轉換,我們一直只處理字符串數(shù)組的第一個元素---我們都假設請求參數(shù)是單個值。實際上,必須考慮請求參數(shù)是字符數(shù)組的情形, 假設用戶信息的請求參數(shù),名稱都是user。那么這兩個請求參數(shù)必須通過getParameterValues方法來獲取參數(shù)。此時user請求參數(shù)必須是數(shù)組類型,或者List類型(實際上,List和數(shù)組是完全相通的)。 24,因為struts2內(nèi)建的OGNL表達式的支持,那么可以用另一種方式將請求參數(shù)轉換成復合類型,如(JSP頁面中): <input type=text name="user.name"/>,<input type=text name="user.pass"/>這樣就不需要轉換器了。 通過這種方式也可以把字符串轉換成復合類型。但需要注意以下幾點: ①因為struts2是需要直接創(chuàng)建一個復合類(User類)的實例,因此系統(tǒng)必須為該復合類構建一個無參的構造方法。 ②如果希望使用user.name請求參數(shù)的形式為Action實例的user屬性和pass屬性賦值,則必須為user屬性對應的復合類型提供setName方法,因為struts2是通過該方法類為屬性賦值的。當然Action類還應該包含setUser方法。 25,表單元素enctype屬性指定的是表單數(shù)據(jù)的編碼方式。屬性有如下3個值: ①application/x-www-form-urlencoded:這是默認的編碼方式。它只處理表單中的value屬性值,采用這種編碼方式會將表單域的值處理成URL編碼方式。 ②multipart/form-data:這種編碼方式會以二進制流的方式來處理表單數(shù)據(jù),這種編碼方式會把文件域指定的文件內(nèi)容也封裝到請求參數(shù)里。 ③text/plain:這種編碼方式當表單的action的屬性為mailto:URL的形式時比較方便,這種方式主要適用于直接通過表單發(fā)送郵件的方式。 26,通過Action在jsp頁面輸出提示信息,我們可以 ①在Action中添加一個屬性(通過setXx方法設置屬性值),然后通過struts2的標簽(<s:properties value="xx"/>)在jsp頁面輸出。 ②通過ActionContext類來處理,如:ActionContext.getContext.put(key,value);然后通過EL表達式進行輸出。 27,在Form表單中action屬性的值要得到【上下文路徑】: ①<%=request.getContextPath()%> ②還可以通過EL表達式得到 :${pageContext.request.contextPath} 28,得到【ValueStack】的對象有哪幾種方法: ①ServletActionContext類中的方法:static getValueStack(HttpServletRequest req)【Gets the current value stack for this request】; ②ActionContext類中的方法:getValueStack()【Gets the OGNL value stack.】; ③ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack"); (request.getAttribute()返回一Object類型) 29,【攔截器】。在默認的情況下,如果我們?yōu)槟硞€Action定義了攔截器,則這個攔截器會攔截Action的所有方法??赡茉谟行┣闆r下,我們無需攔截器所有的方法,只需要攔截某些方法,此時就需要struts2攔截器的方法過濾特性。 30,struts2的【校驗】,可以繼承ActionSupport類重寫validate方法,利用ActionSupport的addFieldError方法把錯誤信息通過key保存起來,在jsp頁面通過struts2標簽的fielderror屬性輸出錯誤信息。注意:struts2的校驗在配置action的時候需要提供輸入頁面(就是<result name="input">)。這是對action中的所有方法進行校驗。 如果要對action中指定的方法進行校驗,把validate方法名改為:validateXxx,其中Xxx是需要校驗的指定方法名。 31,輸入校驗的流程: ①類型轉換器把請求參數(shù)進行類型轉換,并把轉換后的值賦給action中的屬性。 ②如果在執(zhí)行類型轉換的過程中出現(xiàn)異常,系統(tǒng)會將異常信息保存到ActionContext中,conversionError攔截器將異常信息 添加到fieldErrors中。不管類型轉換是否失敗都會轉入第三步。 ③系統(tǒng)通過反射技術調(diào)用action中的validateXxx方法。 ④再調(diào)用validate方法。 ⑤如果fieldErrors中存在錯誤信息,系統(tǒng)自動將請求轉發(fā)至input視圖。如果沒有錯誤信息將執(zhí)行action中的方法。 注意:如果validate方法里沒有問題,卻返回input頁面,可能是類型轉換有問題。所以返回input視圖有兩種原因(類型轉換有問題或校驗出錯). 32,基于xml配置方式對action內(nèi)所有的方法進行校驗,xml文件的命名規(guī)則是:ActionClassName-validation.xml 如果只需要對action內(nèi)指定的方法進行校驗,則xml文件的命名規(guī)則為:ActionClassName-ActionName-validation.xml。其 中ActionName(action的邏輯名稱)。它的配置一般用通配符(有助于實驗)。 ①基于xml配置方式的校驗,如果ActionClassName-validation.xml、ActionClassName-ActionName-validation.xml同時存在則把兩個文件匯總,在進行校驗。如果兩個xml文件的校驗規(guī)則起了沖突則執(zhí)行后面的xml文件。 ②如果action繼承了另一個action則先找到父action校驗文件,在找到子action校驗文件,再把4(每個action都有指定方法名或非指定方法名)個文件匯總。 33,【國際化】。國際化按范圍分為:全局、action、package的范圍的資源文件。Properties文件命名的規(guī)則為:xxx_language_country.properties(xxx為用戶定義的名字,第二部分為語言類別。) Ⅰ定義好了國際化文件后,需要在struts.xml文件配置<constants name="struts.custom.i18n.resources" value="國際化文件的名稱(xxx)">[這是定義全局的國際化資源文件],可以在jsp頁面顯示國際化信息<s:text name="key"/>。 Ⅱ也可以通過action類繼承ActionSupport類,再調(diào)用個getText方法的資源文件的key(getText("key")).然后可以通過EL表達式在jsp頁面輸出。 Ⅲ也可以通過struts2的表單標簽的key屬性。如<s:textfield key="key"/>或<s:textarea key="key"/> 輸出帶有占位符的國際化信息: ①<s:text name="key"><s:param>....</s:param>..</s:text> ②通過ActionSupport類的getText(String key,String[] str)或者getText(String key,List list) 34,包范圍的國際化資源文件, 在大型的應用程序中,整個應用有大量的內(nèi)容需要國際化,如果我們把國際化的內(nèi)容放置在全局資源屬性文件中,顯然會導致資源文件變得過于龐大、臃腫,不便于維護,這個時候我們需要針對不同的模塊,使用包范圍來組織國際化文件。 在java的包下創(chuàng)建名為:package_language_country.properties的資源文件,package為固定寫法,language_country是對應的語言類別。處于該包及子包都可以訪問該資源文件。當在包范圍找不到對應的資源文件,然后會在全局范圍內(nèi)查找。 35,Action范圍的資源文件。在Action所在的路徑創(chuàng)建名為:ActionClassName_language_country.properties 如果同時存在全局、package、Action范圍的國際化資源文件,系統(tǒng)搜索的順序是:Action-->package-->全局范圍。 36,以上三種配置有的是基于配置的國際化資源文件。我們也可以通過無配置的方式進行直接訪問某個資源文件。 通過struts2標簽,如: <s:i18n name="xxx"> <s:text name="key"> </s:i18n> 其中xxx是全局范圍文件的名稱的前綴。 如果直接想訪問包范圍的國際化資源文件 <s:i18n name="com.johnny.action.package"> <s:text name="key"> </s:i18n> 其中package是固定寫法。 37,OGNL表達式(Object Graphic Navigation Language對象圖導航語言),當struts2接受一個請求時,會迅速創(chuàng)建ActionContext、ValueStack、action,然后把action存放在ValueStack,所以OGNL表達式可以迅速訪問action實例的屬性。 OGNL表達式一般要配合Struts2標簽使用。 在struts2中,EL表達式只能訪問OgnlValueStack的root里的屬性。即action的屬性(因為action的屬性放在OgnlValueStack的root屬性里)。利用OGNL表達式創(chuàng)建List/Map對象,<s:set var="" value="" scope=""/>scope指定變量的被放置的范圍,可以為application、session、request、page和action。如果沒有設置屬性,則默認為OGNLContext(OGNL上下文)中,如果在OGNLContext訪問時不用#,如果scope為request....中,則需要用#。value:賦給變量的值,如果沒有該屬性,則將ValueStack的棧頂?shù)闹蒂x給變量。 38,防止表單重復提交,首先要有struts的token標簽。再使用系統(tǒng)的攔截器。 |
|