午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

深入Struts 1.1

 昵稱6300 2006-02-25



作為基于MVC模式的Web應(yīng)用最經(jīng)典框架,Struts已經(jīng)正式推出了1.1版本,該版本在以往版本的基礎(chǔ)上,提供了許多激動(dòng)人心的新功能。本文就將帶你走進(jìn)Struts 1.1去深入地了解這些功能。

說明:希望本文的讀者能有一定的Struts使用基礎(chǔ)。

Model 2

Struts是基于Model 2之上的,而Model 2是經(jīng)典的MVC(模型-視圖-控制器)模型的Web應(yīng)用變體,這個(gè)改變主要是由于網(wǎng)絡(luò)應(yīng)用的特性--HTTP協(xié)議的無狀態(tài)性引起的。Model 2的目的和MVC一樣,也是利用控制器來分離模型和視圖,達(dá)到一種層間松散耦合的效果,提高系統(tǒng)靈活性、復(fù)用性和可維護(hù)性。在多數(shù)情況下,你可以將Model 2與MVC等同起來。

下圖表示一個(gè)基于Java技術(shù)的典型網(wǎng)絡(luò)應(yīng)用,從中可以看出Model 2中的各個(gè)部分是如何對應(yīng)于Java中各種現(xiàn)有技術(shù)的。




在利用Model 2之前,我們是把所有的表示邏輯和業(yè)務(wù)邏輯都集中在一起(比如大雜燴似的JSP),有時(shí)也稱這種應(yīng)用模式為Model 1,Model 1的主要缺點(diǎn)就是緊耦合,復(fù)用性差以及維護(hù)成本高。



回頁首


Struts 1.1 和Model 2

既然Struts 1.1是基于Model 2之上,那它的底層機(jī)制也就是MVC,下面是Struts 1.1中的MVC實(shí)現(xiàn)示意圖:




圖解說明:其中不同顏色代表MVC的不同部分:紅色(控制器)、紫色(模型)和綠色(視圖)

首先,控制器(ActionServlet)進(jìn)行初始化工作,讀取配置文件(struts-config.xml),為不同的Struts模塊初始化相應(yīng)的ModuleConfig對象。比如配置文件中的Action映射定義都保存在ActionConfig集合中。相應(yīng)地有ControlConfig集合、FormBeanConfig集合、ForwardConfig集合和MessageResourcesConfig集合等。

提示:模塊是在Struts 1.1中新提出的概念,在稍后的內(nèi)容中我們將詳細(xì)介紹,你現(xiàn)在可以簡單地把模塊看作是一個(gè)子系統(tǒng),它們共同組成整個(gè)應(yīng)用,同時(shí)又各自獨(dú)立。Struts 1.1中所有的處理都是在特定模塊環(huán)境中進(jìn)行的。模塊的提出主要是為了解決Struts 1.0中單配置文件的問題。

控制器接收HTTP請求,并從ActionConfig中找出對應(yīng)于該請求的Action子類,如果沒有對應(yīng)的Action,控制器直接將請求轉(zhuǎn)發(fā)給JSP或者靜態(tài)頁面。否則控制器將請求分發(fā)至具體Action類進(jìn)行處理。

在控制器調(diào)用具體Action的execute方法之前,ActionForm對象將利用HTTP請求中的參數(shù)來填充自己(可選步驟,需要在配置文件中指定)。具體的ActionForm對象應(yīng)該是ActionForm的子類對象,它其實(shí)就是一個(gè)JavaBean。此外,還可以在ActionForm類中調(diào)用validate方法來檢查請求參數(shù)的合法性,并且可以返回一個(gè)包含所有錯(cuò)誤信息的ActionErrors對象。如果執(zhí)行成功,ActionForm自動(dòng)將這些參數(shù)信息以JavaBean(一般稱之為form bean)的方式保存在Servlet Context中,這樣它們就可以被其它Action對象或者JSP調(diào)用。

Struts將這些ActionForm的配置信息都放在FormBeanConfig集合中,通過它們Struts能夠知道針對某個(gè)客戶請求是否需要?jiǎng)?chuàng)建相應(yīng)的ActionForm實(shí)例。

Action很簡單,一般只包含一個(gè)execute方法,它負(fù)責(zé)執(zhí)行相應(yīng)的業(yè)務(wù)邏輯,如果需要,它也進(jìn)行相應(yīng)的數(shù)據(jù)檢查。執(zhí)行完成之后,返回一個(gè)ActionForward對象,控制器通過該ActionForward對象來進(jìn)行轉(zhuǎn)發(fā)工作。我們主張將獲取數(shù)據(jù)和執(zhí)行業(yè)務(wù)邏輯的功能放到具體的JavaBean當(dāng)中,而Action只負(fù)責(zé)完成與控制有關(guān)的功能。遵循該原則,所以在上圖中我將Action對象歸為控制器部分。

提示:其實(shí)在Struts 1.1中,ActionMapping的作用完全可以由ActionConfig來替代,只不過由于它是公共API的一部分以及兼容性的問題得以保留。ActionMapping通過繼承ActionConfig來獲得與其一致的功能,你可以等同地看待它們。同理,其它例如ActionForward與ForwardConfig的關(guān)系也是如此。

下圖給出了客戶端從發(fā)出請求到獲得響應(yīng)整個(gè)過程的圖解說明。




下面我們就來詳細(xì)地討論一下其中的每個(gè)部分,在這之前,先來了解一下模塊的概念。



回頁首


模塊

我們知道,在Struts 1.0中,我們只能在web.xml中為ActionServlet指定一個(gè)配置文件,這對于我們這些網(wǎng)上的教學(xué)例子來說當(dāng)然沒什么問題,但是在實(shí)際的應(yīng)用開發(fā)過程中,可能會(huì)有些麻煩。因?yàn)樵S多開發(fā)人員都可能同時(shí)需要修改配置文件,但是配置文件只能同時(shí)被一個(gè)人修改,這樣肯定會(huì)造成一定程度上的資源爭奪,勢必會(huì)影響開發(fā)效率和引起開發(fā)人員的抱怨。

在Struts 1.1中,為了解決這個(gè)并行開發(fā)的問題,提出了兩種解決方案:

  1. 多個(gè)配置文件的支持
  2. 模塊的支持

 

支持多個(gè)配置文件,是指你能夠?yàn)锳ctionServlet同時(shí)指定多個(gè)xml配置文件,文件之間以逗號(hào)分隔,比如Struts提供的MailReader演示例子中就采用該種方法。


                                      <!-- Action Servlet Configuration -->
                                    <servlet>
                                    <servlet-name>action</servlet-name>
                                    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
                                    <init-param>
                                    <param-name>config</param-name>
                                    <param-value>/WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml</param-value>
                                    </init-param>
                                    <load-on-startup>1</load-on-startup>
                                    </servlet>
                                    

這種方法可以很好地解決修改沖突的問題,不同的開發(fā)人員可以在不同的配置文件中設(shè)置自己的Action、ActionForm等等(當(dāng)然不是說每個(gè)開發(fā)人員都需要自己的配置文件,可以按照系統(tǒng)的功能模塊進(jìn)行劃分)。但是,這里還是存在一個(gè)潛在的問題,就是可能不同的配置文件之間會(huì)產(chǎn)生沖突,因?yàn)樵贏ctionServlet初始化的時(shí)候這幾個(gè)文件最終還是需要合并到一起的。比如,在struts-config.xml中配置了一個(gè)名為success的<forward>,而在struts-config-registration.xml中也配置了一個(gè)同樣的<forward>,那么執(zhí)行起來就會(huì)產(chǎn)生沖突。

為了徹底解決這種沖突,Struts 1.1中引進(jìn)了模塊(Module)的概念。一個(gè)模塊就是一個(gè)獨(dú)立的子系統(tǒng),你可以在其中進(jìn)行任意所需的配置,同時(shí)又不必?fù)?dān)心和其它的配置文件產(chǎn)生沖突。因?yàn)榍懊嫖覀冎v過,ActionServlet是將不同的模塊信息保存在不同的ModuleConfig對象中的。要使用模塊的功能,需要進(jìn)行以下的準(zhǔn)備工作:

1、為每個(gè)模塊準(zhǔn)備一個(gè)配置文件

2、配置web.xml文件,通知控制器

決定采用多個(gè)模塊以后,你需要將這些信息告訴控制器,這需要在web.xml文件進(jìn)行配置。下面是一個(gè)典型的多模塊配置:


                                    <init-param>
                                    <param-name>config</param-name>
                                    <param-value>/WEB-INF/struts-config.xml</param-value>
                                    </init-param>
                                    <init-param>
                                    <param-name>config/customer</param-name>
                                    <param-value>/WEB-INF/struts-config-customer.xml</param-value>
                                    </init-param>
                                    <init-param>
                                    <param-name>config/order</param-name>
                                    <param-value>/WEB-INF/struts-config-order.xml</param-value>
                                    </init-param>
                                    

要配置多個(gè)模塊,你需要在原有的一個(gè)<init-param>(在Struts 1.1中將其對應(yīng)的模塊稱為缺省模塊)的基礎(chǔ)之上,增加模塊對應(yīng)的<init-param>。其中<param-name>表示為config/XXX的形式,其中XXX為對應(yīng)的模塊名,<param-value>中還是指定模塊對應(yīng)的配置文件。上面這個(gè)例子說明該應(yīng)用有三個(gè)模塊,分別是缺省模塊、customer和order,它們分別對應(yīng)不同的配置文件。

3、準(zhǔn)備各個(gè)模塊所需的ActionForm、Action和JSP等資源

但是要注意的是,模塊的出現(xiàn)也同時(shí)帶來了一個(gè)問題,即如何在不同模塊間進(jìn)行轉(zhuǎn)發(fā)?有兩種方法可以實(shí)現(xiàn)模塊間的轉(zhuǎn)發(fā),一種就是在<forward>(全局或者本地)中定義,另外一種就是利用org.apache.struts.actions.SwitchAction。

下面就是一個(gè)全局的例子:


                                        ...
                                    <struts-config>
                                    ...
                                    <global-forwards>
                                    <forward name="toModuleB"
                                    contextRelative="true"
                                    path="/moduleB/index.do"
                                    redirect="true"/>
                                    ...
                                    </global-forwards>
                                    ...
                                    </struts-config>
                                    

可以看出,只需要在原有的path屬性前加上模塊名,同時(shí)將contextRelative屬性置為true即可。此外,你也可以在<action>中定義一個(gè)類似的本地<forward>。


                                      <action-mappings>
                                    <!-- Action mapping for profile form -->
                                    <action path="/login"
                                    type="com.ncu.test.LoginAction"
                                    name="loginForm"
                                    scope="request"
                                    input="tile.userLogin"
                                    validate="true">
                                    <forward name="success" contextRelative="true" path="/moduleA/login.do"/>
                                    </action>
                                    </action-mappings>
                                    

如果你已經(jīng)處在其他模塊,需要轉(zhuǎn)回到缺省模塊,那應(yīng)該類似下面這樣定義,即模塊名為空。


                                    <forward name="success" contextRelative="true" path="/login.do"/>
                                    

此外,你也可以使用org.apache.struts.actions.SwitchAction,例如:


                                        ...
                                    <action-mappings>
                                    <action path="/toModule"
                                    type="org.apache.struts.actions.SwitchAction"/>
                                    ...
                                    </action-mappings>
                                    ...
                                    



回頁首


ActionServlet

我們首先來了解MVC中的控制器。在Struts 1.1中缺省采用ActionServlet類來充當(dāng)控制器。當(dāng)然如果ActionServlet不能滿足你的需求,你也可以通過繼承它來實(shí)現(xiàn)自己的類。這可以在/WEB-INF/web.xml中來具體指定。

要掌握ActionServlet,就必須了解它所扮演的角色。首先,ActionServlet表示MVC結(jié)構(gòu)中的控制器部分,它需要完成控制器所需的前端控制及轉(zhuǎn)發(fā)請求等職責(zé)。其次,ActionServlet被實(shí)現(xiàn)為一個(gè)專門處理HTTP請求的Servlet,它同時(shí)具有servlet的特點(diǎn)。在Struts 1.1中它主要完成以下功能:

  • 接收客戶端請求
  • 根據(jù)客戶端的URI將請求映射到一個(gè)相應(yīng)的Action類
  • 從請求中獲取數(shù)據(jù)填充Form Bean(如果需要)
  • 調(diào)用Action類的execute()方法獲取數(shù)據(jù)或者執(zhí)行業(yè)務(wù)邏輯
  • 選擇正確的視圖響應(yīng)客戶

 

此外,ActionServlet還負(fù)責(zé)初始化和清除應(yīng)用配置信息的任務(wù)。ActionServlet的初始化工作在init方法中完成,它可以分為兩個(gè)部分:初始化ActionServlet自身的一些信息以及每個(gè)模塊的配置信息。前者主要通過initInternal、initOther和initServlet三個(gè)方法來完成。

我們可以在/WEB-INF/web.xml中指定具體的控制器以及初始參數(shù),由于版本的變化以及Struts 1.1中模塊概念的引進(jìn),一些初始參數(shù)被廢棄或者移入到/WEB-INF/struts-config.xml中定義。下面列出所有被廢棄的參數(shù),相應(yīng)地在web.xml文件中也不鼓勵(lì)再使用。

  • application
  • bufferSize
  • content
  • debug
  • factory
  • formBean
  • forward
  • locale
  • mapping
  • maxFileSize
  • multipartClass
  • nocache
  • null
  • tempDir

ActionServlet根據(jù)不同的模塊來初始化ModuleConfig類,并在其中以XXXconfig集合的方式保存該模塊的各種配置信息,比如ActionConfig,F(xiàn)ormBeanConfig等。

初始化工作完成之后,ActionServlet準(zhǔn)備接收客戶請求。針對每個(gè)請求,方法process(HttpServletRequest request, HttpServletResponse response)將被調(diào)用。該方法指定具體的模塊,然后調(diào)用該模塊的RequestProcessor的process方法。


                                    protected void process(HttpServletRequest request,
                                    HttpServletResponse response)
                                    throws IOException, ServletException {
                                    RequestUtils.selectModule(request, getServletContext());
                                    getRequestProcessor(getModuleConfig(request)).process(request, response);
                                    }
                                    

RequestProcessor包含了Struts控制器的所有處理邏輯,它調(diào)用不同的processXXX方法來完成不同的處理。下表列出其中幾個(gè)主要的方法:

方法 功能
processPath 獲取客戶端的請求路徑
processMapping 利用路徑來獲得相應(yīng)的ActionMapping
processActionForm 初始化ActionForm(如果需要)并存入正確的scope中
processActionCreate 初始化Action
processActionPerform 調(diào)用Action的execute方法
processForwardConfig 處理Action返回的ActionForward



回頁首


ActionForm

對于ActionForm你可以從以下幾個(gè)方面來理解它:

  1. ActionForm表示HTTP窗體中的數(shù)據(jù),可以將其看作是模型和視圖的中介,它負(fù)責(zé)保存視圖中的數(shù)據(jù)供模型或者視圖使用。Struts 1.1文檔中把它比作HTTP和Action之間的防火墻,這體現(xiàn)了ActionForm具有的過濾保護(hù)的作用,只有通過ActionForm驗(yàn)證的數(shù)據(jù)才能夠發(fā)送到Action處理。
  2. ActionForm是與一個(gè)或多個(gè)ActionConfig關(guān)聯(lián)的JavaBean,在相應(yīng)的action的execute方法被調(diào)用之前,ActionForm會(huì)自動(dòng)利用請求參數(shù)來填充自己(初始化屬性)。
  3. ActionForm是一個(gè)抽象類,你必須通過繼承來實(shí)現(xiàn)自己的類。

 

ActionForm首先利用屬性的getter和setter方法來實(shí)現(xiàn)初始化,初始化完畢后,ActionForm的validate方法被調(diào)用,你可以在其中來檢查請求參數(shù)的正確性和有效性,并且可以將錯(cuò)誤信息以ActionErrors的形式返回到輸入窗體。否則,ActionForm將被作為參數(shù)傳給action的execute方法以供使用。

ActionForm bean的生命周期可以設(shè)置為session(缺省)和request,當(dāng)設(shè)置為session時(shí),記得在reset方法中將所有的屬性重新設(shè)置為初始值。

由于ActionForm對應(yīng)于HTTP窗體,所以隨著頁面的增多,你的ActionForm將會(huì)急速增加。而且可能同一類型頁面字段將會(huì)在不同的ActionForm中出現(xiàn),并且在每個(gè)ActionForm中都存在相同的驗(yàn)證代碼。為了解決這個(gè)問題,你可以為整個(gè)應(yīng)用實(shí)現(xiàn)一個(gè)ActionForm或者至少一個(gè)模塊對應(yīng)于一個(gè)ActionForm。

但是,聚合的代價(jià)就是復(fù)用性很差,而且難維護(hù)。針對這個(gè)問題,在Struts 1.1中提出了DynaActionForm的概念。

DynaActionForm類

DynaActionForm的目的就是減少ActionForm的數(shù)目,利用它你不必創(chuàng)建一個(gè)個(gè)具體的ActionForm類,而是在配置文件中配置出所需的虛擬ActionForm。例如,在下表中通過指定<form-bean>的type為"org.apache.struts.action.DynaActionForm"來創(chuàng)建一個(gè)動(dòng)態(tài)的ActionForm--loginForm。


                                    <form-beans>
                                    <form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm">
                                    <form-property name="actionClass" type="java.lang.String"/>
                                    <form-property name="username" type="java.lang.String"/>
                                    <form-property name="password" type="java.lang.String"/>
                                    </form-bean>
                                    </form-beans>
                                    

動(dòng)態(tài)的ActionForm的使用方法跟普通的ActionForm相同,但是要注意一點(diǎn)。普通的ActionForm對象需要為每個(gè)屬性提供getter和setter方法,以上面的例子而言,我們需要提供getUsername() 和 setUsername()方法取得和設(shè)置username屬性,同樣地有一對方法用于取得和設(shè)置password屬性和actionClass屬性。

如果使用DynaActionForm,它將屬性保存在一個(gè)HashMap類對象中,同時(shí)提供相應(yīng)的get(name) 和 set(name)方法,其中參數(shù)name是要訪問的屬性名。例如要訪問DynaActionForm中username的值,可以采用類似的代碼:


                                    String username = (String)form.get("username");
                                    

由于值存放于一個(gè)HashMap對象,所以要記得對get()方法返回的Object對象做強(qiáng)制性類型轉(zhuǎn)換。正是由于這點(diǎn)區(qū)別,如果你在Action中非常頻繁地使用ActionForm對象,建議還是使用普通的ActionForm對象。

在Struts 1.1中,除了DynaActionForm以外,還提供了表單輸入自動(dòng)驗(yàn)證的功能,在包org.apache.struts.validator中提供了許多有用的類,其中最常見的就是DynaValidatorForm類。

DynaValidatorForm類

DynaValidatorForm是DynaActionForm的子類,它能夠提供動(dòng)態(tài)ActionForm和自動(dòng)表單輸入驗(yàn)證的功能。和使用DynaActionForm類似,你必須首先在配置文件中進(jìn)行配置:


                                    <form-beans>
                                    <form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm">
                                    <form-property name="actionClass" type="java.lang.String"/>
                                    <form-property name="username" type="java.lang.String"/>
                                    <form-property name="password" type="java.lang.String"/>
                                    </form-bean>
                                    </form-beans>
                                    

同時(shí)要定義驗(yàn)證的插件:


                                      <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
                                    <set-property property="pathnames"
                                    value="/WEB-INF/validator-rules.xml,
                                    /WEB-INF/validation.xml"/>
                                    </plug-in>
                                    

其中的validator.xml和validator-rules.xml分別表示驗(yàn)證定義和驗(yàn)證規(guī)則的內(nèi)容(可以合并在一起),比如針對上例中的DynaValidatorForm,我們有如下驗(yàn)證定義(validator.xml):


                                    <?xml version="1.0" encoding="ISO-8859-1" ?>
                                    <!DOCTYPE form-validation PUBLIC
                                    "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
                                    "http://jakarta./commons/dtds/validator_1_0.dtd">
                                    <!--    Validation Rules    $Id: validation.xml-->
                                    <form-validation>
                                    <!-- ========== Default Language Form Definitions ===================== -->
                                    <formset>
                                    <form name="loginForm">
                                    <field property="username" depends="required, minlength,maxlength">
                                    <arg0   key="prompt.username"/>
                                    <arg1   key="${var:minlength}" name="minlength" resource="false"/>
                                    <arg2   key="${var:maxlength}" name="maxlength" resource="false"/>
                                    <var>
                                    <var-name>maxlength</var-name>
                                    <var-value>16</var-value>
                                    </var>
                                    <var>
                                    <var-name>minlength</var-name>
                                    <var-value>3</var-value>
                                    </var>
                                    </field>
                                    <field property="password" depends="required, minlength,maxlength" bundle="alternate">
                                    <arg0   key="prompt.password"/>
                                    <arg1   key="${var:minlength}" name="minlength" resource="false"/>
                                    <arg2   key="${var:maxlength}" name="maxlength" resource="false"/>
                                    <var>
                                    <var-name>maxlength</var-name>
                                    <var-value>16</var-value>
                                    </var>
                                    <var>
                                    <var-name>minlength</var-name>
                                    <var-value>3</var-value>
                                    </var>
                                    </field>
                                    </form>
                                    </formset>
                                    </form-validation>
                                    

從上述定義中,我們可以看到對于字段username有三項(xiàng)驗(yàn)證:required, minlength, maxlength,意思是該字段不能為空,而且長度在3和16之間。而validator-rules.xml文件則可以采用Struts提供的缺省文件。注意在<form-bean>中定義的form是如何與validation.xml中的form關(guān)聯(lián)起來的。最后,要啟動(dòng)自動(dòng)驗(yàn)證功能,還需要將Action配置的validate屬性設(shè)置為true。


                                    <action path="/login"
                                    type="com.ncu.test.LoginAction"
                                    name="loginForm"
                                    scope="request"
                                    input="tile.userLogin"validate="true">
                                    

此時(shí),Struts將根據(jù)xml配置文件中的定義來檢驗(yàn)表單輸入,并將不符合要求的錯(cuò)誤信息輸出到頁面。但是你可能會(huì)想:這個(gè)功能雖然好,可是什么檢驗(yàn)都跑到服務(wù)器端執(zhí)行,效率方面和用戶易用性方面是不是有些問題?你可能會(huì)懷念起那簡單的JavaScript客戶端驗(yàn)證。

不用擔(dān)心,在Struts 1.1中也支持JavaScript客戶端驗(yàn)證。如果你選擇了客戶端驗(yàn)證,當(dāng)某個(gè)表單被提交以后,Struts 1.1啟動(dòng)客戶端驗(yàn)證,如果瀏覽器不支持JavaScript驗(yàn)證,則服務(wù)器端驗(yàn)證被啟動(dòng),這種雙重驗(yàn)證機(jī)制能夠最大限度地滿足各種開發(fā)者的需要。JavaScript驗(yàn)證代碼也是在validator-rules.xml文件中定義的。要啟動(dòng)客戶端驗(yàn)證,你必須在相應(yīng)的JSP文件中做如下設(shè)置:

  1. 為<html:form>增加onsubmit屬性
  2. 設(shè)置Javascript支持

 

下表中列出了一JSP文件的示例代碼,紅字部分為Javascript驗(yàn)證所需代碼。


                                    <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
                                    <table bgcolor="#9AFF9A" cellspacing="0" cellpadding="10" border="1" width="100%">
                                    <tr>
                                    <td>
                                    <table cellspacing="0" cellpadding="0" border="0" width="100%">
                                    <tr bgcolor="#696969">
                                    <td align="center">
                                    <font color="#FFFFFF">Panel 3: Profile</font>
                                    </td>
                                    </tr>
                                    <tr>
                                    <td><br>
                                    <html:errors/>
                                    <html:form action="/login.do" focus="username"  onsubmit="return validateLoginForm(this);">
                                    <html:hidden property="actionClass"/>
                                    <center>
                                    <table>
                                    <tr>
                                    <td>UserName:</td>
                                    <td><html:text property="username" size="20"/></td>
                                    </tr>
                                    <tr>
                                    <td>Password:</td>
                                    <td><html:password property="password" size="20"/></td>
                                    </tr>
                                    <tr>
                                    <td colspan=2><html:submit property="submitProperty" value="Submit"/></td>
                                    </table>
                                    </center>
                                    </html:form>
                                    <html:javascript formName="loginForm" dynamicJavascript="true" staticJavascript="false"/>
                                    <script language="Javascript1.1" src="staticJavascript.jsp"></script>
                                    </td>
                                    </tr>
                                    </table>
                                    </td>
                                    </tr>
                                    </table>
                                    

其中onsubmit的值為"return validateLoginForm(this);",它的語法為:

return validate + struts-config.xml中定義的form-bean名稱 + (this);

staticJavascript.jsp的內(nèi)容為:


                                    <%@ page language="java" %>
                                    <%-- set document type to Javascript (addresses a bug in Netscape according to a web resource --%>
                                    <%@ page contentType="application/x-javascript" %>
                                    <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
                                    <html:javascript dynamicJavascript="false" staticJavascript="true"/>
                                    

如果validator-rules.xml中定義的基本驗(yàn)證功能不能滿足你的需求,你可以自己添加所需的驗(yàn)證類型。



回頁首


Action

我們通過繼承Action類來實(shí)現(xiàn)具體的執(zhí)行類。具體Action類的功能一般都在execute(以前是perform方法)方法中完成,其中主要涉及到以下幾個(gè)方面:

  1. 輔助ActionForm進(jìn)行一些表單數(shù)據(jù)的檢查。
  2. 執(zhí)行必要的業(yè)務(wù)邏輯,比如存取數(shù)據(jù)庫,調(diào)用實(shí)體bean等。
  3. 更新服務(wù)器端的bean數(shù)據(jù),后續(xù)對象中可能會(huì)用到這些數(shù)據(jù),比如在JSP中利用bean:write來獲得這些數(shù)據(jù)。
  4. 根據(jù)處理結(jié)果決定程序的去處,并以ActionForward對象的形式返回給ActionServlet。

 

提示:由于在Action和ActionForm中都可以實(shí)現(xiàn)驗(yàn)證方法,那么如何來安排它們之間的分工呢?一般來說,我們秉著MVC分離的原則,也就是視圖級(jí)的驗(yàn)證工作放在ActionForm來完成,比如輸入不能為空,email格式是否正確,利用ValidatorForm可以很輕松地完成這些工作。而與具體業(yè)務(wù)相關(guān)的驗(yàn)證則放入Action中,這樣就可以獲得最大ActionForm重用性的可能。

前面我們提到過,我們主張將業(yè)務(wù)邏輯執(zhí)行分離到單獨(dú)的JavaBean中,而Action只負(fù)責(zé)錯(cuò)誤處理和流程控制。而且考慮到重用性的原因,在執(zhí)行業(yè)務(wù)邏輯的JavaBean中不要引用任何與Web應(yīng)用相關(guān)的對象,比如HttpServletRequest,HttpServletResponse等對象,而應(yīng)該將其轉(zhuǎn)化為普通的Java對象。關(guān)于這一點(diǎn),可以參考Petstore中WAF框架的實(shí)現(xiàn)思路。

此外,你可能還注意到execute與perform的一個(gè)區(qū)別:execute方法簡單地?cái)S出Exception異常,而perform方法則擲出ServletException和IOException異常。這不是說Struts 1.1在異常處理功能方面弱化了,而是為了配合Struts 1.1中一個(gè)很好的功能--宣稱式異常處理機(jī)制。



回頁首


宣稱式異常處理

和EJB中的宣稱式事務(wù)處理概念類似,宣稱式異常處理其實(shí)就是可配置的異常處理,你可以在配置文件中指定由誰來處理Action類中擲出的某種異常。你可以按照以下步驟來完成該功能:

  1. 實(shí)現(xiàn)org.apache.struts.action.ExceptionHandler的子類,覆蓋execute方法,在該方法中處理異常并且返回一個(gè)ActionForward對象
  2. 在配置文件中配置異常處理對象,你可以配置一個(gè)全局的處理類或者單獨(dú)為每個(gè)Action配置處理類

 

下表就定義了一個(gè)全局的處理類CustomizedExceptionHandler,它被用來處理所有的異常。


                                    <global-exceptions>
                                    <exception
                                    handler="com.yourcorp.CustomizedExceptionHandler"
                                    key="global.error.message"
                                    path="/error.jsp"
                                    scope="request"
                                    type="java.lang.Exception"/>
                                    </global-exceptions>
                                    

其中具體的參數(shù)含義,可以參考ExceptionHandler.java源文件。



回頁首


taglib

講完了模型和控制器,接下來我們要涉及的是視圖。視圖的角色主要是由JSP來完成,從JSP的規(guī)范中可以看出,在視圖層可以"折騰"的技術(shù)不是很多,主要的就是自定義標(biāo)記庫的應(yīng)用。Struts 1.1在原有的四個(gè)標(biāo)記庫的基礎(chǔ)上新增了兩個(gè)標(biāo)記庫--Tiles和Nested。

其中Tiles除了替代Template的基本模板功能外,還增加了布局定義、虛擬頁面定義和動(dòng)態(tài)頁面生成等功能。Tiles強(qiáng)大的模板功能能夠使頁面獲得最大的重用性和靈活性,此外可以結(jié)合Tiles配置文件中的頁面定義和Action的轉(zhuǎn)發(fā)邏輯,即你可以將一個(gè)Action轉(zhuǎn)發(fā)到一個(gè)在Tiles配置文件中定義的虛擬頁面,從而減少頁面的數(shù)量。比如,下表中的Action定義了一個(gè)轉(zhuǎn)發(fā)路徑,它的終點(diǎn)是tile.userMain,而后者是你在Tiles配置文件中定義的一個(gè)頁面。


                                    <!-- ========== Action Mapping Definitions ============================== -->
                                    <action-mappings>
                                    <!-- Action mapping for profile form -->
                                    <action path="/login"
                                    type="com.ncu.test.LoginAction"
                                    name="loginForm"
                                    scope="request"
                                    input="tile.userLogin"
                                    validate="true">
                                    <forward name="success" path="tile.userMain"/>
                                    </action>
                                    </action-mappings>
                                    

Tiles配置文件:tiles-defs.xml


                                    <!DOCTYPE tiles-definitions PUBLIC
                                    "-//Apache Software Foundation//DTD Tiles Configuration//EN"       "http://jakarta./struts/dtds/tiles-config.dtd">
                                    <tiles-definitions>
                                    <!-- =======================================================  -->
                                    <!-- Master definitions                                       -->
                                    <!-- =======================================================  -->
                                    <!-- Page layout used as root for all pages. -->
                                    <definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp">
                                    <put name="titleString" value="CHANGE-ME"/>
                                    <put name="topMenu" value="/tiles-components/topMenu.jsp"/>
                                    <put name="leftMenu" value="/tiles-components/panel1.jsp"/>
                                    <put name="body" value="CHANGE-ME"/>
                                    <put name="footer" value="/tiles-components/footer.jsp"/>
                                    </definition>
                                    <!-- =======================================================  -->
                                    <!-- Page definitions 					-->
                                    <!-- =======================================================  -->
                                    <!-- User Login page -->
                                    <definition name="tile.userLogin" extends="rootLayout">
                                    <put name="titleString" value="User Login"/>
                                    <put name="body" value="/src/userLogin.jsp"/>
                                    </definition>
                                    <!-- User Main page -->
                                    <definition name="tile.userMain" extends="rootLayout">
                                    <put name="titleString" value="User Main"/>
                                    <put name="body" value="/src/userMain.jsp"/>
                                    </definition>
                                    </tiles-definitions>
                                    

而Nested標(biāo)記庫的作用是讓以上這些基本標(biāo)記庫能夠嵌套使用,發(fā)揮更大的作用。



回頁首


Commons Logging 接口

所謂的Commons Logging接口,是指將日志功能的使用與日志具體實(shí)現(xiàn)分開,通過配置文件來指定具體使用的日志實(shí)現(xiàn)。這樣你就可以在Struts 1.1中通過統(tǒng)一的接口來使用日志功能,而不去管具體是利用的哪種日志實(shí)現(xiàn),有點(diǎn)于類似JDBC的功能。Struts 1.1中支持的日志實(shí)現(xiàn)包括:Log4J,JDK Logging API, LogKit,NoOpLog和SimpleLog。

你可以按照如下的方式來使用Commons Logging接口(可以參照Struts源文中的許多類實(shí)現(xiàn)):


                                    package com.foo;
                                    // ...
                                    import org.apache.commons.logging.Log;
                                    import org.apache.commons.logging.LogFactory;
                                    //...
                                    public class Foo {
                                    // ...
                                    private static Log log = LogFactory.getLog(Foo.class);
                                    // ...
                                    public void setBar(Bar bar) {
                                    if (log.isTraceEnabled()) {
                                    log.trace("Setting bar to " + bar);
                                    }
                                    this.bar = bar;
                                    }
                                    // ...
                                    }
                                    

而開啟日志功能最簡單的辦法就是在WEB-INF/classes目錄下添加以下兩個(gè)文件:

commons-logging.properties文件:


                                    # Note: The Tiles framework now uses the commons-logging package to output different information or debug statements.
                                    Please refer to this package documentation to enable it. The simplest way to enable logging is to create two files in
                                    WEB-INF/classes:
                                    # commons-logging.properties
                                    # org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
                                    # simplelog.properties
                                    # # Logging detail level,
                                    # # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
                                    #org.apache.commons.logging.simplelog.defaultlog=trace
                                    org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
                                    

simplelog.properties文件:


                                    # Logging detail level,
                                    # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
                                    org.apache.commons.logging.simplelog.defaultlog=fatal
                                    

這里我們采用的日志實(shí)現(xiàn)是SimpleLog,你可以在simplelog.properties文件指定日志明細(xì)的級(jí)別:trace,debug,info,warn,error和fatal,從trace到fatal錯(cuò)誤級(jí)別越來越高,同時(shí)輸出的日志信息也越來越少。而這些級(jí)別是和org.apache.commons.logging.log接口中的方法一一對應(yīng)的。這些級(jí)別是向后包含的,也就是前面的級(jí)別包含后面級(jí)別的信息。



回頁首


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多