<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    Struts 應用轉移到 Struts 2

    原文出處:

    http://www.infoq.com/articles/converting-struts-2-part1
    http://www.infoq.com/articles/migrating-struts-2-part2

    (本文已取得InfoQ.com翻譯授權,譯者:cac@SpringSide團隊 ,   轉載請注明出處)

         有很多人都很熟悉 Struts, 無論是從項目中直接獲得的實戰經驗還是從書中了解到的。我們這一系列文章,將通過一個由 Stuts 轉移到 Struts2 簡單的例子向大家展現Struts2的所有特征。
        在我們開始這個例子之前,你需要去知道一點 Struts2的背景知識。 在第一部分的文章中,我們將介紹Struts2與Struts的核心框架的不同點,以助于更好地了解其他方面的整合。第二部分中,我們將深入探討 actions 的差別, action相關的框架特征,和action配置。在最后一部分中,我們將會講述 user interface,我們也會講到其架構,UI構件,themes 和標簽。 還有如何為你的應用加上新的外觀。
        我們并不打算談及遷移過程的所有細節方面,我們只是從出發點開始介紹Struts2 的概念和現在可用的所有特征。但擁有這些知識,你將在以后Struts2的應用中無往而不利。
       
    Struts的歷史
        Struts的第一個版本 是在 2001年5月份發布。它提供了一個Web應用的解決方案,如何讓 JSPs 和 servlets 共存去提供清晰的分離視圖和業務和應用邏輯的架構。在Struts之前,最通常的做法是在JSP中加入業務和應用邏輯,或者在servlets中生成視圖。
        自從第一個版本的發布, Struts 實際上已成為業界公認的Web應用標準。但隨著時間的推移,Web應用框架經常變化的需求,產生了幾個下一代 Struts的解決方案。其中兩個可選方案是Shale 和 Struts Ti。 Shale 是一個基于構建的框架,并在最近成為 Apache 中的重要項目。而 Struts Ti 則是繼續堅持 MVC模式的基礎上改進,繼續Struts的成功經驗。
        WebWork項目是在2002年3月發布的,它對Struts式框架進行了革命性改進,引進了不少新的思想,概念和功能,但和原Struts代碼并不兼容。WebWork是一個成熟的框架,經過了好幾次重大的改進與發布。在2005年12月,WebWork與Struts Ti決定合拼, 再此同時, Struts Ti 改名為 Struts Action Framework 2.0,成為Struts真正的下一代。

    請求如何運作
        在我們開始詳細探討如何轉移Struts到Struts2之前,讓我們來看看整個請求流程在新架構中是如何運作的。你會注意到在整個請求的生命周期,仍是以controller作主體,而且所有的概念還都是你以前所熟悉的, 就如:

    • 通過URL請求的參數來調用Actions來把數據傳給server.
    • 所有的Servlet objects (request, response, session,之類.) 仍然可以在Action中獲取

    下圖展示了整個請求的概要過程:

    整個請求過程可以分為六步驟:

    1. 一個請求產生并經由框架處理 - 框架根據請求匹配相應的配置,如使用哪些攔截器,action 類和結果。
    2. 請求通過一系列的攔截器 - 攔截器,和攔截器組經配置后,能處理不同等級的請求,它們為請求提供了各種預處理,切面處理。這和Struts的使用 Jakarta Commons Chain 構件的 RequestProcessor類很相似。
    3. 調用 Action - 產生一個新的action對象實例,并提供請求所調用的處理邏輯的方法。Struts2 可以在配置action時為請求分配其指定的方法。我們在第二部文章中將對這步驟進行進一步討論;
    4. 調用產生的結果 - 獲取通過action的方法處理后返回來的結果,匹配其result class并調用產生的實例。有種情況是在UI模板去生成HTML時才去處理這些結果。如果在這種情況下,在Struts2 模板中的tags能直接返回到 action 中,取結果來呈現界面。 
    5. 請求再次經過一系列的攔截器處理后返回 - 請求反順序通過與原來進入時的攔截器鏈, 當然,你也可以配置在這個過程中減少或增加攔截器處理.
    6. 請求返回到用戶 - 最后一步是由 control 返回到servlet。通常是生成HTML返回到user, 但你也可以指定返回的HTTP頭或HTTP重定向。

    你應該已注意到,Struts2與Struts的差別。最明顯的就是Struts2是pull-MVC 架構,就是可以直接從Action中獲取所需要的數據,而不是像Struts那樣必須把 beans 存到page, request,或者session中才能獲取。這個我們將在下一章中詳細提及。

    配置框架
    首先最重要的是,讓框架能通過web.xml在servlet containers里運行。
    下面這個就是大家都熟悉的 Struts在 web.xml里的配置方法

    <servlet>
            <servlet-name>action</servlet-name>
            <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
            <init-param>
                <param-name>config</param-name>
                <param-value>/WEB-INF/struts-config.xml</param-value>
            </init-param>
            <load-on-startup>2</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>action</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>

    在 Struts2 中,這個有少許改變,最明顯的是dispatcher 由servlet轉為servlet filter, 其配置和servlet一樣簡單,如下:

      
     <filter>
             <filter-name>webwork</filter-name>
               <filter-class>
                org.apache.struts.action2.dispatcher.FilterDispatcher
       </filter-class>
        </filter>
        <filter-mapping>
       <filter-name>webwork</filter-name>
       <url-pattern>/*</url-pattern>
        </filter-mapping>

    和servlet配置一樣,filter配置定義了名稱(供關聯)和filter的類。filter mapping讓URI匹配成功的的請求調用該filter。默認情況下,擴展名為".action"。
    這個是在default.properties文件里的"struts.action.extension" 屬性定義的。
    工具箱:  "default.properties"是配置選項定義文件。通過在classpath中包含一個叫"struts.properties"的文件,并設置不同的屬性值,你可以覆蓋這個默認的配置,實現自己的配置。
    對于Struts, servlet配置提供了初始化tag的參數和使用的文件,而Struts2沒有這樣的配置參數,取而代之的是在classpath下的默認配置文件"struts.xml"。
    工具箱/提示: Struts actions(擴展名".do"),Struts2 actions(擴展名".action"),所以Struts和Struts2可以在一個系統中共存。所以最好是保持原先的系統,在新功能的開發上用Struts2, 如果時間和資源允許的情況下再逐步遷移。另一種方法是只是把Struts2的擴展名改為".do",可重用JSPs.
    分析Actions
    在上面介紹的請求運作流程中,我們談及了一些Struts和Struts2的不同點。現在我們將較深入地探討這兩個框架中action結構的具體差別。
    讓我們來回顧一下 Struts 的 action 結構, 主要的形式如下:

    public class MyAction extends Action {
        public ActionForward execute(ActionMapping mapping,
                                     ActionForm form,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
                throws Exception {
            // do the work
            return (mapping.findForward("success"));
        }
    }

    當實現一個Struts action時, 你需要注意一下問題:

    1. 所有的action 都必須繼承于base Action 類.
    2. 所有的action都必須是線程安全的,因為action是單例的,singleton的.
    3. 因為所有的action都必須是線程安全的,所以所有的對象都不能是類屬性, 都必須以方法參數的形式傳值。
    4. 調用action的方法必須命名為 "execute" ( 在Struts中的  DispatchAction 類好像可以用其它方法去執行同一個action ,但實際上在框架中調用的仍然是 "execute" 方法。).
    5. ActionForward 的結果是通過ActionMapping 類中的方法來產生的,通常是"findForward"方法.

    相比較之下, Struts2的action 提供了很多簡單的實現。下面就是個例子

    public class MyAction {
       public String execute() throws Exception {
            // do the work
            return "success";
       }
    }

    首先你會注意到的是,Struts2中的action不再繼承于任何類或需要實現任何接口。實際上,它還遠不只這些。按照慣例,只有"execute"方法能調用action, 但在Struts2中并非必要,任何聲明為public String methodName() 方法都能通過配置來調用action.
    另外,你會注意到返回值不再是"ActionForward ",而是String, 如果你需喜歡String的形式,那在Action接口里有個幫助方法可以提供簡單的結果常量,如"success", "none", "error", "input" 和 "login"。
    最后,和Struts最大的革命性的不同是, 調用action不再是帶參數的。那你如何在獲得你所需要的值呢?答案是"inversion of control" 或 "dependency injection", 反轉控制(想了解更多可以看Martin Fowler的文章 http://www.martinfowler.com/articles/injection.html)。
    為了更好地了解反轉控制,讓我們來看看一個例子,如何在action處理過程中可以訪問到HttpServerRequest 。在我們的例子中,我們用ServletRequestAware 接口,這個接口包含了相應屬性的setter,如下

    public interface ServletRequestAware {
        public void setServletRequest(HttpServletRequest request);
    }

    當我們繼承這個接口時,我們需要通過setter為我們的HttpServerRequest 屬性變量賦值:

    public class MyAction implements ServletRequestAware {
       private HttpServletRequest request;
       public void setServletRequest(HttpServletRequest request) {
            this.request = request;
       }
       public String execute() throws Exception {
            // do the work using the request
            return Action.SUCCESS;
       }
    }

    看起來現在這些屬性是類級別的,并不是線程安全的,但是在Struts2里并沒有問題,因為每個請求過來的時候都會產生一個新的action對象實例,它并沒有和其他請求共享一個對象,所以不需要考慮線程安全問題。

    現在我們還有最后一步,就是把action關聯上ServletConfigInterceptor 攔截器。這個攔截器繼承了ServletRequestAware 接口,并提供了把HttpServletRequest 注入到action中的功能。但是你現在不用擔心如何配置這些,我們將在下一篇文章中具體講述。最重要的是我們明白了攔截器和接口共同為action提供了反轉控制的功能。
    這個設計的好處是能讓action完全和框架解耦。action僅僅是一個被框架使用的簡單的POJO。這對于單元測試但來極大的好處, 你能方便的為Struts action實現 StrutsTestCase 或  MockStrutsTestCase 單元測試。

    總結
    By到現在為止,你應該已經了解了Struts2的整個請求流程,還有高層的框架概念, 你也應該能自己動手配置Struts2的action,和講出Struts和Struts2的差別了。
    在下篇文章中,我們將會介紹一個詳細的Struts應用向Struts2遷移的例子,同時我們也會介紹遷移中相關的知識,會講述如何綜合使用JSTL, JSP 和 Struts2,進一步講述Struts和Struts2的action的差別,Struts2的配置和其他框架元素,和談到更多的其他相關框架的特征。

    Struts 應用轉移到 Struts 2 ( 二 )

        在上篇文章中,我們已經從較高層解釋了整個框架的結構,請求流程的基礎,配置方式和Struts2和Struts1的不同之處。了解這些后從Struts 應用 遷移到 Struts 2 不再是難事。
        在這篇文章中,我們將會更詳細地講述如何由Struts 的action轉為Struts 2的action。

    一個應用的例子
    這個例子選擇了大家都熟悉的 - weblog. 簡單地介紹下這例子的功能需求:

    1. 增加一個新的日志
    2. 察看一個日志
    3. 修改一個日志
    4. 刪除一個日志
    5. 列出所有日至

         增刪修改(CRUD),是項目中最為普遍的應用。
         業務邏輯類在Struts 和 Struts2 應用都是可共用的。如:

    public class BlogService {
         private static List<Blog> blogs = new ArrayList<Blog>();
         public List<Blog> list() { ... }
         public Blog create(Blog blog) { ... }
         public void update(Blog blog) { ... }
         public void delete(int id) { ... }
         public Blog findById(int id) { ... }
    } 

         BlogService 只是個簡單的業務邏輯類,并不是接口,Struts 和 Struts2 的action皆可調用其實例。雖然這樣設計在實際項目中會帶來不必要的耦合,但我們的例子只是集中在討論web層上,所以無關重要。
    工具箱: 在第一篇文章中,我們談論了在Struts2 actions中的依賴注入的接口注入方式。這個是servlet 相關類(HttpServletRequest, HttpServletResponse, PrincipalProxy, 等.)的主要注入方式,但這并不是唯一的方式。
    Struts2 可以使用Spring框架作為默認的容器時,依賴注入的setter方法就可用了。通過在action中加入setter方法(如下演示), Struts2 框架將能從Spring框架中獲得正確的信息,并通過setter加載在action中。

    public void setBlogService(BlogService service) {
         this.blogService = service;
    }

    和接口注入方式類似,我們需要一個攔截器來幫助我們完成任務,這就是 ActionAutowiringInterceptor 攔截器。這樣我們的業務邏輯類就通過Spring框架管理自動在action被調用之前注入到Struts2得action中。有多種的配置參數(如by name, by type 或 automatically)可供選擇,可以讓對象和setter匹配的注入的方式根據你的需要而定。

    Struts 應用中的代碼
         我們首先從Struts講起。在Struts中,最普遍的做法是,對于每個需求用例(如save,update,remove,list)來說都會有對應的action類,同時也會有相應的action form類。在我們的應用中的這個方式或許不是最佳的實現方式(其他的解決方案包括使用dynamic form或者使用request來分發action),但我們例子中的做法是所有Struts開發者最熟悉的一種形式。了解了這種簡單的實現方法,你有能力在遷移到Struts2時,使用更為優秀的方法。
    在第一篇文章中我們談過Struts 和 Struts2 中action的區別。現在我們從UML中再次看看他們的差別。一般來說form在Struts action中的表現形式是:

    這action form將會在多個action中使用,讓我們來看看它:

    public class BlogForm extends ActionForm {
         private String id;
         private String title;
         private String entry;
         private String created;
         // public setters and getters for all properties
    }

         如UML中展示的那樣,其中一個限制就是必須繼承ActionForm類,另外一個限制就是form中所有屬性都必須是String類型,所以所有的getter和setter都必須只能接受String參數和返回String結果。

    然后我們來看看action。我們這個例子中的action有view, create 和 update action。
    The View Action:

    public class ViewBlogAction extends Action {
         public ActionForward execute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                 throws Exception {
             BlogService service = new BlogService();
             String id = request.getParameter("id");
             request.setAttribute("blog",service.findById(Integer.parseInt(id)));
              return (mapping.findForward("success"));
         }
    }

    The Create Action:

    public class SaveBlogEntryAction extends Action {
          public ActionForward execute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                 throws Exception {
             BlogService service = new BlogService();
             BlogForm blogForm = (BlogForm) form;
             Blog blog = new Blog();
             BeanUtils.copyProperties( blog, blogForm );
             service.create( blog );
             return (mapping.findForward("success"));
         }
    }

    The Update Action:

    public class UpdateBlogEntryAction extends Action {
         public ActionForward execute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                 throws Exception {
             BlogService service = new BlogService();
             BlogForm blogForm = (BlogForm) form;
             Blog blog = service.findById( Integer.parseInt(blogForm.getId()));
             BeanUtils.copyProperties( blog, blogForm );
             service.update( blog );
             request.setAttribute("blog",blog);
             return (mapping.findForward("success"));
         }
    }

    這三個action都跟隨著同一個模式:

    • 產生一個新的業務邏輯對象實例 - 如前面所提到的,我們使用最直接的方式在action中使用業務邏輯對象,這表示在每個action中都會產生新的業務邏輯對象實例。
    • 從請求中獲得數據 - 這是兩種形式之一。在view action中,"id"是從HttpServletRequest 對象中直接獲取的。而在create 和 update action 中,則從ActionForm 中取值。ActionForm 與 HttpServletRequest 的調用方式其實很相似,唯一不同的ActionForm 是bean的從field中取值。
    • 調用業務邏輯- 現在開始生成調用業務邏輯所需的參數并調用邏輯。如果參數(在view action中)是一個簡單對象類型,則轉換值時會自動轉為正確的類型(如從String轉到Integer)。如果參數是復雜的對象類型,,則ActionForm 需要通過BeanUtil 來幫忙轉成相應的對象。
    • 設定返回的數據 - 如果需要把數據返回顯示給用戶,那則要把這個數據設在HttpServletRequest 的attribute 中返回。
    • 返回一個 ActionForward - 所有 Struts action的最后都需要找到并返回其相應的 ActionForward 對象.

         最后的兩個action,remove和list action, 只有很少的差別。remove action如下所示,沒有用BlogForm類. 通過從request的attribute中獲取"id"(和view action相似),就能調用業務邏輯完成其需要的工作。在下面我們介紹配置時,你可以看到它并沒有返回任何數據,因為它的"success"返回結果其實是執行remove后再執行了list action來返回信息的。

    public class RemoveBlogEntryAction extends Action {
         public ActionForward execute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                 throws Exception {
             BlogService service = new BlogService();
             String id = request.getParameter("id");
             service.delete(Integer.parseInt(id));
             return (mapping.findForward("success"));
         }
    }

     list action并不需要任何的用戶輸入,它只是簡單地調用了業務邏輯的無參方法,同時返回所有的Blog對象。

    public class ListBlogsAction extends Action {
         public ActionForward execute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                 throws Exception {
             BlogService service = new BlogService();
             request.setAttribute("bloglist",service.list());
             return (mapping.findForward("success"));
         }
    }

    向 Struts2 遷移
         在Struts2中,可選的實現方式有很多,可以像Struts那樣每個需求用例對應一個action,也可以用一個action對應所有需求用例。但在我們的例子中,使用的方法是我認為最佳的解決方案 - 在一個action類中實現整套CRUD功能。
         也許你人為把list需求用例也同樣地整合到同一個action類里會比較好,而我認為把list的功能分到另外一個action中,會減少容易產生的混淆,因為list用例中并不需要Blog這個類作為屬性,而在其他用例中則需要。

    對于 Struts2的例子, 它的UML模型展示如下:

         每個用例在action中都有自己所對應的方法。從上圖中我們可以看到,在BlogAction 中我們有save, update 和 remove三個方法。而ListBlogAction中,沒有list這個方法,因為ListBlogAction繼承了ActionSupport 類,實際上就是在默認的execute 方法中實現list功能。
         為了更容易看,圖中的BlogAction并沒有畫出它所實現了的三個接口。它們分別是ServletRequestAware 接口,  Prepareable 接口和 ModelDriven 接口。
         首先回顧一下ServletRequestAware, 我們在第一篇文章中已經詳細介紹它了。這個ParametersInterceptor 攔截器提供了把HttpServletRequest 自動set到action中的功能,讓我們能通過request, 把所需的值傳回到JSPs。
         接著看看Preparable 接口, 它會聯合PrepareInterceptor攔截器一起工作,讓action在執行execute() 方法前, 執行一個prepare()方法,實現在執行前設定,配置或預設一些值在action中。 在我們的例子里,prepare方法會檢查blogId 屬性,如果為零則這是一個新日志,非零則該日志已經存在,根據blogId取出日志。
         最后我們說說ModelDriven 接口,在上一篇文章中,我們已經了解到 Struts action的很大的不同在于它是需要線程安全的,而在Struts2中則沒有這個限制,因為每次的請求都會有一次action對象的初始化和調用。沒有了這個限制,能允許Struts2使用類級別的屬性變量(特別是getters和setters),從而獲得更多編碼優勢。

    和攔截器的功能結合起來, 把HttpServletRequest 中的attribute 注入action中的流程如下所示:

    • 循環讀取HTTP request中的attribute
    • 查找當前request attribute中是否有和action中的setter中的屬性匹配的
    • 有則根據attribute從HttpServletRequest 里取出其值
    • 把取出來的值由String轉成setter中相應的類型
    • 調用setter把該轉換后的值注入action中

    提示: 當調用action時,如果發現不明原因使不能正確地通過setter注入值情況下,第一步最好是先檢查下各攔截器,確保它們都已作用于該action。因為這些意外通常有時由攔截器設置不當形成的,檢查是否各個攔截器都已起作用,并看看它們作用的順序,因為有些情況下它們間會相互影響而產生錯誤。
        現在我們已經有基于String類型的form bean中取值的方法或者是自動把request的attributes 注入到action的方法,那下一步就是如何把值傳入 domain object 或 value / transfer object的屬性中去。其實這很簡單,你只需要實現ModelDriven 接口(即實現getModel()*方法)就可以了,確保ModelDrivenInterceptor* 攔截器已作用于action。
        除了會調用action中的setter外,model 首先檢查是否有和setter可以匹配當前的attribute名。如果在model中沒有這個attribute相應的setter,則會再在action上找相應的setter來設值。
        在BlogAction 的例子中我們可以看到如何很靈活地使用這些方法,首先通過prepare() 方法根據Id獲取相應的 Blog model object 或新建一個instance, 然后再根據把request中相應的屬性注入Blog instance中和action中。
        以上的兩個功能使得現在調用action那么簡單 - 調用具體的業務邏輯,和把數據設在HttpServletRequest供返回用*。*

    public class BlogAction extends ActionSupport
             implements ModelDriven, Preparable, ServletRequestAware {
         private int blogId;
         private Blog blog;
         private BlogService service = new BlogService();
         private HttpServletRequest request;
         public void setServletRequest(HttpServletRequest httpServletRequest) {
             this.request = httpServletRequest;
         }
          public void setId(int blogId) {
             this.blogId = blogId;
         }
          public void prepare() throws Exception {
             if( blogId==0 ) {
                 blog = new Blog();
             } else {
                 blog = service.findById(blogId);
             }
         }
          public Object getModel() {
             return blog;
         }
          public String save() {
             service.create(blog);
             return SUCCESS;
         }
          public String update() {
             service.update(blog);
             request.setAttribute("blog",blog);
             return SUCCESS;
         }
          public String remove() {
             service.delete(blogId);
             return SUCCESS;
         }
          public String execute() {
             request.setAttribute("blog",blog);
             return SUCCESS;
         }
    } 

        最后就是說說 list這個用例了。它同樣需要訪問HttpServletRequest對象去返回數據給JSP,所以也需要實現ServletRequestAware 接口。但是,因為它并不需要任何輸入值,所以就不需要實現其他的接口了。以下是它的具體實現:

    public class ListBlogsAction extends ActionSupport implements ServletRequestAware {
         private BlogService service = new BlogService();
         private HttpServletRequest request;
         public void setServletRequest(HttpServletRequest httpServletRequest) {
             this.request = httpServletRequest;
         }
         public String execute() {
             request.setAttribute("bloglist",service.list());
             return SUCCESS;
         }
    }

    這樣就完成了我們該實現的action代碼了。 在下一篇文章中,當我們新的Struts2用戶界面結合時,我們還會進一步簡化action的代碼。

    配置Actions
        在我們調用action之前,我們必須通過XML配置文件去配置它們。
        在Struts中, 我們習慣用在WEB-INF 目錄的"struts-config.xml"配置文件,在這里我們需要配置action form和action屬性。在Struts2中, 用的是在classpath中的"struts.xml"配置文件, 它看起來好象會稍微復雜一些,因為它需要在配置action的同時也配置其攔截器。

        在Struts中配置 form-beans 節點很容易, 只需要一個唯一的名字,還有就是繼承ActionForm類的class作為type。

    <struts-config>
         <form-beans>
             <form-bean name="blogForm"
        type="com.fdar.articles.infoq.conversion.struts.BlogForm"/>
         </form-beans>
         ...
    </struts-config>

    在我們的例子中,我們的配置文件有3點不相同:
    1. 重定向配置
        在Struts的配置中,每個mapping 都需要提供調用action時所需要對應的路徑,Struts默認為".do", 例如paht是"/struts/add"對應于URL"/struts/add.do"。同時也需要一個forward 屬性來提供給URL去轉向,如"/struts/add.jsp".

    <struts-config>
         ...
          <action-mappings>
              <action path="/struts/add" forward="/struts/add.jsp"/>
             ...
          </action-mappings>
    </struts-config>

    而Struts2的需要更多的一些配置,如:

    <struts>
          <include file="struts-default.xml"/>
          <package name="struts2" extends="struts-default" namespace="/struts2">
              <action name="add" >
                 <result>/struts2/add.jsp</result>
             </action>
             ...
          </package>
    </struts> 

        首先你會注意到的是,代替action-mappings 節點的是includepackage 節點。Struts2可以把配置細分到任意數目的配置文件中,來實現配置可模塊化管理。每個配置文件的結構其實都是一樣的,不同的只是文件名。
        include 節點中,以文件名作為file 屬性,可把所include的文件內容包含到當前文件中。
       package 節點把actions組成一組,其name 屬性的值必須是唯一的。
       在 Struts action的配置中, paht屬性需要指定完整的URL路徑。而在Struts2中,URL是通過package節點中的namespace屬性,還有在action 節點中的name 屬性, 和action擴展(默認是".action")共同起作用的。在上面的例子中,則URL為"/struts2/add.action"時會調用action。
       package節點除了可以分離命名空間外, package 節點中的 extends 屬性,還提供了某種可復合的組成結構。通過繼承另外一個package節點,你就能繼承那個節點的配置,包括其actions, results, interceptors, exception,等值。在我們的例子中,"struts2" package節點繼承了 "struts-default" package 節點(在"struts-default.xml" 文件里定義了該節點) ,注意這個是主要的include文件,所以必須在所有配置之前的第一行中寫出。 這個功能有助于大大減少你重復性輸入默認配置所浪費的時間。
        最后是result 節點, 它只是存放你這個action所需要轉向的URL. 在這里我們沒有提及nametype 屬性。如果你不想改變它們的默認屬性的話,你能忽略不寫它們,讓你的配置文件看起來更清晰。從action返回的 "success" 的結果將組成這個JSP顯示給用戶。

    2. Action 配置
        在Struts 中forward 節點指定了action處理后,結果將重定向到哪個相應的頁面。type屬性指定了action的類,scope 屬性保證了form beans只在request范圍內。

    <struts-config>
         ...
          <action-mappings>
              <action path="/struts/list" scope="request"
                     type="com.fdar.articles.infoq.conversion.struts.ListBlogsAction" >
                 <forward name="success" path="/struts/list.jsp"/>
             </action>
             ...
          </action-mappings>
    </struts-config>

        Struts2 的 XML配置和上面提到的基本相同。唯一不同的就是通過class屬性為action節點提供了它所需要調用的類的完整路徑

    <struts>
         ...
          <package name="struts2" extends="struts-default" namespace="/struts2">
              <default-interceptor-ref name="defaultStack"/>
              <action name="list"
                     class="com.fdar.articles.infoq.conversion.struts2.ListBlogsAction">
                 <result>/struts2/list.jsp</result>
                 <interceptor-ref name="basicStack"/>
             </action>
             ...
          </package>
    </struts>

        如果是用其他的方法而不是用默認的execute 方法去調用action(在BlogAction 類中大多數方法如此), 則需要在action節點的 method 屬性里加入方法名,下面就是個例子,這時候update方法將會被調用。

    <action name="update" method="update"
        class="com.fdar.articles.infoq.conversion.struts2.BlogAction" >
            ...
        </action>

        default-interceptor-refinterceptor-ref 節點有幾點不同。在第一篇文章中,我們看到在action被調用之前必須通過一系列的攔截器,而這兩個節點就是用來配置攔截器組的。default-interceptor-ref 節點為該package提供了默認的攔截器組。當在action節點中提供 interceptor-ref節點時 ,它就會覆蓋默認的攔截器(interceptor-ref 節點能夠和單獨一個攔截器相關聯,或者跟一個攔截器組相關聯),在action節點中可以存在多個interceptor-ref節點,處理攔截器組的順序會和該節點列出的順序一致。

    3. 再重定向配置
        當我們提交表格的時候,我們需要重定向到更新后的結果頁面。這個通常稱為 "post-redirect pattern" 或, 最近出現的, "flash scope."
        由于這是一個form, 所以在Struts中我們需要為Struts指定一個ActionForm。需要在name屬性中提供form的名稱,同樣地,我們也需要在forward 節點中舉加入redirect屬性為true。

    <struts-config>
         ...
          <action-mappings>
              <action path="/struts/save"
                     type="com.fdar.articles.infoq.conversion.struts.SaveBlogEntryAction"
                     name="blogForm" scope="request">
                 <forward name="success" redirect="true" path="/struts/list.do"/>
              </action>
             ...
          </action-mappings>
    </struts-config>

    Struts2 在result 節點里提供了type 屬性, 默認情況下是"dispatch", 如果需要重定向,則需要設為 "redirect"。

    <struts>
         ...
          <package name="struts2" extends="struts-default" namespace="/struts2">
              <action name="save" method="save"
                     class="com.fdar.articles.infoq.conversion.struts2.BlogAction" >
                 <result type="redirect">list.action</result>
                 <interceptor-ref name="defaultStack"/>
              </action>
             ...
          </package>
    </struts>

    總結
        我們并不可能在這篇文章中覆蓋所有的內容,如果你需要更好的了解整個框架,還有其他的實現方式和選項,這里有幾點可以供你參考:

    • 配置攔截器和攔截器組 - 以Struts2-core JAR 包里的"struts-default.xml" 文件作為例子。"struts-default.xml" 演示了如何配置你自己的攔截器組,包含新的攔截器,你可以嘗試實現自己的攔截器。
    • 配置文件中的通配符模式 - 你可以選擇使用Struts2中的通配符模式來簡化你的配置。
    • 通過 ParameterAware 接口把form值傳入maps中 - 你可以在Struct2中配置,讓所有request的form屬性都存于action的一個map中,這樣就不需要專門再為action指定model / transfer / value object了。這和Struts的dynamic form特點很相似。

        也許到現在為,也許你有個疑問,"遷移后我們的界面是否可以完全重用呢?",答案是yes。你能從這里(http://www.infoq.com/resource/articles/migrating-struts-2-part2/en/resources/convertingtostruts2-part-ii.zip), 下載到我這篇文章中的完整源代碼,你可以自己嘗試把URL的擴展名由".do" 改為 ".action",使用的頁面時一樣的。除此之外,其實用JSTL來代替Struts taglib也是很容易的。
    在下一篇文章中,我們將講述用戶界面,討論themes 和 tags; 如何做validation;  如何重用UI控件。

    posted on 2007-04-18 17:36 蘆葦 閱讀(672) 評論(0)  編輯  收藏 所屬分類: JAVAStruts
    主站蜘蛛池模板: 亚洲AV无码日韩AV无码导航| 亚洲天堂一区在线| 在线看片免费人成视频久网下载| 久久久久久a亚洲欧洲aⅴ| 国产男女爽爽爽爽爽免费视频 | 青青青亚洲精品国产| 久久精品国产亚洲精品| 亚洲精品视频在线观看免费| 国产精品亚洲专区无码WEB| 亚洲国产精品va在线播放| 拨牐拨牐x8免费| 国产裸体美女永久免费无遮挡| 亚洲国产精品一区二区久| 亚洲第一福利网站在线观看| 最近中文字幕完整免费视频ww | 亚洲另类激情综合偷自拍| 四虎永久成人免费影院域名| 麻豆成人久久精品二区三区免费| 亚洲日韩国产欧美一区二区三区| 亚洲成A人片在线观看WWW| 国产在线观看免费视频播放器| 免费无码又爽又刺激高潮视频| 亚洲av无码专区青青草原| 亚洲五月激情综合图片区| 亚洲av区一区二区三| 成人女人A级毛片免费软件| a在线视频免费观看| 久久久久久久久无码精品亚洲日韩| 亚洲国产综合专区在线电影| 亚洲日韩国产精品乱| 毛片免费视频播放| 91精品国产免费入口| 国产特黄特色的大片观看免费视频 | 亚洲一级毛片免费看| 国产免费高清69式视频在线观看| 亚洲色大成网站www永久男同| 91亚洲国产在人线播放午夜| 黑人大战亚洲人精品一区 | 亚洲国产精品综合久久网各| 亚洲精品无码永久在线观看你懂的| 最好免费观看韩国+日本|