但在struts2里面,由于只能返回字符串,這個字符串是在配置文件中的result. 會產生一些困擾.
只想出下面的解決方法. 正確的解決方法,尋找中...
解決這個問題的方法步驟:
1.在struts2的配置文件中,配置一個global-results, 如下.
<global-result>
<result name="forwardURL" type="redirect">${forwardUrl}</result>
</global-results>
其中forwardUrl,即action中的forwardUrl的值
2.在action中定義一個String forwardUrl, 當要自定義轉向時,給這個forwardUrl賦值,值為要轉向的url,如:"/aaa.jsp";
3.在action中返回 return "forwardURL";
其實,Struts 1.x在此部分已經做得相當不錯了。它極大地簡化了我們程序員在做國際化時所需的工作,例如,如果您要輸出一條國際化的信息,只需在代碼包中加入FILE-NAME_xx_XX.properties(其中FILE-NAME為默認資源文件的文件名),然后在struts-config.xml中指明其路徑,再在頁面用<bean:message>標志輸出即可。
不過,所謂“沒有最好,只有更好”。Struts 2.0并沒有在這部分止步,而是在原有的簡單易用的基礎上,將其做得更靈活、更強大。
下面讓我們看一個例子——HelloWorld。這個例子演示如何根據用戶瀏覽器的設置輸出相應的HelloWorld。
![]() |
Struts 2.0有兩個配置文件,struts.xml和struts.properties都是放在WEB-INF/classes/下。
|
![]() |
在此想和大家分享一個不錯的編寫properties文件的Eclipse插件(plugin),有了它我們在編輯一些簡體中文、繁體中文等Unicode文本時,就不必再使用native2ascii編碼了。您可以通過Eclipse中的軟件升級(Software Update)安裝此插件,步驟如下: 1、展開Eclipse的Help菜單,將鼠標移到Software Update子項,在出現的子菜單中點擊Find and Install;
2、在Install/Update對話框中選擇Search for new features to install,點擊Next; 3、在Install對話框中點擊New Remote Site; 4、在New Update Site對話框的Name填入“PropEdit”或其它任意非空字符串,在URL中填入http://propedit.sourceforge.jp/eclipse/updates/; 5、在Site to include to search列表中,除上一步加入的site外的其它選項去掉,點擊Finsih; 6、在彈出的Updates對話框中的Select the features to install列表中將所有結尾為“3.1.x”的選項去掉(適用于Eclipse 3.2版本的朋友); 7、點擊Finish關閉對話框; 8、在下載后,同意安裝,再按提示重啟Eclipse,在工具條看到形似vi的按鈕表示安裝成功,插件可用。此時,Eclpise中所有properties文件的文件名前有綠色的P的圖標作為標識。 |
之所以說Struts 2.0的國際化更靈活是因為它可以能根據不同需要配置和獲取資源(properties)文件。在Struts 2.0中有下面幾種方法:
上面我列舉了四種配置和訪問資源的方法,它們的范圍分別是從大到小,而Struts 2.0在查找國際化字符串所遵循的是特定的順序,如圖3所示:
假設我們在某個ChildAction中調用了getText("user.title"),Struts 2.0的將會執行以下的操作:
許多情況下,我們都需要在動行時(runtime)為國際化字符插入一些參數,例如在輸入驗證提示信息的時候。在Struts 2.0中,我們通過以下兩種方法做到這點:
開發國際化的應用程序時,有一個功能是必不可少的——讓用戶快捷地選擇或切換語言。在Struts 2.0中,通過ActionContext.getContext().setLocale(Locale arg)可以設置用戶的默認語言。不過,由于這是一個比較普遍的應用場景(Scenario),所以Struts 2.0為您提供了一個名i18n的攔截器(Interceptor),并在默認情況下將其注冊到攔截器鏈(Interceptor chain)中。它的原理為在執行Action方法前,i18n攔截器查找請求中的一個名為"request_locale"的參數。如果其存在,攔截器就將其作為參數實例化Locale對象,并將其設為用戶默認的區域(Locale),最后,將此Locale對象保存在session的名為“WW_TRANS_I18N_LOCALE”的屬性中。
下面,我將提供一完整示例演示它的使用方法。
上述代碼的原理為,LangSelector.jsp先實例化一個Locales對象,并把對象的Map類型的屬性locales賦予下拉列表(select) 。如此一來,下拉列表就獲得可用語言的列表。大家看到LangSelector有<s:form>標志和一段Javascript腳本,它們的作用就是在用戶在下拉列表中選擇了后,提交包含“reqeust_locale”變量的表單到Action。在打開頁面時,為了下拉列表的選中的當前區域,我們需要到session取得當前區域(鍵為“WW_TRANS_I18N_LOCALE”的屬性),而該屬性在沒有設置語言前是為空的,所以通過值棧中locale屬性來取得當前區域(用戶瀏覽器所設置的語言)。
你可以把LangSelector.jsp作為一個控件使用,方法是在JSP頁面中把它包含進來,代碼如下所示:![]() |
可能大家會問為什么一定要通過Action來訪問頁面呢? 你可以試一下不用Action而直接用JSP的地址來訪問頁面,結果會是無論你在下拉列表中選擇什么,語言都不會改變。這表示不能正常運行的。其原因為如果直接使用JSP訪問頁面,Struts 2.0在web.xml的配置的過濾器(Filter)就不會工作,所以攔截器鏈也不會工作。 |
言歸正傳,本文的目的主要是介紹在Struts 2中實現控制反轉。
眾所周知,Struts 2是以Webwork 2作為基礎發展出來。而在Webwork 2.2之前的Webwork版本,其自身有一套控制反轉的實現,Webwork 2.2在Spring 框架的如火如荼發展的背景下,決定放棄控制反轉功能的開發,轉由Spring實現。值得一提的是,Spring確實是一個值得學習的框架,因為有越來越多的開源組件(如iBATIS等)都放棄與Spring重疊的功能的開發。因此,Struts 2推薦大家通過Spring實現控制反轉。
首先,在開發環境中配置好Struts 2的工程。對這部分仍然有問題的朋友,請參考我的早前的文章。
然后,將所需的Spring的jar包加入到工程的構建環境(Build Path)中,如下圖1所示:
圖1 所依賴的Spring的jar包
本文使用的是Spring 2.0,Spring強烈建議大家在使用其jar包時,只引用需要的包,原因是Spring是一個功能非常強大的框架,其中有些功能是您不需要的;而且Spring提倡的是“按需所取”,而不是EJB的“愛我就要愛我的一切”。當然,如果你怕麻煩或者是不清楚每個包的作用,引用一個Spring的總包也未嘗不可。
接下來,就要修改WEB-INF\web.xml文件了,內容為:
大家一看便知道,主要是加入Spring的ContextLoaderListener監聽器,方便Spring與Web容器交互。
緊接著,修改Struts.properties文件,告知Struts 2運行時使用Spring來創建對象(如Action等),內容如下:
再下來,遵循Spring的原則——面向接口編程,創建接口ChatService,代碼如下:
然后,再創建一個默認實現ChatServiceImpl,代碼如下:
接下來,就該新建Action了。tutorial.ChatAction.java的代碼如下:
ChatAction類使用屬性(Getter/Setter)注入法取得ChatService對象。
然后,配置Spring的applicationContext.xml(位于WEB-INF下)文件,內容如下:
上述代碼有二點值得大家注意的:
接下來,在classes/struts.xml中配置Action,內容如下:
這里的Action和平常不同的就是class屬性,它對應于Spring所定義的bean的id,而不是它的類全名。
最后,讓我們看看/UserList.jsp,內容如下:
大功告成,分布運行應用程序,在瀏覽器中鍵入http://localhost:8080/Struts2_IoC/Chat.action,出現如圖2所示頁面:
圖2 /ListUser.jsp
通過Spring在Struts 2上實現控制反轉是強烈推薦的做法,當然您也可以組合其它的實現(如Pico等)。
但是,所謂“金無赤金,人無完人”,Struts自身也有不少的缺點:
這些缺點隨著Web的發展越來越明顯。這就促生了Struts 2.0,它的誕生能很好的解決上述問題。 好啦,廢話就不多說了,現在就讓我們感受一下的Struts 2.0的魅力吧。
點擊菜單File\New\Project,出現如圖1所示對話框
圖1 新建工程對話框
選擇Web\Dynamic Web Project,點擊“Next”,出現圖2對話框
圖2 新建動態Web工程對話框
在“Project Name”中鍵入Struts2_HelloWorld,點擊“New”,出現以下對話框
圖3 新建服務器運行時對話框
選擇“Apache\Apache Tomat v5.5”,點擊“Next”,出現以下對話框
圖4新建服務器運行時對話框
點擊“Finish”,關閉對話框。
圖5 Struts 2.0的lib目錄
按ctr+a全選,復制,再轉到Eclipse窗口,在“Project Explorer”子窗口中選中Struts2_HelloWorld\WebContent\WEB-INF\lib,然后粘貼。經過Eclipse自動刷新“Project Explorer”子窗口,剛才所粘貼的jar文件應該會出現在Struts2_HelloWorld\Java Resources: src\Libraries\Web App Libraries下,如圖6所示:
圖6 Project Explorer子窗口
右鍵點擊,Struts2_HelloWorld\Java Resources: src,出現如圖7所示菜單
圖7 新建Other菜單
點擊“Other”,出現新建對話框,如圖8所示
圖8 新建對話框
點擊“Next”,出現新建文件對話框,如圖9所示
圖9 新建文件對話框
在“File name”中鍵入sturts.xml,點擊“Finish”,然后將struts.xml的內容修改為:
右鍵點擊Struts2_HelloWorld\WebContent,出現如圖10所示的菜單
圖10 新建Other菜單
點擊“Other”,出現新建對話框,如圖11所示
圖11 新建對話框
選擇Web\HTML,點擊“Next”出現如圖12所示的對話框
圖12 新建HTML頁面對話框
在“File Name”中鍵入index.html,點擊“Next”,出現如圖13所示的對話框
圖13 模板選擇對話框
點擊“Finish”,將index.html的內容修改為以下內容:
右鍵點擊Struts_HelloWorld,出現如圖14所示的菜單
圖14 工程菜單
點擊“Export\WAR file”,出現如圖15所示的對話框
圖15 輸出對話框
選擇“Web\WAR file”,點擊“Next”,出現如圖16所示的對話框
圖16 輸出路徑對話框
輸入war文件的路徑(如%tomcat%\webapps\Struts2_HelloWorld.war),點擊“Finish”關閉對話框。
打開你的Internet Explorer,鍵入http://localhost:8080/Struts2_HelloWorld/,窗口輸出如圖17所示
圖17 Hello World窗口
右鍵點擊Struts2_HelloWorld\Java Resources: src,出現如圖18所示菜單
圖18 新建菜單"
點擊“New\Package”,出現如圖19所示對話框
圖19新建Java類包對話框
在“Name”鍵入tutorial,點擊“Finish”關閉對話框。
右鍵點擊Struts2_HelloWorld\Java Resources: src\tutorial,出現如圖20所示菜單
圖20 新建菜單
點擊“New\Class”,出現如圖21所示對話框
圖21 新建Java類對話框
在“Name”中鍵入HelloWorld,在“Superclass”中鍵入com.opensymphony.xwork2.ActionSupport,點擊“Finish”關閉對話框。將HelloWorld.java的內容修改為:
參考“新建index.html文件”步驟,彈出如圖22所示對話框
圖22 新建對話框
點擊“Next”, 進入下一步,如圖23所示
圖23 新建JSP對話框
在“File name”鍵入SayHello.jsp,點擊“Next”進入下一步,如圖24所示
圖24 模板選擇對話框
點擊“Finish”關閉對話框,并將SayHello.jsp的內容修改為:
先停止tomcat, 再將tomcat里webapps下的Struts2_HelloWorld.war和Struts2_HelloWorld文件夾刪除,參照“將應用程序打包到tomcat上”重新發布應用程序。
打開Internet Explorer,鍵入http://localhost:8080/Struts2_HelloWorld/SayHello.jsp,窗口輸出如圖25所示
圖25 SayHello.jsp
在“Name”鍵入字符串(如World),點擊Submit,轉到HelloWorld.jsp頁面,如圖26所示
圖26 HelloWorld.jsp
在文章開始的時候提及,單元測試困難是Struts一大缺點。現在讓我們在體驗一下,在Struts 2.0中是如何進行測試的。
右鍵點擊Struts2_HelloWorld\Java Resources: src\tutorial,彈出如圖27所示對話框
圖27 新建菜單
點擊“Next\Other”
圖28 新建對話框
選擇“Java\JUnit\JUnit Test Case”,點擊“Next”
圖29 新建JUnit 測試用例對話框
選擇“New JUnit 4 test”,在“Name”中鍵入HelloWorldTest,在“Class under test”鍵入tutorial.HelloWorld,點擊“Next”
圖30 選擇方法對話框
選中HelloWorld\execute方法,點擊Finish。如果生成的HelloWorldTest.java文件的圖標(Icon)出現紅色交叉標志,請進行以下步驟添加JUnit 4的jar包。
右鍵點擊Struts2_HelloWorld,出現如圖所示菜單。
圖31 新建菜單
點擊“Build Path\Add Libararis”,彈出圖32對話框
圖32 添加庫對話框
選中“JUnit”,點擊“Next”
圖33 選擇版本對話框
選擇“JUnit 4”,點擊“Finish”關閉對話框,并將HelloWorldTest.java的內容修改為:
右鍵點擊Struts2_HelloWorld\Java Resources: src\tutorial\HelloWorldTest.java,彈出如圖34所示菜單
圖34 運行為菜單
點擊“Run As\JUnit Test”,出現JUnit子窗口如圖35所示
圖35 JUnit子窗口
圖35的綠色矩形表示,所有單元測試通過。
上面的例子簡單地演示了,Web 應用程序的基本操作,也即是,頁面輸入->Action處理->再輸出到另外頁面。Struts 2.0的簡單易用、方便測試相信也會給大家留下不錯的印象吧。我相信,Struts 2.0作為一個全新的Web架構,將會再次掀起Web開發的熱潮。 不過,Struts 2.0還在測試中,正式版的發布還需些時日,所以文檔方面可能有所欠缺。請大家繼續留意我的博客,我會盡我所能為大家寫更多關于Struts 2.0的文章。
?? SpringSide對Struts做了兩層封裝:
?? 第一層:StrutsAction,繼承于DispatchAction,附帶一些Utils函數,另外注冊了幾個Converter。
?? 第二層:StruttsEntityAction,繼承于StrutsAction, 演示了如何為單個對象的CRUD操作(增刪改查)封裝了默認Action,子類只需要范型聲明所管理的對象類型和管理類型,即擁有CRUD操作的能力。
????大家各自項目的習慣不同,流程,可以參考SpringSide的封裝,封裝自己的版本。
??? 典型子類代碼如下:
public class UserAction extends StrutsEntityAction<User,UserManager> { private UserManager userManager; public void setUserManager(UserManager userManager) { this.userManager = userManager; } }
?? 第一 extends StrutsEntityAction<User,UserManager>,聲明管理的Entity類型是User,管理的Entity是UserManager,UserManager必須實現EntityDao<T>接口;
?? 第二 定義userManager用于依賴注入的setter函數;
???? StrutsEntityAction 會持有一個EntityDao接口的實體來做CRUD的操作,子類通過在泛型中聲明UserAction<User, UserManager>,自動查找屬性中類型為UserManager的屬性作為EntityDao。如果子類有多個UserManager屬性(很少的情況),就需自行實現getEntityManager()函數。
???? CRUD現在主要封裝了list、edit、view、save、delete 5個流程,一般會調用doListEntity、doGetEntity、doNewEntity、doSaveEntity(),doDeleteEntity 5個業務函數去做相應的業務操作。
???? 在controller中很重要的request 數據與POJO的轉換,由initEntity、initForm? 兩個函數完成。
???? initEntity 先調用bindObject 函數用BeanUtils 直接copy lazyBean的FormBean 和 Entity POJO,然后調用子類的onInitEntity()函數。initForm是同樣的原理。
?????通常還有一些輔助的對象,比如Book 修改頁要有Category列表做下拉選擇框,這些輔助對象統一子類重載onRefrence()函數放入request.attributes.
?? EntityAction必須預留足夠的擴展點給子類重載,具體函數注釋見StrutsEntityAction的JavaDoc, 包括:
??? 1.list、edit、view、save、delete: 五種action的流程封裝;
?? 2.doListEntity、doGetEntity、doNewEntity、doSaveEntity(),doDeleteEntity: 五種業務函數調用;
? ?3.initEntity、initForm?: FormBean與業務對象的初始化函數及refrenceData,onInitForm,onInitEntity 三個回調函數;
?? 4.savedMessage、deletedMessage: 兩種業務操作成功后顯示的信息的回調函數。
??幾個回調函數在子類重載,而如果幾個封裝函數不合心意,請重新擴展一個基類或完全重新封裝。