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