Struts2是一個在WebWork框架基礎上發展起來開源MVC框架。html
StrutsPrepareAndExecuteFilter本質上是一個過濾器,配置在web容器中,該過濾器做爲Struts框架的啓動項,將符合擴展名要求的請求轉發給Struts框架處理,將處理結果返回給瀏覽器。java
對於那些符合擴展名要求的請求,StrutsPrepareAndExecuteFilter直接將其轉發給Struts框架,沒有沿着過濾器鏈向下傳遞,因此配置在其後的過濾器不起做用。那些不符合擴展名要求的請求將沿過濾器鏈正常執行。web
StrutsPrepareAndExecuteFilter(爲便於表述,如下稱做struts啓動項)將符合擴展名要求的請求轉發到Struts框架中,首先生成一個ActionMapping,該ActionMapping表明了須要調用的Action對象,基於ActionMapping返回一個ActionProxy,proxy經過配置管理器查詢配置文件struts.xml,返回一個ActionInvocation對象,由Invocation對象具體調用action中的方法。在action方法調用前以及調用後都會執行一系列攔截器,最後將響應結果反饋給瀏覽器。數組
Action是Struts2框架的控制器,將請求分發給響應的業務邏輯。每請求一次,建立一個對象。瀏覽器
建立Action對象時推薦繼承ActionSupport,由於ActionSupport實現了不少接口,繼承該類能夠擁有國際化、數據驗證等功能。Struts2也支持不繼承任何類的POJO對象,只能實現一些簡單的功能,如表單注入,實現類型轉化、數據驗證、攔截器、國際化、文件上傳等特殊功能時必須繼承ActionSupport。安全
在請求url中加入方法名以訪問Action中指定方法的機制。
高版本的Struts禁用了動態Action,可使用通配符,動態地調用action中的方法:服務器
struts.xml是Action對象的默認配置文件。
格式:session
<struts> <package name="resultList"extends="struts-default"abstract="true"> <global-results> <result name="">/xxx.jsp</result> </global-results> </package> <include file="newFile.xml"></include> <contant name="struts.devMode"value="true"></constant> <package name="packageName"extends="struts-default"> <global-results> <result name="">xxxx</result> </global-results> <action name="url*"class="完整包名{1}"> <result name="res" type="">/xxx.jsp</result> <result name=""type="redirect"> <param name="location">/xxx.jsp</parame> <param name="key">value</param> </result> <result name=""type="redirectAction"> <param name="actionName">actionName</param> <param name="key">value</param> </result> </action> </package>
</struts>
標籤說明:數據結構
爲不一樣的模塊設定不一樣的配置文件,最後集中到默認的配置文件struts.xml中。app
設定struts框架的屬性。
name:設定一個名稱,當action對象返回的字符串與該名稱值相同時,返回對應的文件(如jsp、html)給瀏覽器,name默認值爲success。返回文件採用以「/」開頭相對於項目的路徑形式。
type:設定頁面跳轉的類型:
在Action中定義與表單輸入同名的屬性,底層自動調用setter方法將輸入注入到屬性中。
建立一個封裝了表單輸入的類,在Action中引用該類的對象,併爲對象提供getter/setter方法。要求表單輸入必須指明所屬的對象,實現方式將表單輸入的名稱定義爲「obj.name」,obj是Action中封裝對象的引用變量。
底層實現過程:域模型爲表單輸入指明瞭所屬的對象,Action對象建立完成之後,調用getter方法,若是存在對象,則返回,不存在,
接着調用setter方法建立對象,對象建立完成之後,調用對象中的setter方法爲對象屬性賦值。
若是表單輸入能夠被封裝到一個類的多個對象中,那麼可使用域模型將輸入注入到向Action對象的List集合中,實現以下:
在表單輸入中使用List集合引用變量與下標給表單輸出指定所屬的對象:
<input type="text"name="list[0].name">
Action對象實現ModelDriven接口中的getModel方法,getModel方法負責接收表單輸入,將輸入注入到實體對象中,並返回實體對象不須要在表單輸入中指明將要注入的對象,即表單輸入名稱前再也不加對象的引用變量。
Struts2提供了Map類型的request、session、application,經過ActionContext對象獲取,首先獲取ActionContext對象:
ActionContext context = ActionContext.getContext();
獲取request、session、application對象的通用方法,以request爲例:
Map<Object Object> request=context.get("request");
獲取session對象的專有方法:
Map<Object,Object> session=context.getSession();
獲取application對象的專有方法:
Map<Object,Object> application=context.getApplication();
Struts提供了一個ServletActionContext類,利用該類的靜態方法能夠獲取request\session\application對象:
HttpServletRequest request=ServletActionContext.getRequest(); HttpSession session=request.getSession(); ServletContext servletContext=ServletActionContext.getServletContext();
一個線程,一個ActionContext;一個Action,一個ActionContext,ActionContext是線程安全的。
對應於OGNL的根,使用OGNL表達式能夠直接獲取其中的數據。數據結構:
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.push(Object obj);//將數據放到棧頂 valueStack.set(Object key,Object value);//若是頂層存在Map集合,則放入Map集合中;不存在,建立一個,再將數據放入其中
valueStack.peek();// 獲取棧頂元素 valueStack.pop();// 獲取並刪除該棧頂元素
若是棧中的對象包含多個屬性,獲取屬性值時不須要經過對象引用的形式,能夠直接使用屬性名,系統從棧頂開始檢索,找到第一個屬性名稱相同的屬性,將其值返回。
4.request、session、application(Map類型的集合):在OGNL中,採用#request.key獲取屬性值。
5.parameters:存放請求參數,經過#parameters.name獲取請求參數的值。
6.attr:不指定屬性的範圍,能夠經過#attr.key獲取屬性的值,檢索順序request、session、application。
7.action對象:獲取其中的數據<s:property value="#action.varName"/>。
Object Graph Navigation Language,能夠自動導航對象的結構,訪問對象,爲對象賦值。
OGNL的核心是OGNL上下文,OGNL上下文至關於一個Map類型的容器,能夠存儲任何類型的數據。OGNL分層次,有一個區域是OGNL的根,能夠直接訪問根中數據,訪問其餘區域的數據須要在前面加「#」。
當指定內容有可能被執行環境當作字符串時,告知指定內容是OGNL表達式。
@完整類名@屬性名::訪問靜態變量。
@完整類名@method():訪問靜態方法。
Struts默認狀況下不容許訪問靜態方法,如需訪問須要在配置文件中作以下設置:
<constant name="struts.ognl.allowStaticMethodAccess"value="true"/>
訪問java.lang.Math中的靜態方法,能夠由@java.lang.Math@method()簡寫爲@@method()。
arr[index]:獲取數組指定索引位置的元素。
arr.length:獲取數組的長度。
獲取集合中知足條件的對象,針對行的操做,返回一個集合。
操做方法:
建立攔截器對象時,若是直接實現Interceptor接口,需實現其中的三個方法,而這三個方法在實際中並非所有須要的。AbstractInterceptor是一個抽象類,實現了Interceptor接口,實現了init、destroy方法,所以自定義攔截器對象時,繼承該方法,只實現intercept方法便可。
攔截器對象的生命與引用分離,先聲明,後引用。
在不作其餘特殊設定的狀況下,使用了自定義的攔截器,系統默認的攔截器失效。因爲系統默認的攔截器比較重要,實現重要功能不可缺乏,所以應該將系統默認的攔截器包含進去,而且放在其餘自定義攔截器前面。
分別定義與引用多個攔截器。
----------------攔截器聲明------------------------ <interceptors> <interceptor name="interceptor01"class=""/> <interceptor name="interceptor02"class=""/> </interceptors> ----------------攔截器引用------------------------ <action> <interceptor-ref name="defaultStack"/> <interceptor-ref name="interceptor01"/> <interceptor-fef name="interceptor01"/> </action>
將多個攔截器集中在攔截器棧中,引用攔截器棧。攔截器棧至關於攔截器集合。
----------------攔截器聲明------------------------ <interceptors> <interceptor name="interceptor01"class=""/> <interceptor name="interceptor02"class=""/> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="interceptor01"/> <interceptor-fef name="interceptor01"/> </interceptor-stack> </interceptors> ----------------攔截器引用------------------------ <action> <interceptor-ref name="myStack"/> </action>
將攔截器集中在默認攔截器中,對包中全部的Action有效。
----------------攔截器聲明------------------------ <interceptors> <interceptor name="interceptor01"class=""/> <interceptor name="interceptor02"class=""/> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="interceptor01"/> <interceptor-fef name="interceptor02"/> </interceptor-stack> </interceptors> <default-interceptor-ref name="myStack"/>
直接繼承AbstractInterceptor建立的攔截器對全部方法都進行攔截,繼承MethodFilterInterceptor建立的攔截器能夠指定攔截的方法。
引用方式:
<interceptor-ref name="interceptor01"class=""> <param name="includeMethods">methodName01,methodName02</param>//指定攔截的方法 <param name="excludeMethods">methodName01,methodName02</param>//指定不攔截的方法 </interceptor-ref>
Struts內置了許多類型轉化器,主要是將字符串轉化爲基本數據類型及其包裝類,將字符串轉化爲日期。系統默認的日期格式是yyyy-MM-dd HH:mm:ss,當輸入的字符串符合該格式時,自動轉化爲日期。
public class MyDateConverter extends DefaultTypeConverter { @Override public Object convertValue(Object value, Class toType) { // TODO Auto-generated method stub return super.convertValue(value, toType); } }
該方法分爲兩部分,有時執行兩次:
、
發生類型轉換異常,會返回值input,須要在配置文件中定義input對應的返回頁面。input只在拋出TypeConversionException時才返回,所以須要在自定義類型轉換器中拋出該異常,能夠先判斷表單輸入的格式是否是容許的格式,若是不是容許格式,拋出該異常。
文件命名方式ActionClassName-conversion.properties,放在Action包中,屬性文件內容:
屬性名=類型轉換器全限定性類名
文件命名方式xwork-conversion.properties,放在src目錄下,屬性文件內容:
屬性類型(如java.util.Date)=類型轉換器全限定性類名
修改類型驗證返回的提示信息,建立ActionClassName.properties文件,放在Action包中,內容:
invalid.fieldvalue.fieldname=數據驗證失敗提示信息
ActionSupport實現了Validatable接口,對其中的方法validate只是空實現,所以手動編寫驗證器時,繼承ActionSupport類,重寫validate方法。手動驗證器默認對對象內的全部方法都進行驗證。
public class MyValidator extends ActionSupport{ public void validate(){ if(xxxxxx)//驗證若是未經過 this.addFieldError("字段名","顯示的錯誤提示信息"); } }
驗證文件的命名規則:
ActionClassName-validation.xml:對Action對象中全部方法都進行驗證。
ActionClassName-AliasName(配置中的名稱)-validation.xml:只對指定的方法進行驗證。
驗證文件的編寫:
<validators> <field name="fieldName"> <field-validator type="requiredstring"> <message>驗證未經過時輸出的信息</message> </field-validator> </field> <validators>
驗證未經過時,Action返回值「input」,所以須要在<action>標籤內部配置返回值爲「input」時的返回頁面。
若是爲同一個方法同時定義了多個數據驗證方式,執行的優先級:基於XML的針對方法的驗證>基於XML的針對對象的驗證>手動編寫的針對方法的驗證>手動編寫的針對對象的驗證。
引用:
<%@taglib prefix="s" uri="/struts-tags"%>
主要標籤:
1.<s:debug/>:在頁面中顯示ActionContext中的內容。
2.<s:property value=""/>:
3.<s:property value="#request.name"/>:
4.<s:set name=""value="''"scope=""/>:賦值語句,字符串必須在內層使用‘',外層使用"",未指定做用域時放在context。
5.<s:iterator value=""/>:將遍歷對象放到值棧棧頂。
6.<s:property value="'s' in #list/>:判斷某個數據是否在列表中,相應地,還有不存在判斷not in。
7.<s:push value=""/>:將數據壓入棧中,以便之後訪問,該標籤不穩定,減小使用。
首次訪問表單頁面,若是該頁面採用了令牌機制,token攔截器生成一個隨機數,將這個隨機數在瀏覽器與服務器端各保存一份。首次提交表單時,token攔截器對比兩個參數,相同,完成提交,而後服務器單方面修改該隨機數,不通知瀏覽器。瀏覽器再次提交,兩個參數值不相同,token攔截器返回invalid.token值,跳轉到該值對應的頁面,請求未到達Action對象,這樣就防止了重複提交。
使同一個事物適應多種國際環境,就叫作國際化,在Web應用程序開發中就是使頁面可以按照多種語言來顯示。
Struts提供了一個攔截器I18N,該攔截器會自動獲取與國際化相關的請求參數,根據參數值選取相應地資源文件爲程序內部的變量賦值,賦值完成後,頁面按賦值結果顯示。這個請求參數是request_locale,將其追加到URL後面,並按照格式request_locale=language_country賦值。
實現國際化須要使用Struts標籤創建頁面。
國際化的實現依賴於資源文件,一種語言一個資源文件,資源文件的命名決定了其做用範圍,共有三種命名方式:
全局範圍資源文件,對整個應用都有效。baseName能夠自定義,放在scr目錄下,在配置文件中配置:
<constant name="struts.sustom.i18n.resources"value="baseName"/>
包範圍資源文件。
Action範文資源文件,放在包內。
在資源文件中定義動態參數:keyName={0},valueContext,其中佔位符從0開始。
在java文件中,採用如下形式爲動態參數賦值:
String str=this.getText("key",String[] args);
其中args是一個數組,爲資源文件中的佔位符賦值,這樣就能夠理解爲何不使用*,並且從0開始了。
<s:text name="key"> <s:param><s:property value=""></s:param>//爲第一個佔位符賦值 <s:param><s:property value=""></s:param>//爲第二個佔位符賦值 </s:text>
<s:param>標籤用做傳遞參數,<s:property>用來取值。
<s:i18n name="資源文件名相對於src的路徑"> -------指定資源------- </s:i18n>