)。ActionServlet委派請求是基于客戶端傳入的URI。一旦Action類完成處理,ActionServlet根據Action返回的鍵值來決定在什么視圖中顯示Action的類處理結果。ActionServlet類似于一個創建Action對象的工廠,由Action對象去執行應用中實際的業務邏輯。控制器是Struts框架中最重要的部分。
1.6.1 Struts的運行過程
下面是一幅和MVC模式對應的STRUTS框架圖
?視圖(view1)???????????????????????????????????
????????????????????????????????????????????? Action1
???????????????????????????????????????????????????
???? ?????????????????????????????????????????Action2
?????????????????? ActionServlet????????????? Action3
???????????????????? (控制器)
????????????????????????????????????????????? Action4
??????????????????????????????????????????????????
視圖(view2)???????? ?????????????????????????????????模型(Model)
?
????? 圖7?STRUTS框架圖
圖7是Struts框架下應用程序請求流通過的路徑。這個處理過程由5個基本的步驟組成。
下面是處理步驟的描述。
1.由顯示視圖產生一個請求。
2.?請求被ActionServlet(控制器)接收,它在struts-config.xml文件中尋找請求的URI,找到對應的Action類后,Action類執行相應的業務邏輯。
3.?Action類執行建立在模型組件基礎上的業務邏輯,模型組件是和應用程序關聯的。
4.?一旦Action類處理完業務邏輯,它把控制權返回給ActionServlet。,Action類提供一個鍵值作為返回的一部分,它指明了處理的結果。ActionServlet使用這個鍵值來決定在什么視圖中顯示Action的類處理結果。
5.?當ActionServlet把Action類的處理結果傳送到指定的視圖中,請求的過程也就完成了。
?
???????????????? HttpServlet???????????????????? ?????????????????????FrowardConfig
?? <<front controller>>
org.apache.struts.action.ActionServlet??????????????????? org.apache.struts.action.ActionForWard
?
?
?
??<<dispatcher>>???????????????????????????????????????????????????? ActionConfig
?org.apache.struts.action.RequestProcessor????????????????? org.apache.struts.action.ActionMapping
?
?
????????????????????? Serializable
?????????? <<view helper>>??????????????????????????????? <<request handler>>
?? org.apache.struts.action.ActionForm??????????? ???????????????????org.apache.struts.action.Action
?
圖8?Struts中MVC實現
?
圖8中各個類的語義
1.?ActionServlet類:實現控制器,Struts必需的配置在ActionServlet.init()方法中加載。ActionServlet將所有的輸入請求委托給RequestProcessor.
2.?RequestProcessor類:分配器,所有輸入的請求都被控制器委托給分配器(dispatcher).
3. ActionForm類:存儲表單數據,由ActionForm派生出來的對象用于存儲請求對象中的參數,因此它們和用戶是緊密耦合的。
4. ActionForward類:ActionForward對象是配置對象。這些配置對象有唯一的標識符,以使它們根據有意義的名稱進行尋找。ActionForward對象封裝提交的URL路徑,它被請求處理程序用來標識目標視圖。
5. ActionMapping類:它提供了引入的請求和相應的請求處理程序之間的映射。
6.Action類:請求處理程序。Action類的子類作為適配器用于引入的請求和模型之間。Action類的子類是為每個請求單獨創建的。Action的基類提供了訪問與框架相關的資源的公共函數,以及保存由它的子類的exectue(…)方法進行檢查而得到錯誤的方法。
1.6.2?Struts的主要組件:
1.6.2.1 控制器對象
控制器語義有ActionServlet。控制器語義提供了處理所有客戶請求的中心位置。這就為控制器層提供了一個清楚的工作分配情況,控制器層主要的工作是處理試圖和導航管理、將模型訪問和操作交給有特定請求的請求處理程序(Command對象[Gof])。所有引入的請求被映射到部署描述符的中心控制器上。
1.6.2.2 分配器對象
RequestProcessor作為一個分配器運行,并通過實例化(或重用)一個請求處理和對應的表單bean來處理客戶機請求。創建的錯誤或是表單bean和請求處理程序拋出的異常(由RequestProcessor處理),影響了RequestProcessor的視圖管理功能。表單bean幫助RequestProcessor存儲表單數據和分段傳輸視圖需要的中間模型數據,RequestProcessor使用<action>聲明實例化特定請求的請求處理程序。
1.6.2.3請求處理程序
Action類的子類作為適配器用于引入的請求和模型之間。請求最初由RequestProcessor截獲,RequestProcessor則實例化一個對應的請求處理程序。這個從Action類繼承而來的對象(也稱為請求處理程序)是為每個請求而特別創建的。客戶機請求封裝請求URI中所需的動作作為servlet路徑,該路徑信息隨后有分配器(RequestProcessor)提取,從而創建相應的請求處理程序來處理程序實例。命令模式將URI從請求處理程序中分離出來。
1.6.3?Struts的配置文件struts-config.xml
Struts 的核心是控制器ActionServlet,而ActionServlet的核心是配置文件struts-config.xml,該配置文件的主要作用是建立控制器與模型之間的聯系。它描述了控制器將客戶請求映射到對應處理的法則,同時還定義了用戶輸入數據與ActionFor。組件的對應映射關系。此外,該配置文件的另一個作用是將邏輯名映射到物理路徑,使得物理路徑與程序路徑無關,整個系統導航使用邏輯名在struts-config.xml中完成。
這種在配 置文件中完成業務邏輯控制的方法主要有以下幾個優點:首先,應用的所有頁面的導航定義都集中在一個分等級的文本文件中,通過此配置文件即可迅速把握整個系統的脈絡;第二,網頁設計人員在修改網頁時無需遍歷Java代碼來理解應用的業務邏輯,而當業務邏輯發生改變時,業務邏輯開發者也只需在struts-config.xml中做出相應的調整和修改,而無需重新編譯代碼。在大型的Web應用系統中,這種管理頁面邏輯的方式無論是在系統前期的開發過程,還是后期的維護與升級階段都顯示出了方便性和有效性。
struts-config.xml的正文部份由八個元素組成,下面將對系統中涉及的元素的功能與使用方法舉例闡明。
1.6.3.1 定義ActionForm
ActionServlet使用ActionForm來保存請求參數,這些Bean的屬性名稱與HTTP請求參數中的名稱相對應,控制器將請求參數傳遞到ActionFormBean的實例中,然后將這個實例傳送到Action類。Struts的配置文件struts-config.xml提供了一個<form-beans>元素用于統一管理系統中所有的ActionForm Bean。每個ActionForm Bean都由一個相應的<form-bean>元素創建。在運行時,控制器通過調用適當的ActionForm Bean來確定被創建的ActionForm對象及特性。下面是項目中一個針對常規ActionForm的<form-bean>元素配置:
<form-beans>
<form-bean name="userInfoForm" ???? ???? ?type="aiai.keyan.manage.user_Manage.pursuerInfoBean" />
</form-beans>
其中,屬性name是表單bean在相關作用域的名稱,它用于將ActionFormBean與ActionMapping進行關聯;而屬性type是類的完全限定名。
1.6.3.2 定義全局轉發
在常見的Web應用中,多數URI都與應用中的物理文件直接映射,這在應用開發的初級階段顯得較為容易。但是,在應用開發的后期或維護階段,應用的邏輯通常會發生改變,這時就必須更新整個應用,如果遺漏了某部分,就會產生“異常更新”。這一點給應用的后期開發者和維護人員造成了不小的困難。為了解決這一難題,在Struts應用中,開發人員將邏輯名映射到物理地址,在應用中使用邏輯名實現系統導航,這就使得應用的物理地址與程序地址無關。而元素<global-forwards>就是用于實現這個功能。這個元素可以包含任意個<forward/>子元素,每一個子元素對應一個邏輯名與一個物理地址的映射。當系統的邏輯發生改變時,開發人員只需修改相應<forward/>中的映射關系即可。如下所示:
<global-forwards>
<forward name="forStep1"
path="/researching/datainput/step1.jsp" />
</global-forwards>
上述代碼是項目的配置文件中的一部分。其中,屬性name表示全局轉發的邏輯名,path表示目標URI的物理路徑。除了可 以 在<global-forwards>元素中部署全局轉發外,開發人員除還可以在<action>元素中部署局部轉發, 局部轉發僅針對對應的ActionMapping有效。
1.6.3.3 定義Action映射
<Action -Mapping>元素的作用在于幫助開發人員進行框架內部的流程控制。該元素可以包含任意個<action />子元素。每一個子元素將一個請求URI路徑映射到對應的Action類,并且將Action類與對應ActionForm bean相關聯。ActionServlet在內部使用這些映射,并將控制轉移到特定的Action類實例。所有Action類使用perform()方法實現特定的業務邏輯,然后返回一個ActionForward對象,其中包括響應轉發的目標資源名稱。下列代碼截取自項目的配置文件:
<action-mappings>
<action name="userInfoForm" ?type="aiai.keyan.manage.user_Manage.Struts.userInfoAction" validate="true"
input="/menage/user/register1.jsp"
scope="request" path="/register1" />
</action-mappings>
其中子元素<action>的屬性path表示Action類的相對路徑,name表示與指定操作關聯的Action Bean的名稱,type表示連接到本映射的Action類的全稱,scope表示與指定Action對應的ActionForm Bean的作用域,input表示輸入表單的路徑和發生輸入錯誤時系統應返回的頁面。在<action-mappings>元素中還可以使用<forward>子元素定義資源的邏輯名稱,該資源是Action類的響應要轉發的目標。其中<forward>的屬性name表示Action類訪問ActionForward時所用的邏輯名,path表示響應轉發的目標資源的路徑。
1.6.4 Struts的自定義標記庫
Struts 提供了一組可擴展的自定義標記庫(Taglib),采用這些標記庫,可以幫助開發人員簡化創建用戶界面的過程。目前 Struts提供了四種基本自定義Taglib以及兩種附加Taglib .
struts-bean taglib:不僅包含可以在訪問bean和bean屬性時使用的標記,還包含一些用于消息顯示的標記。
struts-html taglib:不僅包含用于創建Struts輸入表單的標記,而且包含其它通常用來創建動態HTML用戶界面或表格的標記。
struts-logic taglib:該庫所包含的標記通常用于管理輸出文本的條件生成、循環使用對象集合以重復生成輸出文本以及應用程序流管理。
struts-template taglib:該庫包含的標記可用作創建動態JSP模板,所有采用同一模板的JSP頁面都擁有一個公共的外觀或共同的格式。
T iles 插件:除了替代Template的基本模板功能外,還增加了布局定義、虛擬頁面定義和動態頁面生成等功能。Tiles強大的模板功能能夠使頁面獲得最大的重用性和靈活性,此外,結合Tiles配置文件中的頁面定義和Action的轉發邏輯(即將一個Action轉發到一個在Tile:配置文件中定義的虛擬頁面),可以減少頁面的數量,從而簡化JSP開發。
Nested:該標記庫的作用在于讓上述的基本Struts自定義標記庫的功能能夠嵌套應用于上下文,發揮更大的作用。
?
2.7?WEB服務器的搭建與集成
2.7.1 jsp,Serlvet容器Tomcat
????? Tomcat是一個免費的開源的Serlvet容器,它是Apache基金會的Jakarta項目中的一個核心項目,由Apache,Sun和其它一些公司及個人共同開發而成。由于有了Sun的參與和支持,最新的Servlet和Jsp規范總能在Tomcat中得到體現。
?? 由于Java的跨平臺特性,基于Java的Tomcat也具有跨平臺性。與傳統的桌面應用程序不同,Tomcat中的應用程序是一個WAR(Web?Archive)文件。WAR是Sun提出的一種Web應用程序格式,與JAR類似,也是許多文件的一個壓縮包。這個包中的文件按一定目錄結構來組織:通常其根目錄下包含有Html和Jsp文件或者包含這兩種文件的目錄,另外還會有一個WEB-INF目錄,這個目錄很重要。通常在WEB-INF目錄下有一個web.xml文件和一個classes目錄,web.xml是這個應用的配置文件,而classes目錄下則包含編譯好的Servlet類和Jsp或Servlet所依賴的其它類(如JavaBean)。通常這些所依賴的類也可以打包成JAR放到WEB-INF下的lib目錄下,當然也可以放到系統的CLASSPATH中,但那樣移植和管理起來不方便。
?? 在Tomcat中,應用程序的部署很簡單,你只需WAR放到Tomcat的webapp目錄下,Tomcat會自動檢測到這個文件,并將其解壓。在瀏覽器中訪問這個應用的Jsp時,通常第一次會很慢,因為Tomcat要將Jsp轉化為Servlet文件,然后編譯。編譯以后,訪問將會很快。另外Tomcat也提供了一個應用:manager,訪問這個應用需要用戶名和密碼,用戶名和密碼存儲在一個xml文件中。通過這個應用,輔助于Ftp,你可以在遠程通過Web部署和撤銷應用。當然本地也可以。?Tomcat不僅僅是一個Servlet容器,它也具有傳統的Web服務器的功能:處理Html頁面。但是與Apache相比,它的處理靜態Html的能力就不如Apache。我們可以將Tomcat和Apache集成到一塊,讓Apache處理靜態Html,而Tomcat處理Jsp和Servlet。這種集成只需要修改一下Apache和Tomcat的配置文件即可。
?? 另外,Tomcat提供Realm支持。Realm類似于Unix里面的group。在Unix中,一個group對應著系統的一定資源,某個group不能訪問不屬于它的資源。Tomcat用Realm來對不同的應用(類似系統資源)賦給不同的用戶(類似group)。沒有權限的用戶則不能訪問這個應用。Tomcat提供三種Realm,1:JDBCRealm,這個Realm將用戶信息存在數據庫里,通過JDBC獲得用戶信息來進行驗證。2:JNDIRealm,用戶信息存在基于LDAP的服務器里,通過JNDI獲取用戶信息。3:MemoryRealm,用戶信息存在一個xml文件里面,上面講的manager應用驗證用戶時即使用此種Realm。通過Realm我們可以方便地對訪問某個應用的客戶進行驗證。
?? 在Tomcat中,可以利用Servlet2.3提供的事件監聽器功能,來對Application或者Session實行監聽。Tomcat也提供其它的一些特征,如與SSL集成到一塊,實現安全傳輸。還有Tomcat也提供JNDI支持,這與那些J2EE應用服務器提供的是一致的。說到這里要介紹一下通常所說的應用服務器(如WebLogic)與Tomcat有何區別。應用服務器提供更多的J2EE特征,如EJB,JMS,JAAS等,同時也支持Jsp和Servlet。而Tomcat則功能沒有那么強大,它不提供EJB等支持。但如果與JBoss(一個開源的應用服務器)集成到一塊,則可以實現J2EE的全部功能。既然應用服務器具有Tomcat的功能,那么Tomcat有沒有存在的必要呢?事實上,在很多中小應用不需要采用EJB等技術,Jsp和Servlet已經足夠,這時如果用應用服務器就有些浪費了。而Tomcat短小精悍,配置方便,能滿足我們的需求,這種情況下我們自然會選擇Tomcat。
???? Tomcat也可以與其它一些軟件集成起來實現更多的功能。如與上面提到的JBoss集成起來開發EJB,與Cocoon(Apache的另外一個項目)集成起來開發基于Xml的應用,與OpenJMS 集成起來開發JMS應用,除了我們提到的這幾種,可以與Tomcat集成的軟件還有很多。
配置Tomcat虛擬目錄,為了使得Tomcat即可以實時對開發工具的修改進行監測,以達到與開發工具實時同步數據。可以在不重啟服務器的情況下對項目進行修改。這是非常重要的由于在一臺服務器上可能運行這不止一個的WEB項目,在新加項目時不可能讓服務器重啟,因此必須配置虛擬目錄。在{TOMCAT_HOME}/conf/server.xml中的<Host></Host>之間加上
<Context path="dir1"
docBase="D:\web"??
reloadable="true" crossContext="true" >
</Context >
其中:
path: web應用的context路徑。catalina將每個URL的起始和context path進行比較,選擇合適的web應用處理該請求。特定Host下的context path必須是惟一的。如果context path為空字符串(""),這個context是所屬Host的缺省web應用,用來處理不能匹配任何context path的請求。
DocBase:該web應用的文檔基準目錄(Document Base,也稱為Context Root),或者是WAR文件的路徑。可以使用絕對路徑,也可以使用相對于context所屬的Host的appBase路徑。
Reloadable: 如果希望Catalina監視/WEB-INF/classes/和/WEB-INF/lib下面的類是否發生變化,在發生變化的時候自動重載web application,設為true。這個特征在開發階段很有用,但也大大增加了服務器的開銷。因此,在發布以后,不推薦使用。但是,你可以使用Manager應用在必要的時候觸發應用的重載。
CrossContext:如果想在應用內調用ServletContext.getContext()來返回在該虛擬主機上運行的其他web application的request dispatcher,設為true。在安全性很重要的環境中,設為false,使得getContext()總是返回null。缺省值為false。
2.7.2 HTTP服務器Apache2.0
Apache HTTP服務器被設計為一個強大、靈活的能夠在多種平臺上及不同的環境下工作的服務器。不同的平臺和不同的環境經常產生不同的需求,或是會為了達到同樣的最佳效果而采用不同的方法。Apache憑借它的模塊設計很好的適應了大量不同的環境。這一設計使得網站管理員能夠在編譯時和運行時憑借載入不同的模塊來決定服務器的不同附加功能。
Apache可以在混合多進程、多線程模式下運行,使很多(但不是全部的)配置的可擴縮性得到改善。Apache2.0重寫了原來的編譯系統,現在是基于autoconf和libtool的,使得Apache的配置系統與其他軟件包更加相似。Apache 2.0在諸如BeOS,OS/2和Windows等非Unix平臺上有了更好的速度和穩定性。 隨著平臺特定的multi-processing modules(MPMs)和 Apache Portable Runtime (APR)的引入,Apache在這些平臺上的指令由它們本地的API指令實現。 避免了以往使用POSIX模擬層造成的bug和性能低下。
2.7.3 Tomcat與Apache的整合
整合Apache有兩個目的
1. 把靜態和動態的內容分別有兩個不同的服務器承擔
2.達到簡單的負載均衡
修改Uri mapping的內容即可實現分流
如:
# Uri mapping?
[uri:/*.*]?
改成
# Uri mapping
[uri:/*.do]
[uri:/*.jsp]
第一步 把mod_jk_2.0.47.dll拷貝到{Apache}\modules文件夾中。
第二步 在{TOMCAT_HOME}\conf中新建一個workers.properties文件內容如下
#####--begin--########
?workers.tomcat_home={TOMCAT_HOME}?#讓mod_jk模塊知道Tomcat
?workers.java_home={JAVA_HOME}?????? #讓mod_jk模塊知道j2sdk
?ps=\
?worker.list=ajp13?????????????????????? #模塊版本
?worker.ajp13.port=8009?????????? ???????#工作端口
?worker.ajp13.host=localhost?????????????? #主機名稱
worker.ajp13.type=ajp13???????????????? #類型
?worker.ajp13.lbfactor=1????????????????? #代理數
######---end---#######
第三步?打開{Apache}\conf\httpd.conf 在文件末尾添加如下內容
########-beging--########
<VirtualHost?localhost>????????????????????? ??????? ??????? ????????
ServerAdmin?hua@mzh.com??????????????? #apache注冊的信息
DocumentRoot?D:\Web ??????? ??????? ????
#與tomcat虛擬目錄中docBase相同
ServerName?localhost??????? ??????????????? #主機名稱
ErrorLog?logs/robornet_home_log.txt??? #日志?? ??????? ??????? ????????
CustomLog?logs/robornet_Custom_log.txt?common?????????????????
JkMount /* ajp13???????? #目錄中的以下文件由tomcat處理????????????????????????
JkMount /*.jsp ajp13???
JkMount /*.do ajp13???????????????????????????????????????????
JkMount /*.gif ajp13?
JkMount /*.jpg ajp13???
JkMount /*.css ajp13
JkMount /*.js ajp13????
</VirtualHost>?
########-end--########
?
########-beging--########
LoadModule jk_module modules/mod_jk_2.0.47.dll
#裝載模塊,用于處理連接(對上一行的注釋,下同)
JkWorkersFile "{ TOMCAT_HOME }/conf/workers.properties"
#設置模塊的工作文件
JkLogFile "{ TOMCAT_HOME }/logs/mod_jk2.log"
?#設置模塊工作的日志文件,Tocmat啟動時會自建
JkLogLevel info
######---end---###########
其中:TOMCAT_HOME是tomcat的路徑
????????????? ?? JAVA_HOME是j2sdk的路徑
????????????? ?? Apache是Apache路徑