京山游俠

          專注技術,拒絕扯淡
          posts - 50, comments - 868, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          SpringSide 3 中的 Struts 2

          Posted on 2008-12-24 13:36 京山游俠 閱讀(11628) 評論(13)  編輯  收藏 所屬分類: SpringSide開發實戰

          在SpringSide 3 中,使用的MVC框架是Struts 2。Struts 2 向對于Struts 1 來說,具有相當多的優點,有很多人都說,用過Struts 2之后,再也不想看Struts 1了。然而,任何東西都有它的復雜性,Struts 2也不例外,SpringSide 3做了很多工作來簡化Struts 2 的使用。

          先來說說Struts 2的特點:
          1、編寫Action變得簡單了,Action變成了簡單的POJO,再也不用和ActionForm、ActionForward打交道了,返回的時候直接返回字符串即可。如果要訪問Servlet API,則直接使用ServletActionContext類的靜態方法。
          2、Struts 2提供了插件機制,允許我們自己為它編寫插件,當然,要我自己寫是不現實的,但是面對別人寫的琳瑯滿目的插件,我一樣會昏頭。再網上隨便一搜,就可以發現40多種Struts 2插件。SpringSide 3選擇的CodeBehind,就是一種Struts 2插件,它的目的是為了簡化配置。
          3、Struts 2提供了攔截器機制,之所以編寫Action的任務那么簡單,靠的都是這些攔截器,比如它們可以自動解析Web表單和URL參數,把它們注入到Action中。
          4、Struts 2提供了豐富的taglib,當然,豐富也代表著我們要化更多的時間去學習。
          5、Struts 2依然提供了Validator和i18n支持。
          等等...

          下面,我們來看看SpringSide 3是怎么使用Struts 2的吧。SpringSide 3的主要目標是降低我們使用Struts 2的復雜性,所以,它選擇了這些辦法:
          1、沒有使用Validator和i18n,對數據的驗證交給了JQuery,這變成了表現層的任務,而且JQuery也可以使用AJAX從服務器端進行驗證。至于i18n,江南白衣說小網站用不上。
          2、沒有使用Struts 2的UI標簽,當然也就沒有使用FreeMaker或SiteMesh了。

          當然,省掉了一些東西,就省掉了我們不少的學習時間。對于Struts 2核心的一些東西,我們看看它是怎么做的:

          1、使用CodeBehind插件來簡化配置。使用CodeBehind后,我們就可以不用配置result了,它可以根據我們Action的返回值自動猜測返回的視圖頁面,它猜測的規則是這樣的:返回頁面的路徑為struts.codebehind.pathPrefix + package namespace + action name + action returnvalue?+?.jsp,action returnvalue為success時,值為空,為其他時,值為"-" + return type。我們來看看SpringSide 3生成的項目中關于Struts 2的配置文件:
          001.PNG
          其中struts.codebehind.pathPrefix設置為“/WEB-INF/jsp/”,package的namespace沒有設置,所以,如果我們的Action為UserAction,則返回success時,就會返回到/WEB-INF/jsp/user.jsp,如果返回input,則返回到/WEB-INF/jsp/user-input.jsp。這里江南白衣玩了一個狡猾,他把所有的jsp頁面放到WEB-INF目錄中,別人就沒有辦法直接訪問了,這樣就可以簡化Acegi的配置工作。

          2、關于攔截器棧
          在上面講Struts 2的特點時,我已經說了Struts 2中攔截器的重要作用,在上面的截圖中,package的配置沒有做別的什么事,主要就是配置了攔截器棧。那么攔截器棧是怎么使用的呢?它是在Action類中通過@ParentPackage指定的,如下面的代碼:
          002.PNG

          下面,我來具體說一下攔截器有什么作用。
          ?例子一、我們知道Struts 2中的Action是和Servlet API解耦的,那么如果我們要在Action中訪問Servlet API怎么辦呢?一種辦法就是使用ServletActionContext,如下圖:
          003.PNG
          另外一種辦法,就是讓我們的Action實現ServletRequestAware接口,如下代碼:

          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;
          ???}
          }
          這時候,ServletConfigInterceptor 攔截器就會把request對象注入到我們的Action中。

          例子二、ParametersInterceptor 攔截器會自動解析web表單或URL參數,并把它們注入到Action中。但是很多時候,我們不愿意我們的Action具有太多的屬性,因為一大堆的get、set方法看起來太亂糟糟,我們希望有一個專門的Model對象來存儲這些值,而且剛好我們為Hibernate設計的Entity類用來做Model正合適。這時,我們可以讓我們的Action實現ModelDriven接口,讓getModel()方法返回我們的entity對象即可。這正是SpringSide 3采取的方法,如下圖的代碼片斷:
          004.PNG
          這時候,ModelDrivenInterceptor攔截器就會幫助我們把解析的URL參數或表單數據注入到entity的屬性中,而不是Action中。

          例子三、Preparable 接口聯合PrepareInterceptor攔截器一起工作,可以讓action在執行execute() 方法前, 執行一個prepare()方法,這也正是SpringSide 3的工作方式。

          3、關于Action
          有了上面對CodeBehind的理解和對攔截器棧的理解后,再來理解SpringSide 3中的Action就再簡單不過了,SpringSide 3中Action的繼承樹如下:
          005.PNG

          其中ActionSupport類是Struts 2提供的,另外兩個類是白衣自己擴展的。其中SimpleActionSupport主要是提供了一些繞過jsp頁面直接輸出字符串的方法,不值一談。而CRUDActionSupport就比較復雜,如下:
          public?abstract?class?CRUDActionSupport<T>?extends?SimpleActionSupport?implements?ModelDriven<T>,?Preparable?{
          ????
          /**
          ?????*?進行CUD操作后,以redirect方式重新打開action默認頁的result名.
          ?????
          */
          ????
          public?static?final?String?RELOAD?=?"reload";

          ????
          /**
          ?????*?Action函數,默認action函數,默認指向list函數.
          ?????
          */
          ????@Override
          ????
          public?String?execute()?throws?Exception?{
          ????????
          return?list();
          ????}

          ????
          /**
          ?????*?Action函數,顯示Entity列表.
          ?????*?return?SUCCESS.
          ?????
          */
          ????
          public?abstract?String?list()?throws?Exception;

          ????
          /**
          ?????*?Action函數,新增或修改Entity.?
          ?????*?return?RELOAD.
          ?????
          */
          ????
          public?abstract?String?save()?throws?Exception;

          ????
          /**
          ?????*?Action函數,刪除Entity.
          ?????*?return?RELOAD.
          ?????
          */
          ????
          public?abstract?String?delete()?throws?Exception;

          ????
          /**
          ?????*?在save()前執行二次綁定.
          ?????
          */
          ????
          public?void?prepareSave()?throws?Exception?{
          ????????prepareModel();
          ????}

          ????
          /**
          ?????*?在input()前執行二次綁定.
          ?????
          */
          ????
          public?void?prepareInput()?throws?Exception?{
          ????????prepareModel();
          ????}

          ????
          /**
          ?????*?屏蔽公共的二次綁定.
          ?????
          */
          ????
          public?void?prepare()?throws?Exception?{
          ????}

          ????
          /**
          ?????*?等同于prepare()的內部函數.?
          ?????
          */
          ????
          protected?abstract?void?prepareModel()?throws?Exception;
          }


          第一,它做了把CRUD操作放到了同一個Action中的操作,這樣可以少寫幾個Action。這個工作難度不大,我覺得白衣此舉,主要是為了規范CRUD函數的命名。在Struts 2中,如果我們要訪問的不是默認的excute方法,可以使用如/user!save.action的格式,這樣訪問的就是UserAction的save方法。
          第二,它實現了ModelDriven接口和Preparable接口,關于這兩個接口,我在前面講攔截器的時候已經提到過了,所以很容易理解。我們可以把我們為Hibernate設計的entity類作為Model,也可以把初始化這些entity的工作放到prepareSave()和prepareInput()方法中,這兩個方法將會在save()和input()方法執行前自動執行。
          第三,它定義了一個靜態變量RELOAD,定義這個變量的目的是為了定義一個result的需要。CodeBehind中,大部分的result可以自己猜測,對于不能猜測的,需要使用@Results指定,如下代碼:
          006.PNG

          ?

          ?好了,對SpringSide 3中Struts 2的分析就寫到這里了。總之,使用SpringSide 3時,對于Action這一塊非常簡單,如果不設及到CRUD操作,就繼承SimpleActionSupport,如果涉及到CRUD操作,就繼承CRUDActionSupport,并在getModel()\save()\prepareSave\input()\prepareInput()等框框中填入適當的代碼即可。


          評論

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2008-12-24 15:38 by 虎嘯龍吟
          非常不錯!比看springSide的源碼清晰多了。節省了大量的時間。期待有更多的
          springSide的文章。

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2008-12-24 16:27 by blablalba
          Hey,大俠,我從springside的論壇上尋到這兒來。
          http://forum.springside.org.cn/viewthread.php?tid=3232&extra=&page=1
          是關于配多數據源的,你在回帖中提到的事務配置方面的問題我也碰到了。
          <tx:annotation-driven transaction-manager="transactionManager" />

          ms不能有多個的<tx:annotation-driven>??

          現在提供一個解決方案么?不要JTA咯

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2008-12-24 17:08 by lx281
          謝謝,文章寫的很清晰明白,學習struts2中,順便看看springside

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2008-12-24 20:11 by 海邊沫沫
          @blablalba
          等我的下一篇,下一篇我會寫關于數據訪問方面的內容。

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2009-01-15 15:19 by 向往藍天
          寫的很好啊,謝謝了,我剛開始使用springside
          看了你的前一篇文章,覺得思路清晰多了,
          我是使用maven 來管理的,但是maven 我剛開始接觸
          而springside的主頁上的文檔說的比較凌亂,應該是自己的技術太淺的緣故
          能不能麻煩你寫便關于maven 結合eclipse3.4的文章啊

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2009-01-16 11:23 by talangniao
          如果我想使用FreeMarker作模板,
          怎樣配置映射到WEB-INF/ftl/下的.ftl文件?

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2009-01-16 11:27 by talangniao
          使用FreeMarker作模板,是不是要進行配置namespace?
          要怎樣進行配置?

          # re: SpringSide 3 中的 Struts 2[未登錄]  回復  更多評論   

          2009-02-11 10:49 by sniper
          看了文章寫的挺詳細的,中間有個不明白的地方:prepareSave()和prepareInput()是如何調用的,因為看了Preparable接口只有一個方法prepare(),在實現接口時也只是一個空方法,不知道是如何調用到相應的prepare*方法的,希望能幫忙說明一下。

          # re: SpringSide 3 中的 Struts 2[未登錄]  回復  更多評論   

          2009-02-11 10:57 by sniper
          呵呵查看了一些關于PrepareInterceptor的文章,原來是攔截器中處理的。http://willson-tien.javaeye.com/blog/270596

          # re: SpringSide 3 中的 Struts 2[未登錄]  回復  更多評論   

          2009-02-12 22:36 by haha
          寫得不錯,謝謝。springside3還是有很多難點之處。下載的源代碼注釋不是很清楚,希望樓主能寫更詳細的springside的說明文檔和流程結構圖。
          再次感謝!

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2009-04-28 10:52 by fmq2008
          user.action的 url 怎么在ss3中配置成user.html

          # re: SpringSide 3 中的 Struts 2  回復  更多評論   

          2009-05-06 11:17 by 海邊沫沫
          @fmq2008
          很簡單,在Struts的配置文件中加入:
          <constant name="struts.action.extension" value="html">

          # re: SpringSide 3 中的 Struts 2[未登錄]  回復  更多評論   

          2009-12-31 13:11 by bean
          如何在原有的攔截器棧中增加配置一個自己的攔截器?
          我添加后,不能起作用,代碼如下
          <package name="crud-default" extends="convention-default">

          <interceptors>
          <interceptor name="checkUserAndEncoding"
          class="CheckUserAndEncodingIntercept" />

          <interceptor-stack name="crudStack">
          <interceptor-ref name="checkUserAndEncoding" />
          <interceptor-ref name="store">
          <param name="operationMode">AUTOMATIC</param>
          </interceptor-ref>
          <interceptor-ref name="paramsPrepareParamsStack" />

          </interceptor-stack>
          </interceptors>
          <default-interceptor-ref name="crudStack" />
          </package>
          主站蜘蛛池模板: 鲁甸县| 秦皇岛市| 太谷县| 鄯善县| 大厂| 聂荣县| 新田县| 连云港市| 噶尔县| 二手房| 内黄县| 佛坪县| 宁河县| 松滋市| 宣恩县| 刚察县| 无极县| 仙游县| 厦门市| 九台市| 邹城市| 大新县| 金昌市| 岳普湖县| 呼和浩特市| 武平县| 巴彦淖尔市| 新安县| 闻喜县| 四会市| 屯留县| 新津县| 天长市| 江油市| 克东县| 伊川县| 贞丰县| 军事| 大连市| 广饶县| 孟州市|