Struts===

Struts2是在WebWork2基礎上發展而來的,和struts1同樣,struts2也屬於MVC框架。不過有一點你們須要注意的是:儘管Struts2和Struts1在名字上的差異不是很大,可是Struts2和Struts1在代碼風格上幾乎是不同的。那麼既然有Struts1,爲什麼還要推出Sturts2?java

  • 1>在軟件設計上Struts2沒有像Struts1那樣個ServletApi跟SturtsApi有着緊密的耦合,Struts2的應用能夠不依賴於ServletApi和StrutsApi,Struts2的這種設計屬於無侵入式設計,而Struts1卻屬於侵入式設計。
  • public class OrderListAction extends Action
  • {
  • public ActionForward execute(ActionMapping mapping ,ActionForm form,HttpServletRequest request,HttpServletResponse response)throws Exception{
  • }
  • }
  • 2>Struts2提供了攔截器,利用攔截器能夠進行AOP編程,實現如權限攔截功能
  • 3>Struts2提供了類型轉換器,咱們能夠把特殊的請求參數轉換爲須要的類型,在Struts1中,若是咱們要實現一樣的功能,就必須向Struts1的底層實現BeanUtil註冊類型轉換器才行。
  • 4>Struts2提供支持多種表現層技術,如:JSP,freeMaiker,Velocity等等。
  • 5>Struts2的輸入校驗能夠對指定的方法進行校驗,解決了Struts1長久之痛。
  • 6>提供了全局範圍,包範圍和Action範圍的國際化資源文件管理實現。

搭建Struts2開發環境
搭建Struts2環境時,咱們通常須要作一下幾個步驟的工做web

  • 1》找到開發Struts2應用須要的jar文件
  • 2》編寫Struts2的配置文件
  • 3》在web.xml中加入Sturts2 MVC 框架啓動配置
  • 搭建Struts2開發環境--開發Struts2應用依賴的jar文件
  • struts1-core-2.x.x.jar:Struts2框架的核心類庫
  • xwork-2.x.x.jar:xwork類庫,Struts2在其構建
  • ognl-2.6.x.jar:對象圖導航語言,struts2框架經過其讀寫對象的屬性
  • freemarker-2.3.x.jar:struts2的UI標籤的模板使用FreeMarker編寫
  • commons-logging-1.1.x.jar:ASF出品的日誌包,Struts2框架使用這個日誌包支持Log4J和JDK1.4的日誌記錄
  • commons-fileupload-1.2.1.jar:文件上傳組件,2.1.6版本後必須加入此文件

Struts2應用的配置文件
Struts2默認的配置文件爲struts.xml,該文件須要存放在web-inf/classes下,該文件的配置模板以下:
Struts2在web中的啓動配置
在struts1.x中,struts框架是經過Servlet啓動的,在struts2中,struts框架是經過Filter啓動的,他在web.xml中的配置以下
在strutsPrepareAndExecuteFilter的init()方法中將會讀取類路徑下默認的配置文件struts.xml,完成初始化操做。
注意,struts2讀取到struts.xml的內容後,以javabean形式存放在內存中,之後struts2對用戶的每次請求處理將使用內存中的數據,而不是每次都讀取struts.xml文件
Struts.xml配置中的包的介紹
在struts2框架中使用包來管理Action,包的做用和java中的類包是很是類似的,它主要用於管理一組業務功能先關的action,在實際應用中,咱們應該把一組業務功能相關的action,在實際應用中,咱們應該把一組業務功能相關的Action放在同一個包下。
配置包時必須指定name屬性,該name屬性值能夠任意取名,但必須惟一,他不對應java的類包,若是其餘包要繼承該包,必須經過該屬性進行引用,包的namespace屬性用於定義該包的命名空間,命名空間做爲訪問該包下Action的路徑的一部分,如訪問上面例子的Action,訪問路徑爲:/test/helloworld.action。namespace屬性能夠不配置,對本例而言,若是不指定該屬性,默認的命名空間爲""。(空字符串)
一般每一個包都應該繼承struts-default包,由於struts2不少核心的功能都是攔截器來實現的,如:從請求中把請求參數封裝到action,文件上傳和數據驗證等等都是經過攔截器來實現的,能夠這麼說,當包繼承了struts-default才能使用struts2提供的核心功能,struts-default包是在strust2-core-2.x.x.jar文件中的struts-default.xml中定義。struts-default.xml也是struts2默認配置文件。Struts2每次都會自動加載struts-default.xml文件。
包還能夠經過abstract="true"定義爲抽象包,抽象包中不能包含action。編程

Action名稱的搜索順序
1,得到請求路徑的URI,例如url是:http://server/struts2/path1/path2/path3/test.action
2,首先尋找namespace爲/path1/path2/path3的package,若是不存在這個package則執行步驟3:若是存在這個package,則在這個package中尋找名字爲test的action,當該package下尋找不到action時就會直接跑到默認的namespace的package裏面尋找action(默認的命名空間爲空字符串),若是在默認namespace的package裏面還尋找不到該action,頁面提示找不到action。安全

 

<package name="itcast" namespace="/test" extends="struts-default">
<action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
</package>
1》若是沒有爲action指定class,默認是ActionSupport。
2》若是沒有爲action指定method,默認執行action中的execute()方法。
3》若是沒有指定result的name屬性,默認值success。session

Action中result的各類轉發類型
<action name="helleworld" class="cn.itcast.action.HelloWorldAction">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
result配置相似於struts1中的forward,可是struts2中提供了多種結果類型,經常使用的類型有,dispatcher(默認值),redirect,plainText,redirectAction。
在result中還可使用${屬性名}表達式訪問action中的屬性,表達式裏的屬性名對應action中的屬性,以下
<result type="redirect">helloworld</result>
下面是redirectAction結果類型的例子,若是重定向的action中同一包下:
<result type="redirectAction">helloworld</result>
若是重定向的action在別的命名空間下:
<result type="redirectAction">
<param name="actionName">helloworld</param>
<param name="namespace">/test<param>
</result>
plaintext顯示原始文本內容,例如,當咱們須要原樣顯示jsp文件源代碼的時候,咱們可使用此類型,
<result name="source" type="plainText">
<param name="location">/xx.jsp</param>
<param name="charSet">UTF-8</param><!-- 指定讀取文件的編碼 -->
</result>
一個項目需求
使用重定向的技術,地址欄上面顯示了用戶名,經過編碼的方法來顯示
public String execute() throws Exception{
this.username = URLEncoder.encode("傳智播客","UTF-8");
return "success";
}
in jsp write
<% URLDecoder.decode(new String(request.getParameter("username").getBytes(ISO8859-1),"UTF-8"),"UTF-8")%>
配置文件
<result name="success" type="reidirect">/employeeAdd.jsp?username=${username}</result>app

 

爲Action屬性注入值
爲Action的屬性注入值,若是要實現依賴注入,要實現setter and getter method
<action name="itcast" class="cn.itcast.action.HelloWorld">
<param name="savepath">/images</param>
</action>
經過這些信息的配置,能夠實現給cn.itcast.action.HelloWorld這個類的savepath屬性依賴注入值。
指定Struts2處理的請求後綴
前面咱們都是默認使用.action後綴名訪問action。其實默認後綴名是能夠經過常量"struts.action.extension"進行修改的,例如,咱們能夠
配置Struts2只處理以.do爲後綴的請求路徑。
<struts>
<constant name="struts.action.extension" value="do,action,jsp"/>
</struts>
若是用戶須要指定多個請求後綴,則多個後綴之間以英文逗號隔開,
細說常量定義
常量能夠在struts.xml或struts.properties中配置,建議在struts.xml中配置,兩種配置方式以下,在struts.xml文件中配置常量
<struts>
<constant name="struts.action.extension" value="do"/>
</struts>
在struts.properties中配置常量
struts.action.extension=do框架

由於常量能夠在下面多個配置文件進行定義,因此咱們須要瞭解struts2加載常量的搜索順序,
struts-default.xml
struts-plugin.xml
strus.xml
strus.properties
web.xml
若是在多個文件中配置了同一個常量,則後一個文件中配置的常量值會覆蓋前面文件中配置的常量值。
常量能夠在struts.xml
Struts2的處理流程與Action的管理方式
StrutsPrepareAndExecuteFilter是Struts2框架的核心控制器,他負責攔截由<url-pattern></url-pattern>指定的全部用戶請求,當用戶請求到達時,該Filter會過濾用戶的請求,默認狀況下,若是用戶請求的路徑不帶後綴或者後綴以.action結尾,這時請求將被轉入Struts2框架處理,不然Struts框架將略過該請求的處理,當請求轉入Struts2框架處理時會先通過一系列的攔截器,而後再到Action,與Struts1不一樣,Struts2對用戶的每一次請求都會建立一個Action,因此Struts2中的Action是線程安全的。
爲應用指定多個配置文件
在大部分應用裏,隨着應用規模的增長,系統中Action的數量也會大量增長,致使struts.xml配置文件變得很是臃腫,爲了不struts.xml文件過於龐大,臃腫,提升struts.xml文件的可讀性,咱們能夠將一個struts.xml配置文件分解成多個配置文件,而後再struts.xml文件中包含其餘配置文件。
<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
</struts>
經過這種方式,咱們就能夠將struts2的Action按模塊添加在多個配置文件中。jsp

如何接收請求參數
在學習中我發現一個知識要點,那就是在Action中定義一個方法,
public String test()
{
return "success";
}
在返回success的時候,也就是返回一個success頁面的時候,會把這個Action的參數也給帶過去。因此,假如說,這個"success"對應的是一個頁面,那麼這個頁面可使用到該Action裏面的屬性。
接收請求參數
採用基本類型接收請求參數(get/post)
requestPath:http://localhost:8080/test/view.action?id=78
public class Production{post

private Integer id;
public void setId(Integer id){this.id = id;}
public Integer getId(){return this.id;}學習

}
採用複合類型接收請求參數
requestPath:http://localhost:8080/test/view.action?product.id=78
public class ProductAction{

private Product product ;
public void setProduct(Product product){this.product = product;}
public Product getProduct(){return product;}
}
struts2首先經過反射技術調用Product的默認構造器建立Product對象,而後再經過反射技術調用product中與請求參數同名的屬性的setter方法來獲取請求參數值。
若是使用符合類型了接收參數的話,注意必定要給一個默認的構造器,such as
public class Person{
public Person(){}
}
自定義類型轉換器

 

動態方法調用
若是Action中存在多個方法時,咱們可使用!+方法名調用指定方法,以下:
public class HelloWorld{

private String message;
...
public String execute() throws Exception{
this.message="個人第一個struts2應用";
return "success";
}
public String other()throws Exception{
this.message="第二個方法";
return "success";
}
}
假設訪問上面action的URL路徑爲:/struts/test/helloworld.action
要訪問action的other()方法,咱們能夠這樣調用:
/struts/test/hellowrold.action
若是咱們不想使用動態方法調用,咱們能夠經過常量struts.enable.DynamicMethodinvocation關閉動態方法調用。
<constant name="struts.enable.DynamicMethodinvocation" value="false">

使用通配符定義action
<packge name="itcast" namespace="/test" extends="struts-default">
<action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
</package>

public class HelloworldAction extends ActionSupport{

private String message ;
public String execute() throws Exception{
this.message="個人第一個struts2應用";
return "success";
}
public String other()throws Exception{
this.message="第二個方法";
return "success";
}
}

要訪問other方法,能夠經過這樣的url訪問:/test/helloworld_other.actoin

Struts也能夠實現AOP的編程
這個功能的實現是經過攔截器來實現的,下面是一個案例
若是用戶登陸後能夠訪問action的全部方法,若是,用戶沒有登陸不容許訪問action的全部方法,並顯示用戶沒有訪問權限。
1,在jsp頁面中經過session來設置用戶的登陸狀態。
2,攔截器跟Filter很相像,自定義的攔截器要實現Interceptor接口。該接口一共有三個方法
public void init()
public void destroy()
public String intercept(ActionInvocation invocation)throws Exception()
3,註冊攔截器,在struts.xml中定義一個攔截器
<interceptors>
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
</inpterceptors>

<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
<interceptor-ref name="permission"/>
</action>
//採用上述的方法能夠得到一個攔截器的使用permiession,可是卻失去了struts定義好的全部默認的攔截器。因此採用下面的方法
<interceptors><!-- 注意這個struts提供給咱們的defaultStack棧是要放在前面的 -->
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
<interceptor-stack name="permiessionStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="permiession"/>
</interceptor-stack>

</inpterceptors>

<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
<interceptor-ref name="permiessionStack"/>
</action>


//struts-default.xml定義了一個攔截器棧<interceptor name="defaultStack">,這個棧裏面放置一些經常使用的攔截器,
上面我配置的攔截器只能做用於一個action,若是想做用於整個包底下的action,我能夠這樣定義

<interceptors>
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
<interceptor-stack name="permiessionStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="permiession"/>
</interceptor-stack>
</inpterceptors>
<default-interceptor-ref name="permiessionStack"/>
<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
</action>
//經過<default-inpterceptor-ref>來聲明一個全局的攔截器做用於整個包下
//注意若是這個時候在action中再定義一個攔截器的話,那麼<default-interceptor-ref>定義的攔截器將不會做用在該action中。

 

由於struts2中如文件上傳,數據驗證,封裝驗證,封裝請求參數到action等功能都是系統默認的defaultStack中的攔截器實現的,因此咱們定義的攔截器須要引用系統默認的defaultStack,這樣應用纔可使用struts2框架提供的衆多功能。
若是但願包下的全部action都使用自定義的攔截器,能夠經過<default-interceptor-ref name="permiessionStack"/>把攔截器定義爲默認攔截器,注意,每一個包只能指定一個默認攔截器,另外,一旦咱們爲該包中的某個action顯示指定了某個攔截器,則默認攔截器不會起什麼做用。

對Action中全部的方法進行輸入校驗
在struts2中,咱們能夠實現對action的全部方法進行校驗或者對action的指定方法進行校驗。
對於輸入校驗struts2提供了兩種實現方法:
1,採用手工編寫代碼實現
2,基於XML配置方式實現
手工編寫代碼實現對action中全部的方法輸入校驗
經過重寫validate()方法實現,validate()中全部與execute方法簽名相同的方法,當某個數據校驗失敗時,咱們應該調用addFieldError()方法往系統的fieldError添加失敗信息,(爲了使用addFieldError方法,action能夠繼承ActionSupport),若是系統的fieldError包含失敗信息,struts2會將請求轉發到名爲input的result視圖,在input視圖中能夠經過<s:fielderror/>顯示失敗信息。
validate()使用例子
public void validate(){  if(this.mobile==null||"".equals(this.mobile.trim()){this.addFieldError("username","手機號不能爲空!");}

  else if(Pattern.compile("^1[358]\\d{9}").matcher(this.mobile.trim().matches()){
  this.addFieldError("mobile","手機號格式不正確!");
}
}
驗證失敗後,請求轉發到input視圖
  <result name="input">/WEB-INF/page/addUser.jsp</result>
在addUser.jsp頁面中使用<s:fielderror/>顯示失敗信息。


項目需求,一個是用戶名不能爲空,另外一個是手機號的長度爲符合手機號的格式,1,開始,3,5,8爲第二個,後面一共有九個數字。
1,定義一個jsp頁面
  用戶名:<input type="text" name="username"/>
  手機號:<input type="text" name="tel"/>
  <input type="submit" value="提交"/>
2,定義一個action,
public PersonAction extends ActionSupport
{
  private String username ;
  private String mobile ;
  ...setter and getter method
  public String save()throws Exception(){return "success";}
  public Stirng add() throws Exception(){return "fail";}

}
//重寫validate方法
public void validate()
{
  if(this.username==null&&"".equals(this.username.trim())){
}

}

手工編寫代碼實現actioin指定方法輸入校驗
經過重寫validateXxxx()方法實現,validateXxxx()只會校驗action中方法名爲Xxx的方法,其中Xxx的第一個字母要大寫,當某個數據校驗失敗時,咱們應該調用addFieldError()方法往系統中fieldError添加校驗失敗信息(爲了使用addFieldError方法,action能夠繼承ActionSupport,若是系統的fieldError包含失敗信息,struts2會將請求轉發到名爲input的result,在input視圖中能夠經過<s:fielderror/>顯示失敗信息
validateXxx()方法使用例子
public String add()throws Exception {return "success";}
public void validateAdd(){if..............this.addFieldError(''''}

 

輸入校驗的流程
  1,類型轉換器對請求參數執行類型轉換,並把轉換後的值賦予action中的屬性。
  2,若是在執行類型轉換的過程當中出現異常,系統會將異常信息保存到ActionContext,conversionError攔截器將異常信息封裝到fieldError裏,無論類型轉換是否出現異常,都會進入第三步。
  3,系統經過反射技術先調用acion中的validateXxx方法,Xxx爲方法名。
  4,在調用action中的validate方法。
  5,通過上面四步,若是系統中的fieldError存在錯誤信息,(即存在錯誤信息的集合的size大於0),系統自動將請求轉發至名稱input的視圖,若是系統中的fieldError沒有任何錯誤信息,系統將執行action的處理方法。

注://這裏有一個須要說明的是當我把validate或者validateXxx方法裏面的代碼所有清空,結果,發現系統仍是執行input方法,那麼,這個時候就要注意了,多是在類型轉換的時候出現了錯誤,這時候,要檢查類型轉換器。

相關文章
相關標籤/搜索