在應用啟動時需要裝入應用初始化數據到context 中。
創建一個類,實現org.apache.struts.action.PlugIn接口,并且在struts-config.xml文件中指定plug-in元素。下面的XML 片斷展示了一個plug-in 聲明以及一個嵌套的set-property元素來設置定制屬性:
Struts提供了一個PlugIn接口,你可以用它來創建在應用啟動時初始化的定制服務。PlugIn接口的Java源代碼示于Example 2-1. (為了清晰起見,去除了JavaDoc 文檔)
為了實現一個plug-in,只需要實現這個接口并且在struts-config.xml文件中聲明這個plug-in 實現。有兩個方法必須被實現:即init()和destroy( ), 它們在插件的生命周期中被調用。Struts 在啟動ActionServlet時實例化plug-in 之后調用init( )。Struts則在ActionServlet被銷毀時調用destroy()方法,通常是在一個用服務器停止時。首先,這個 plug-in 特征似乎是很單純和有限的。然而,通過使用Struts的另外一個特征,即set-property元素,你可以將特殊的信息傳遞到plug-in中。這種能力增強了這些類的靈活性。
set-property元素被幾乎所有定義Struts實體的元素所支持,比如form-bean, action-mapping, action, 以及plug-in。set-property元素有兩個屬性:name和value。Struts調用name屬性的值指定的property的setter方法,將property設置為value屬性的字符串值。 |
對給定plug-in的所有set-property元素都將在調用plug-in的init( )方法之前進行處理。這允許plug-in 在init( )方法中使用屬性的值。
如果對一個plug-in使用多個set-property元素, Struts不能保證它們被調用的順序。每個setter方法都應該獨立于其他任何方法。 |
Struts 將對ActionServlet和plug-in的ModuleConfig的引用作為引數傳遞給init( )方法。ActionServlet允許訪問ServletContext來進行應用范圍的對象存儲。ActionServlet還可以允許你訪問更多高級的容器管理的J2EE 組件,比如數據源和消息隊列。ModuleConfig允許你訪問定義plug-in 的模塊的Struts配置。
每個Struts 應用至少有一個模塊:默認模塊。如果你不熟悉模塊,我們將在第2.5式中講解之。 |
為了更具體一些,請考慮一個簡單的,但仍然相關的例子。你需要定義一個plug-in,它可以使你決定應用何時啟動,以及它啟動和運行了多長時間。你可以使用下面所示的類跟蹤和報告你的應用的運行時間。
創建一個PlugIn接口的實現,比如Example 2-3所示,它實例化了TimeTracker。plug-in 通過plug-in 屬性的值將TimeTracker實例保存在ServletContext中。你可以使用這個值來從Servlet上下文中獲取TimeTracker實例。雖然這個值是硬編碼的,使用屬性也提供了更大的靈活性。
現在你已經有了為plug-in 創建的類,你可以通過在struts-config.xml中加入plug-in元素來將其集成到Struts 應用中。
plug-in 在servlet 上下文中存儲了time tracker對象。可以訪問TimeTracker來顯示關于應用啟動運行時間的信息,下面是相關的JSP 片斷:
你可以使用一個servlet 來載入像Struts plug-in之類的初始化數據。具有load-on-startup初始化參數的servlet,應將其設置為較低的數值,比如1, 一保證它們在應用啟動時載入。容器在實例化Servlet之后將調用servlet的init( )方法。但是Struts plug-in 方式由多個優點。首先,大多數Struts 應用在其初始化設置后不需要修改web.xml文件。必須在web.xml中聲明額外的Servlet意味著要維護額外的文件。其次,如果需要PlugIn接口提供對特定Struts信息的訪問。最后,因為plug-in 的生命周期緊隨ActionServlet的生命周期,所以可以保證在你的Struts應用所需時數據有效。
第2.8式展示了set-property元素的另一種用法。Struts 文檔中關于plug-in 的信息可以訪問http://jakarta.apache.org/struts/userGuide/building_controller.html#plugin_classes.
你也可以使用一個Servlet 上下文listener 來載入初始化數據。
struts.devMode
Whether Struts is in development mode or not
是否為struts開發模式
struts.dispatcher.parametersWorkaround
Whether to use a Servlet request parameter workaround necessary for some versions of WebLogic
(某些版本的weblogic專用)是否使用一個servlet請求參數工作區(PARAMETERSWORKAROUND)
struts.enable.DynamicMethodInvocation
Allows one to disable dynamic method invocation from the URL
允許動態方法調用
struts.freemarker.manager.classname
The org.apache.struts2.views.freemarker.FreemarkerManager implementation class
org.apache.struts2.views.freemarker.FreemarkerManager接口名
struts.i18n.encoding
The encoding to use for localization messages
國際化信息內碼
struts.i18n.reload
Whether the localization messages should automatically be reloaded
是否國際化信息自動加載
struts.locale
The default locale for the Struts application
默認的國際化地區信息
struts.mapper.class
The org.apache.struts2.dispatcher.mapper.ActionMapper implementation class
org.apache.struts2.dispatcher.mapper.ActionMapper接口
struts.multipart.maxSize
The maximize size of a multipart request (file upload)
multipart請求信息的最大尺寸(文件上傳用)
struts.multipart.parser
The org.apache.struts2.dispatcher.multipart.MultiPartRequest parser implementation for a multipart request (file upload)
專為multipart請求信息使用的org.apache.struts2.dispatcher.multipart.MultiPartRequest解析器接口(文件上傳用)
struts.multipart.saveDir
The directory to use for storing uploaded files
設置存儲上傳文件的目錄夾
struts.objectFactory
The com.opensymphony.xwork2.ObjectFactory implementation class
com.opensymphony.xwork2.ObjectFactory接口(spring)
struts.objectFactory.spring.autoWire
Whether Spring should autoWire or not
是否自動綁定Spring
struts.objectFactory.spring.useClassCache
Whether Spring should use its class cache or not
是否spring應該使用自身的cache
struts.objectTypeDeterminer
The com.opensymphony.xwork2.util.ObjectTypeDeterminer implementation class
com.opensymphony.xwork2.util.ObjectTypeDeterminer接口
struts.serve.static.browserCache
If static content served by the Struts filter should set browser caching header properties or not
是否struts過濾器中提供的靜態內容應該被瀏覽器緩存在頭部屬性中
struts.serve.static
Whether the Struts filter should serve static content or not
是否struts過濾器應該提供靜態內容
struts.tag.altSyntax
Whether to use the alterative syntax for the tags or not
是否可以用替代的語法替代tags
struts.ui.templateDir
The directory containing UI templates
UI templates的目錄夾
struts.ui.theme
The default UI template theme
默認的UI template主題
struts.url.http.port
The HTTP port used by Struts URLs
設置http端口
struts.url.https.port
The HTTPS port used by Struts URLs
設置https端口
struts.url.includeParams
The default includeParams method to generate Struts URLs
在url中產生 默認的includeParams
struts.velocity.configfile
The Velocity configuration file path
velocity配置文件路徑
struts.velocity.contexts
List of Velocity context names
velocity的context列表
struts.velocity.manager.classname
org.apache.struts2.views.velocity.VelocityManager implementation class
org.apache.struts2.views.velocity.VelocityManager接口名
struts.velocity.toolboxlocation
The location of the Velocity toolbox
velocity工具盒的位置
struts.xslt.nocache
Whether or not XSLT templates should not be cached
是否XSLT模版應該被緩存
本文轉自福州IT信息網(http://www.fzic.net),詳細出處參考:http://www.fzic.net/SrcShow.asp?Src_ID=990
在Struts2中,radio標簽可以使用一個list來輸出一組radio按鈕,
<s:radio name="sex" list="#{'male','female'}" label="%{getText('app.label.sex')}" />
但是如何設置其中一個被默認選中。
查閱了struts2的文檔,發現radio標簽有一個value屬性是用于對radio的進行預選的: http://struts.apache.org/2.x/docs/radio.html
value: Preset the value of input element.
于是,進行了試驗,<s:radio name="sex" list="#{'male','female'}" label="%{getText('app.label.sex')}" value="male" />
結果失敗了。male的值并沒有被選中,經過反復研究,終于得到了正確的結果:
<s:radio name="sex" list="#{'male','female'}" label="%{getText('app.label.sex')}" value="'male'" />
看到其中的區別了嗎,就是多了兩個單引號。
我認為這是因為value屬性的特性引起的。如果male沒有加引號,那么struts2會去值的堆棧中尋找變量名為male的值,結果找不到。
加上單引號后,struts2(應該是ognl)把'male'認為是一個簡單的字符串。
這樣,radio就能夠正確地匹配到值,使指定的值默認被選中
Struts2提供了一種可插拔方式來管理插件,安裝Struts2的JSON插件與安裝普通插件并沒有太大的區別,一樣只需要將Struts2插件的JAR文件復制到Web應用的WEB-INF/lib路徑下即可。
安裝JSON插件按如下步驟進行:
(1)登陸http://code.google.com/p/jsonplugin/downloads/list站點,下載Struts2的JSON插件的最新版本,當前最新版本是0.7,我們可以下載該版本的JSON插件。
(2)將下載到的jsonplugin-0.7.jar文件復制到Web應用的WEB-INF路徑下,即可完成JSON插件的安裝。
實現Actio邏輯
假設wo,en輸入頁面中包含了三個表單域,這三個表單域對于三個請求參數,因此應該使用Action來封裝這三個請求參數。三個表單域的name分別為field1、field2和field3。
處理該請求的Action類代碼如下:
public class JSONExample { //封裝請求參數的三個屬性 private String field1; private transient String field2; private String field3; //封裝處理結果的屬性 private int[] ints = {10, 20}; private Map map = new HashMap(); private String customName = "custom"; //三個請求參數對應的setter和getter方法 public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } //此處省略了field1和field2兩個字段的setter和getter方法 ... //封裝處理結果的屬性的setter和getter方法 public int[] getInts() { return ints; } public void setInts(int[] ints) { this.ints = ints; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } //使用注釋語法來改變該屬性序列化后的屬性名 @JSON(name="newName") public String getCustomName() { return this.customName; } public String execute() { map.put("name", "yeeku"); return Action.SUCCESS; } } |
serialize:設置是否序列化該屬性
deserialize:設置是否反序列化該屬性。
format:設置用于格式化輸出、解析日期表單域的格式。例如"yyyy-MM-dd'T'HH:mm:ss"。
配置該Action與配置普通Action存在小小的區別,應該為該Action配置類型為json的Result。而這個Result無需配置任何視圖資源。
配置該Action的struts.xml文件代碼如下:
<?xml version="1.0" encoding="GBK"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.i18n.encoding" value="UTF-8"/> <package name="example" extends="json-default"> <action name="JSONExample" class="lee.JSONExample"> <result type="json"/> </action> </package> </struts> |
The Struts 2 Tags can be divided into two types:
The main difference between Struts Generic Tags and Struts UI Tags are:
來源:struts2開發組 翻譯:tianxinet(胖猴)
Action 類:
• Struts1要求Action類繼承一個抽象基類。Struts1的一個普遍問題是使用抽象類編程而不是接口。
• Struts 2 Action類可以實現一個Action接口,也可實現其他接口,使可選和定制的服務成為可能。Struts2提供一個ActionSupport基類去實現 常用的接口。Action接口不是必須的,任何有execute標識的POJO對象都可以用作Struts2的Action對象。
線程模式:
• Struts1 Action是單例模式并且必須是線程安全的,因為僅有Action的一個實例來處理所有的請求。單例策略限制了Struts1 Action能作的事,并且要在開發時特別小心。Action資源必須是線程安全的或同步的。
• Struts2 Action對象為每一個請求產生一個實例,因此沒有線程安全問題。(實際上,servlet容器給每個請求產生許多可丟棄的對象,并且不會導致性能和垃圾回收問題)
Servlet 依賴:
• Struts1 Action 依賴于Servlet API ,因為當一個Action被調用時HttpServletRequest 和 HttpServletResponse 被傳遞給execute方法。
• Struts 2 Action不依賴于容器,允許Action脫離容器單獨被測試。如果需要,Struts2 Action仍然可以訪問初始的request和response。但是,其他的元素減少或者消除了直接訪問HttpServetRequest 和 HttpServletResponse的必要性。
可測性:
• 測試Struts1 Action的一個主要問題是execute方法暴露了servlet API(這使得測試要依賴于容器)。一個第三方擴展--Struts TestCase--提供了一套Struts1的模擬對象(來進行測試)。
• Struts 2 Action可以通過初始化、設置屬性、調用方法來測試,“依賴注入”支持也使測試更容易。
捕獲輸入:
• Struts1 使用ActionForm對象捕獲輸入。所有的ActionForm必須繼承一個基類。因為其他JavaBean不能用作ActionForm,開發者經常創建多余的類捕獲輸入。動態Bean(DynaBeans)可以作為創建傳統ActionForm的選擇,但是,開發者可能是在重新描述(創建)已經存在的JavaBean(仍然會導致有冗余的javabean)。
• Struts 2直接使用Action屬性作為輸入屬性,消除了對第二個輸入對象的需求。輸入屬性可能是有自己(子)屬性的rich對象類型。Action屬性能夠通過web頁面上的taglibs訪問。Struts2也支持ActionForm模式。rich對象類型,包括業務對象,能夠用作輸入/輸出對象。這種ModelDriven 特性簡化了taglib對POJO輸入對象的引用。
表達式語言:
• Struts1 整合了JSTL,因此使用JSTL EL。這種EL有基本對象圖遍歷,但是對集合和索引屬性的支持很弱。
• Struts2可以使用JSTL,但是也支持一個更強大和靈活的表達式語言--"Object Graph Notation Language" (OGNL).
綁定值到頁面(view):
• Struts 1使用標準JSP機制把對象綁定到頁面中來訪問。
• Struts 2 使用 "ValueStack"技術,使taglib能夠訪問值而不需要把你的頁面(view)和對象綁定起來。ValueStack策略允許通過一系列名稱相同但類型不同的屬性重用頁面(view)。
類型轉換:
• Struts 1 ActionForm 屬性通常都是String類型。Struts1使用Commons-Beanutils進行類型轉換。每個類一個轉換器,對每一個實例來說是不可配置的。
• Struts2 使用OGNL進行類型轉換。提供基本和常用對象的轉換器。
校驗:
• Struts 1支持在ActionForm的validate方法中手動校驗,或者通過Commons Validator的擴展來校驗。同一個類可以有不同的校驗內容,但不能校驗子對象。
• Struts2支持通過validate方法和XWork校驗框架來進行校驗。XWork校驗框架使用為屬性類類型定義的校驗和內容校驗,來支持chain校驗子屬性
Action執行的控制:
• Struts1支持每一個模塊有單獨的Request Processors(生命周期),但是模塊中的所有Action必須共享相同的生命周期。
• Struts2支持通過攔截器堆棧(Interceptor Stacks)為每一個Action創建不同的生命周期。堆棧能夠根據需要和不同的Action一起使用。
最明顯的就是Struts2是pull-MVC 架構,就是可以直接從Action中獲取所需要的數據,而不是像Struts那樣必須把 beans 存到page, request,或者session中才能獲取。
<form name="form1" method="post" action="<%=request.getContextPath()%>/fileUpload.do?method=upload" enctype="multipart/form-data">
<table width="43%" border="1" align="center">
<tr>
<td colspan="2"><div align="center">上傳周報</div></td>
</tr>
<tr>
<td width="22%">文件名稱</td>
<td width="78%"><input type="text" name="fileName"></td>
</tr>
<tr>
<td width="22%">選擇文件</td>
<td width="78%"><input type="file" name="docfile"/></td>
</tr>
<tr>
<td width="22%">文件描述</td>
<td><input type="textarea" name="fileDescription"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" name="Submit" value="上傳"><input type="reset" name="Submit2" value="重置"></td>
</tr>
</table>
String filename = "";
String filePath = "";
try {
is = (InputStream) docfile.getInputStream();// 把文件讀入
bis = new BufferedInputStream(is);
filePath ="E:/upload/";// 取當前系統路徑
File rootfile = new File(filePath);
if (!rootfile.exists()) {
rootfile.mkdirs();
}
String name= new String(docfile.getFileName().getBytes("UTF-8"),"gb2312");
filename = new Date().getTime()+request.getSession().getId()+fileName+".doc";
fos = new FileOutputStream(filePath + filename);// 建立一個上傳文件的輸出流
bos = new BufferedOutputStream(fos);
int bytesRead = 0;
byte[] buffer = new byte[2 * 1024];
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);// 將文件寫入服務器
}
FileUpload fileUpload=new FileUpload();
fileUpload.setFileName(fileName);
fileUpload.setFilePath(filePath+filename);
fileUpload.setFileDescription(fileDescription);
this.getSiteBusiness().getFileLoadService().save(fileUpload);
return mapping.findForward("uploadsucess");
}catch (Exception e) {
e.printStackTrace();
return mapping.getInputForward();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
System.err.print(e);
return mapping.getInputForward();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
System.err.print(e);
return mapping.getInputForward();
}
}
}
}
|
您肯定已經聽說過控制反轉 (IOC) 設計模式,因為很長一段時間以來一直在流傳關于它的信息。如果您在任何功能中使用過 Spring 框架,那么您就知道其原理的作用。在本文中,我利用這一原理把一個 Struts 應用程序注入 Spring 框架,您將親身體會到 IOC 模式的強大。
將一個 Struts 應用程序整合進 Spring 框架具有多方面的優點。首先,Spring 是為解決一些關于 JEE 的真實世界問題而設計的,比如復雜性、低性能和可測試性,等等。第二,Spring 框架包含一個 AOP 實現,允許您將面向方面技術應用于面向對象的代碼。第三,一些人可能會說 Spring 框架只有處理 Struts 比 Struts 處理自己好。但是這是觀點問題,我演示三種將 Struts 應用程序整合到 Spring 框架的方法后,具體由您自己決定使用哪一種。
我所演示的方法都是執行起來相對簡單的,但是它們卻具有明顯不同的優點。我為每一種方法創建了一個獨立而可用的例子,這樣您就可以完全理解每種方法。
Spring 的創立者 Rod Johnson 以一種批判的眼光看待 Java™ 企業軟件開發,并且提議很多企業難題都能夠通過戰略地使用 IOC 模式(也稱作依賴注入)來解決。當 Rod 和一個具有奉獻精神的開放源碼開發者團隊將這個理論應用于實踐時,結果就產生了 Spring 框架。簡言之,Spring 是一個輕型的容器,利用它可以使用一個外部 XML 配置文件方便地將對象連接在一起。每個對象都可以通過顯示一個 JavaBean 屬性收到一個到依賴對象的引用,留給您的簡單任務就只是在一個 XML 配置文件中把它們連接好。
![]() |
|
依賴注入是一個強大的特性,但是 Spring 框架能夠提供更多特性。Spring 支持可插拔的事務管理器,可以給您的事務處理提供更廣泛的選擇范圍。它集成了領先的持久性框架,并且提供一個一致的異常層次結構。Spring 還提供了一種使用面向方面代碼代替正常的面向對象代碼的簡單機制。
Spring AOP 允許您使用攔截器 在一個或多個執行點上攔截應用程序邏輯。加強應用程序在攔截器中的日志記錄邏輯會產生一個更可讀的、實用的代碼基礎,所以攔截器廣泛用于日志記錄。您很快就會看到,為了處理橫切關注點,Spring AOP 發布了它自己的攔截器,您也可以編寫您自己的攔截器。
與 Struts 相似,Spring 可以作為一個 MVC 實現。這兩種框架都具有自己的優點和缺點,盡管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多開發團隊已經學會在時間緊迫的時候利用 Struts 作為構造高品質軟件的基礎。Struts 具有如此大的推動力,以至于開發團隊寧愿整合 Spring 框架的特性,而不愿意轉換成 Spring MVC。沒必要進行轉換對您來說是一個好消息。Spring 架構允許您將 Struts 作為 Web 框架連接到基于 Spring 的業務和持久層。最后的結果就是現在一切條件都具備了。
在接下來的小竅門中,您將會了解到三種將 Struts MVC 整合到 Spring 框架的方法。我將揭示每種方法的缺陷并且對比它們的優點。 一旦您了解到所有三種方法的作用,我將會向您展示一個令人興奮的應用程序,這個程序使用的是這三種方法中我最喜歡的一種。
接下來的每種整合技術(或者竅門)都有自己的優點和特點。我偏愛其中的一種,但是我知道這三種都能夠加深您對 Struts 和 Spring 的理解。在處理各種不同情況的時候,這將給您提供一個廣闊的選擇范圍。方法如下:
ActionSupport
類整合 Structs
DelegatingRequestProcessor
覆蓋 Struts 的 RequestProcessor
Action
管理委托給 Spring 框架 無論您使用哪種技術,都需要使用 Spring 的 ContextLoaderPlugin
為 Struts 的 ActionServlet
裝載 Spring 應用程序環境。就像添加任何其他插件一樣,簡單地向您的 struts-config.xml 文件添加該插件,如下所示:
|
竅門 1. 使用 Spring 的 ActionSupport
手動創建一個 Spring 環境是一種整合 Struts 和 Spring 的最直觀的方式。為了使它變得更簡單,Spring 提供了一些幫助。為了方便地獲得 Spring 環境,org.springframework.web.struts.ActionSupport
類提供了一個 getWebApplicationContext()
方法。您所做的只是從 Spring 的 ActionSupport
而不是 Struts Action
類擴展您的動作,如清單 1 所示:
|
讓我們快速思考一下這里到底發生了什么。在 (1) 處,我通過從 Spring 的 ActionSupport
類而不是 Struts 的 Action
類進行擴展,創建了一個新的 Action
。在 (2) 處,我使用 getWebApplicationContext()
方法獲得一個 ApplicationContext
。為了獲得業務服務,我使用在 (2) 處獲得的環境在 (3) 處查找一個 Spring bean。
這種技術很簡單并且易于理解。不幸的是,它將 Struts 動作與 Spring 框架耦合在一起。如果您想替換掉 Spring,那么您必須重寫代碼。并且,由于 Struts 動作不在 Spring 的控制之下,所以它不能獲得 Spring AOP 的優勢。當使用多重獨立的 Spring 環境時,這種技術可能有用,但是在大多數情況下,這種方法不如另外兩種方法合適。
將 Spring 從 Struts 動作中分離是一個更巧妙的設計選擇。分離的一種方法是使用 org.springframework.web.struts.DelegatingRequestProcessor
類來覆蓋 Struts 的 RequestProcessor
處理程序,如清單 2 所示:
清單 2. 通過 Spring 的 DelegatingRequestProcessor 進行整合
|
我利用了 <controller>
標記來用 DelegatingRequestProcessor
覆蓋默認的 Struts RequestProcessor
。下一步是在我的 Spring 配置文件中注冊該動作,如清單 3 所示:
|
注意:在 (1) 處,我使用名稱屬性注冊了一個 bean,以匹配 struts-config 動作映射名稱。SearchSubmit
動作揭示了一個 JavaBean 屬性,允許 Spring 在運行時填充屬性,如清單 4 所示:
清單 4. 具有 JavaBean 屬性的 Struts 動作
|
在清單 4 中,您可以了解到如何創建 Struts 動作。在 (1) 處,我創建了一個 JavaBean 屬性。DelegatingRequestProcessor
自動地配置這種屬性。這種設計使 Struts 動作并不知道它正被 Spring 管理,并且使您能夠利用 Sping 的動作管理框架的所有優點。由于您的 Struts 動作注意不到 Spring 的存在,所以您不需要重寫您的 Struts 代碼就可以使用其他控制反轉容器來替換掉 Spring。
DelegatingRequestProcessor
方法的確比第一種方法好,但是仍然存在一些問題。如果您使用一個不同的 RequestProcessor
,則需要手動整合 Spring 的 DelegatingRequestProcessor
。添加的代碼會造成維護的麻煩并且將來會降低您的應用程序的靈活性。此外,還有過一些使用一系列命令來代替 Struts RequestProcessor
的傳聞。 這種改變將會對這種解決方法的使用壽命造成負面的影響。
一個更好的解決方法是將 Strut 動作管理委托給 Spring。您可以通過在 struts-config
動作映射中注冊一個代理來實現。代理負責在 Spring 環境中查找 Struts 動作。由于動作在 Spring 的控制之下,所以它可以填充動作的 JavaBean 屬性,并為應用諸如 Spring 的 AOP 攔截器之類的特性帶來了可能。
清單 5 中的 Action
類與清單 4 中的相同。但是 struts-config 有一些不同:
|
清單 5 是一個典型的 struts-config.xml 文件,只有一個小小的差別。它注冊 Spring 代理類的名稱,而不是聲明動作的類名,如(1)處所示。DelegatingActionProxy 類使用動作映射名稱查找 Spring 環境中的動作。這就是我們使用 ContextLoaderPlugIn
聲明的環境。
將一個 Struts 動作注冊為一個 Spring bean 是非常直觀的,如清單 6 所示。我利用動作映射使用 <bean>
標記的名稱屬性(在這個例子中是 "/searchSubmit
")簡單地創建了一個 bean。這個動作的 JavaBean 屬性像任何 Spring bean 一樣被填充:
清單 6. 在 Spring 環境中注冊一個 Struts 動作
|
動作委托解決方法是這三種方法中最好的。Struts 動作不了解 Spring,不對代碼作任何改變就可用于非 Spring 應用程序中。RequestProcessor
的改變不會影響它,并且它可以利用 Spring AOP 特性的優點。
動作委托的優點不止如此。一旦讓 Spring 控制您的 Struts 動作,您就可以使用 Spring 給動作補充更強的活力。例如,沒有 Spring 的話,所有的 Struts 動作都必須是線程安全的。如果您設置 <bean>
標記的 singleton 屬性為“false”,那么不管用何種方法,您的應用程序都將在每一個請求上有一個新生成的動作對象。您可能不需要這種特性,但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如,當實例化 Struts 動作時,<bean>
標記的 init-method 屬性被用于運行一個方法。類似地,在從容器中刪除 bean 之前,destroy-method 屬性執行一個方法。這些方法是管理昂貴對象的好辦法,它們以一種與 Servlet 生命周期相同的方式進行管理。
前面提到過,通過將 Struts 動作委托給 Spring 框架而整合 Struts 和 Spring 的一個主要的優點是:您可以將 Spring 的 AOP 攔截器應用于您的 Struts 動作。通過將 Spring 攔截器應用于 Struts 動作,您可以用最小的代價處理橫切關注點。
雖然 Spring 提供很多內置攔截器,但是我將向您展示如何創建自己的攔截器并把它應用于一個 Struts 動作。為了使用攔截器,您需要做三件事:
這看起來非常簡單的幾句話卻非常強大。例如,在清單 7 中,我為 Struts 動作創建了一個日志記錄攔截器。 這個攔截器在每個方法調用之前打印一句話:
|
這個攔截器非常簡單。before()
方法在攔截點中每個方法之前運行。在本例中,它打印出一句話,其實它可以做您想做的任何事。下一步就是在 Spring 配置文件中注冊這個攔截器,如清單 8 所示:
|
您可能已經注意到了,清單 8 擴展了 清單6 中所示的應用程序以包含一個攔截器。具體細節如下:
<value>
標記。
就是這樣。就像這個例子所展示的,將您的 Struts 動作置于 Spring 框架的控制之下,為處理您的 Struts 應用程序提供了一系列全新的選擇。在本例中,使用動作委托可以輕松地利用 Spring 攔截器提高 Struts 應用程序中的日志記錄能力。
在本文中,您已經學習了將 Struts 動作整合到 Spring 框架中的三種竅門。使用 Spring 的 ActionSupport
來整合 Struts(第一種竅門中就是這樣做的)簡單而快捷,但是會將 Struts 動作與 Spring 框架耦合在一起。如果您需要將應用程序移植到一個不同的框架,則需要重寫代碼。第二種解決方法通過委托 RequestProcessor
巧妙地解開代碼的耦合,但是它的可擴展性不強,并且當 Struts 的 RequestProcessor
變成一系列命令時,這種方法就持續不了很長時間。第三種方法是這三種方法中最好的:將 Struts 動作委托給 Spring 框架可以使代碼解耦,從而使您可以在您的 Struts 應用程序中利用 Spring 的特性(比如日志記錄攔截器)。
三種 Struts-Spring 整合竅門中的每一種都被實現成一個完整可用的應用程序。
import Java.io.IOException;
import Java.io.PrintWriter;
import Java.util.Iterator;
import Java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.validator.DynaValidatorForm;
import com.rain.bean.KindDao;
/**
* MyEclipse Struts
* Creation date: 09-13-2006
*
* XDoclet definition:
* @struts.action parameter="method"
*/
public class KindAction extends DispatchAction {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward search(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
DynaValidatorForm kindForm = (DynaValidatorForm)form;
KindDao dao=new KindDao();
int kindid=Integer.parseInt(kindForm.getString("kindid"));
List list=dao.findAllKind(kindid);
Iterator it=list.iterator();
if(it.hasNext()){
PrintWriter out;
try {
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
out = response.getWriter();
out.println("<response>");
while(it.hasNext()){
String name=it.next().toString();
out.println("<kind>"+name+"</kind>");
}
out.println("</response>");
it=null;
out.close();
} catch (IOException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
}else{
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
// TODO Auto-generated method stub
return null;
}
}
</head>
<body>
<form name="RegistForm">
<table height="328" align="center" cellpadding="0" cellspacing="0" style="border:2px #666666 solid; ">
<tr>
<td colspan="2" height="30" bgcolor="#666666" align="center" style="border-bottom:1px #666666 solid;"><font color="#FFFFFF"><b>用 戶 注 冊</b></font></td>
</tr>
<tr>
<td width="147" height="35" align="right">用 戶 名:</td>
<td width="368"><input type="text" name="UserName" id="username" maxlength="15" size="13" onblur="checkUsername(this.value);"> <font color="#ff0000">*</font> <span id="usernameview"></span></td>
</tr>
<tr>
<td height="35" align="right">密 碼:</td>
<td><input type="password" name="Password" id="password1" maxlength="15" size="15" onblur="checkPassword(this.value);"> <font color="#ff0000">*</font><span id="pwdview"></span></td>
</tr>
<tr>
<td height="35" align="right">密碼校驗:</td>
<td><input type="password" name="Password2" id="password2" maxlength="15" size="15" onblur="checkPassword2(this.value);"> <font color="#ff0000">*</font> <span id="pwd2view"></span></td>
</tr>
<tr>
<td height="35" align="right">真實姓名:</td>
<td><input type="text" name="realname" id="realname" size="10" maxlength="10" onblur="checkRealName(this.value);"> <font color="#ff0000">*</font><span id="realnameview"></span></td>
</tr>
<tr>
<td height="35" align="right">性 別:</td>
<td><select name="sex" id="sex">
<option value="m">男</option>
<option value="w">女</option></select> <font color="#ff0000">*</font></td>
</tr>
<tr>
<td height="35" align="right">聯系電話:</td>
<td><input type="text" name="tel" id="tel" maxlength="12" size="13" > <font color="#ff0000">*</font></td>
</tr>
<tr>
<td height="35" align="right">手 機:</td>
<td><input type="text" name="mobile" id="mobile" maxlength="12" size="13"> <font color="#ff0000">*</font></td>
</tr>
<tr>
<td height="35" align="right">E - mail:</td>
<td><input type="text" name="email" id="email" size="25" onChange="checkEmail();"> <font color="#ff0000">*</font></td>
</tr>
<tr>
<td height="86" align="right">個人簡介:</td>
<td><textarea cols="30" rows="4" class="text" name="memo" style="overflow:auto; border:1px #666666 solid; color:#3399FF;"></textarea> <font color="#ff0000">*</font></td>
</tr>
<tr>
<td height="10" colspan="2"></td>
</tr>
<tr>
<td height="30" colspan="2" align="center" style="border-top:1px #666666 solid; "><input onClick="javascript:addUser();" style="background-color:#666666; color:#FFFFFF; border:0; text-align:center; width:60px;" type="button" name="add" value="A D D"> <input style="background-color:#666666; color:#FFFFFF; border:0; width:60px;" type="reset" name="reset" value="R E T"></td>
</tr>
</table>
</form>
</body>
</html>
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClass.vtl
*/
package com.rain.struts.action;
import Java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.validator.DynaValidatorForm;
import com.rain.bean.Regist;
/**
* MyEclipse Struts
* Creation date: 09-12-2006
*
* XDoclet definition:
* @struts.action parameter="method" validate="true"
*/
public class LoginAction extends DispatchAction {
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward checkUserName(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
Regist regist=new Regist();
DynaValidatorForm loginForm = (DynaValidatorForm)form;
String username=loginForm.getString("UserName");
System.out.println(username);
boolean flag=regist.findByName(username);
System.out.println("test");
if(flag)
{
try {
response.getWriter().write("sorry!");
} catch (IOException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
}else
{
try {
response.getWriter().write("luck!");
} catch (IOException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
}
return null;
}
}
var row, cell, txtNode;
for (var i = 0; i < size; i++) {
var nextNode = the_names[i].firstChild.data;
row = document.createElement("tr");
cell = document.createElement("td");
cell.onmouseout = function() {this.className='mouseOver';};
cell.onmouseover = function() {this.className='mouseOut';};
cell.setAttribute("bgcolor", "#FFFAFA");
cell.setAttribute("border", "0");
cell.onclick = function() { populateName(this); } ;
txtNode = document.createTextNode(nextNode);
cell.appendChild(txtNode);
row.appendChild(cell);
nameTableBody.appendChild(row);
}
}
function setOffsets() {
var end = inputField.offsetWidth;
var left = calculateOffsetLeft(inputField);
var top = calculateOffsetTop(inputField) + inputField.offsetHeight;
completeDiv.style.border = "black 1px solid";
completeDiv.style.left = left + "px";
completeDiv.style.top = top + "px";
nameTable.style.width = end + "px";
}
function calculateOffsetLeft(field) {
return calculateOffset(field, "offsetLeft");
}
function calculateOffsetTop(field) {
return calculateOffset(field, "offsetTop");
}
function calculateOffset(field, attr) {
var offset = 0;
while(field) {
offset += field[attr];
field = field.offsetParent;
}
return offset;
}
function populateName(cell) {
inputField.value = cell.firstChild.nodeValue;
clearNames();
}
function clearNames() {
var ind = nameTableBody.childNodes.length;
for (var i = ind - 1; i >= 0 ; i--) {
nameTableBody.removeChild(nameTableBody.childNodes[i]);
}
completeDiv.style.border = "none";
}
</script>
</head>
<body>
<h3>Ajax Auto Complete Example</h3>
請輸入名稱:<input type="text" name="title" id="title" size="30" width="100" height="20" onkeyup="findNames();">
<div style="position:absolute;" id="popup">
<table id="name_table" bgcolor="#FFFAFA" border="0" cellspacing="0" cellpadding="0"/>
<tbody id="name_table_body"></tbody>
</table>
</div>
</body>
</html>
Action源代碼
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClass.vtl
*/
package com.rain.struts.action;
import Java.io.IOException;
import Java.io.PrintWriter;
import Java.io.UnsupportedEncodingException;
import Java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.validator.DynaValidatorForm;
import com.rain.bean.ArticleDao;
/**
* MyEclipse Struts
* Creation date: 09-12-2006
*
* XDoclet definition:
* @struts.action parameter="method"
*/
public class ArticleAction extends DispatchAction {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward search(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
DynaValidatorForm articleForm = (DynaValidatorForm)form;
String title;
try {
title = new String(request.getParameter("title").getBytes("ISO8859_1"),"UTF-8");
System.out.println(title);
ArticleDao dao=new ArticleDao();
Iterator it=dao.findAllName(title).iterator();
if(it.hasNext()){
PrintWriter out;
try {
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
out = response.getWriter();
out.println("<response>");
while(it.hasNext()){
String name=it.next().toString();
out.println("<title>"+name+"</title>");
}
out.println("</response>");
it=null;
out.close();
} catch (IOException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
}else{
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
} catch (UnsupportedEncodingException e1) {
// TODO 自動生成 catch 塊
e1.printStackTrace();
}
return null;
}
}
import Java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.rain.HibernateSessionFactory;
/**
*
*/
public class ArticleDao {
public List findAllName(String title){
System.out.println("11");
String hql="select art.title from Article art where art.title like '"+title+"%'";
List list=null;
try{
Session session=HibernateSessionFactory.getCurrentSession();
Transaction tx=session.beginTransaction();
Query query=session.createQuery(hql);
list=query.list();
tx.commit();
session.close();
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
return list;
}
}