☆藍色夢想☆

          世界總是反反覆覆錯錯落落地飄去 來不及嘆息 生活不是平平淡淡從從容容的東西 不能放棄
          posts - 57, comments - 5, trackbacks - 0, articles - 0

          導(dǎo)航

          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類(56)

          隨筆檔案(57)

          相冊

          Technology

          搜索

          •  

          積分與排名

          • 積分 - 35607
          • 排名 - 1254

          最新評論

          閱讀排行榜

          評論排行榜

          SpringSide團隊翻譯,?轉(zhuǎn)載請注明出處。

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

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

          1. 增加一個新的日志
          2. 察看一個日志
          3. 修改一個日志
          4. 刪除一個日志
          5. 列出所有日至??
          ? ???增刪修改(CRUD),是項目中最為普遍的應(yīng)用。
          ? ???業(yè)務(wù)邏輯類在Struts 和 Struts2 應(yīng)用都是可共用的。如:
          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 只是個簡單的業(yè)務(wù)邏輯類,并不是接口,Struts 和 Struts2 的action皆可調(diào)用其實例。雖然這樣設(shè)計在實際項目中會帶來不必要的耦合,但我們的例子只是集中在討論web層上,所以無關(guān)重要。
          工具箱: 在第一篇文章中,我們談?wù)摿嗽赟truts2 actions中的依賴注入的接口注入方式。這個是servlet 相關(guān)類(HttpServletRequest, HttpServletResponse, PrincipalProxy, 等.)的主要注入方式,但這并不是唯一的方式。
          Struts2 可以使用Spring框架作為默認的容器時,依賴注入的setter方法就可用了。通過在action中加入setter方法(如下演示), Struts2 框架將能從Spring框架中獲得正確的信息,并通過setter加載在action中。
          public?void?setBlogService(BlogService?service)?{
          ?????
          this.blogService?=?service;
          }
          ?


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

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



          這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參數(shù)和返回String結(jié)果。

          然后我們來看看action。我們這個例子中的action有view, create 和 update action。
          The View Action:
          The Create 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"));
          ?????}

          }

          ?

          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都跟隨著同一個模式:

          • 產(chǎn)生一個新的業(yè)務(wù)邏輯對象實例 - 如前面所提到的,我們使用最直接的方式在action中使用業(yè)務(wù)邏輯對象,這表示在每個action中都會產(chǎn)生新的業(yè)務(wù)邏輯對象實例。
          • 從請求中獲得數(shù)據(jù)- 這是兩種形式之一。在view action中,"id"是從HttpServletRequest 對象中直接獲取的。而在create 和 update action 中,則從ActionForm 中取值。ActionForm 與 HttpServletRequest 的調(diào)用方式其實很相似,唯一不同的ActionForm 是bean的從field中取值。
          • 調(diào)用業(yè)務(wù)邏輯- 現(xiàn)在開始生成調(diào)用業(yè)務(wù)邏輯所需的參數(shù)并調(diào)用邏輯。如果參數(shù)(在view action中)是一個簡單對象類型,則轉(zhuǎn)換值時會自動轉(zhuǎn)為正確的類型(如從String轉(zhuǎn)到Integer)。如果參數(shù)是復(fù)雜的對象類型,,則ActionForm 需要通過BeanUtil 來幫忙轉(zhuǎn)成相應(yīng)的對象。
          • 設(shè)定返回的數(shù)據(jù) - 如果需要把數(shù)據(jù)返回顯示給用戶,那則要把這個數(shù)據(jù)設(shè)在HttpServletRequest 的attribute 中返回。
          • 返回一個 ActionForward- 所有 Struts action的最后都需要找到并返回其相應(yīng)的 ActionForward 對象.
          ?????最后的兩個action,remove和list action, 只有很少的差別。remove action如下所示,沒有用BlogForm類. 通過從request的attribute中獲取"id"(和view action相似),就能調(diào)用業(yè)務(wù)邏輯完成其需要的工作。在下面我們介紹配置時,你可以看到它并沒有返回任何數(shù)據(jù),因為它的"success"返回結(jié)果其實是執(zhí)行remove后再執(zhí)行了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并不需要任何的用戶輸入,它只是簡單地調(diào)用了業(yè)務(wù)邏輯的無參方法,同時返回所有的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中,可選的實現(xiàn)方式有很多,可以像Struts那樣每個需求用例對應(yīng)一個action,也可以用一個action對應(yīng)所有需求用例。但在我們的例子中,使用的方法是我認為最佳的解決方案 - 在一個action類中實現(xiàn)整套CRUD功能。
          ? ???也許你人為把list需求用例也同樣地整合到同一個action類里會比較好,而我認為把list的功能分到另外一個action中,會減少容易產(chǎn)生的混淆,因為list用例中并不需要Blog這個類作為屬性,而在其他用例中則需要。

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


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

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

          • 循環(huán)讀取HTTP request中的attribute
          • 查找當前request attribute中是否有和action中的setter中的屬性匹配的
          • 有則根據(jù)attribute從HttpServletRequest 里取出其值
          • 把取出來的值由String轉(zhuǎn)成setter中相應(yīng)的類型
          • 調(diào)用setter把該轉(zhuǎn)換后的值注入action中
          提示: 當調(diào)用action時,如果發(fā)現(xiàn)不明原因使不能正確地通過setter注入值情況下,第一步最好是先檢查下各攔截器,確保它們都已作用于該action。因為這些意外通常有時由攔截器設(shè)置不當形成的,檢查是否各個攔截器都已起作用,并看看它們作用的順序,因為有些情況下它們間會相互影響而產(chǎn)生錯誤。
          ? ? 現(xiàn)在我們已經(jīng)有基于String類型的form bean中取值的方法或者是自動把request的attributes 注入到action的方法,那下一步就是如何把值傳入 domain object 或 value / transfer object的屬性中去。其實這很簡單,你只需要實現(xiàn)ModelDriven 接口(即實現(xiàn)getModel()方法)就可以了,確保ModelDrivenInterceptor 攔截器已作用于action。
          ? ? 除了會調(diào)用action中的setter外,model 首先檢查是否有和setter可以匹配當前的attribute名。如果在model中沒有這個attribute相應(yīng)的setter,則會再在action上找相應(yīng)的setter來設(shè)值。
          ? ? 在BlogAction 的例子中我們可以看到如何很靈活地使用這些方法,首先通過prepare() 方法根據(jù)Id獲取相應(yīng)的 Blog model object 或新建一個instance, 然后再根據(jù)把request中相應(yīng)的屬性注入Blog instance中和action中。
          ? ? 以上的兩個功能使得現(xiàn)在調(diào)用action那么簡單 - 調(diào)用具體的業(yè)務(wù)邏輯,和把數(shù)據(jù)設(shè)在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對象去返回數(shù)據(jù)給JSP,所以也需要實現(xiàn)ServletRequestAware 接口。但是,因為它并不需要任何輸入值,所以就不需要實現(xiàn)其他的接口了。以下是它的具體實現(xiàn):
          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;
          ?????}


          }


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


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

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


          2. Action 配置
          ? ? 在Struts 中forward 節(jié)點指定了action處理后,結(jié)果將重定向到哪個相應(yīng)的頁面。type屬性指定了action的類,scope 屬性保證了form beans只在request范圍內(nèi)。
          <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節(jié)點提供了它所需要調(diào)用的類的完整路徑
          <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 方法去調(diào)用action(在BlogAction 類中大多數(shù)方法如此), 則需要在action節(jié)點的 method 屬性里加入方法名,下面就是個例子,這時候update方法將會被調(diào)用。

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


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


          3. 再重定向配置
          ? ? 當我們提交表格的時候,我們需要重定向到更新后的結(jié)果頁面。這個通常稱為 "post-redirect pattern" 或, 最近出現(xiàn)的, "flash scope."
          ? ? 由于這是一個form, 所以在Struts中我們需要為Struts指定一個ActionForm。需要在name屬性中提供form的名稱,同樣地,我們也需要在forward 節(jié)點中舉加入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 節(jié)點里提供了type 屬性, 默認情況下是"dispatch", 如果需要重定向,則需要設(shè)為 "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>?

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

          • 配置攔截器和攔截器組 - 以Struts2-core JAR 包里的"struts-default.xml" 文件作為例子。"struts-default.xml" 演示了如何配置你自己的攔截器組,包含新的攔截器,你可以嘗試實現(xiàn)自己的攔截器。
          • 配置文件中的通配符模式 - 你可以選擇使用Struts2中的通配符模式來簡化你的配置。
          • 通過 ParameterAware 接口把form值傳入maps中 - 你可以在Struct2中配置,讓所有request的form屬性都存于action的一個map中,這樣就不需要專門再為action指定model / transfer / value object了。這和Struts的dynamic form特點很相似。
          ??? 也許到現(xiàn)在為,也許你有個疑問,"遷移后我們的界面是否可以完全重用呢?",答案是yes。你能從這里, 下載到我這篇文章中的完整源代碼,你可以自己嘗試把URL的擴展名由".do" 改為 ".action",使用的頁面時一樣的。除此之外,其實用JSTL來代替Struts taglib也是很容易的。
          在下一篇文章中,我們將講述用戶界面,討論themes 和 tags; 如何做validation;??如何重用UI控件。
          主站蜘蛛池模板: 灵川县| 绥芬河市| 宁波市| 高平市| 杭锦旗| 专栏| 临邑县| 乌拉特中旗| 苏尼特左旗| 遂溪县| 包头市| 阳新县| 高陵县| 措勤县| 通河县| 新巴尔虎左旗| 玛曲县| 德惠市| 乌鲁木齐县| 常宁市| 独山县| 麻城市| 福清市| 枣强县| 石阡县| 富锦市| 突泉县| 玉溪市| 富阳市| 宕昌县| 文登市| 和顺县| 罗田县| 耿马| 济源市| 开阳县| 南郑县| 青浦区| 上饶市| 郯城县| 泰和县|