posts - 495,  comments - 11,  trackbacks - 0

          Struts的plug-in配置部分明確指出,Spring的配置文件有兩個:applicationContext.xml和action-servlet.xml。其實,完全可以使用一個配置文件。通常,習慣將Action Bean配置在控制器的context內。action-servlet.xml用于配置表現層上下文,其詳細配置信息如下:

          <?xml version="1.0" encoding="gb2312"?>

          <!-- 指定Spring配置文件的根元素,以及對應的Schame信息 -->

          <beans xmlns="http://www.springframework.org/schema/beans"

          ?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

          ?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

          ??? <!-- 每個request請求產生一個新實例,將所有該請求的作用域配置成request -->

          ??? <bean name="/login" class="lee.LoginAction" scope="request">

          ??????? <property name="vb" ref="vb"/>

          ??? </bean>

          </beans>

          因為每次請求都應該啟動新的Action處理用戶請求,因此,應將Action的作用域配置成Request。

          注意:ActionServlet轉發請求時,是根據Bean的name屬性,而不是id屬性。因此,此處確定的name屬性與Struts的action屬性相同。

          applicationContext.xml只有一個bean配置,即vb bean。其詳細配置如下:

          <?xml version="1.0" encoding="GBK"?>

          <!-- 指定Spring 配置文件的根元素,以及對應的Schema信息 -->

          <beans xmlns="http://www.springframework.org/schema/beans"

          ?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

          ?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

          ??? <!-- 配置ValidBean實例 -->

          ??? <bean id="vb" class="lee.ValidBeanImpl"/>

          </beans>

          ValidBeanImpl是一個業務邏輯bean,本示例程序中僅作簡單的判斷,ValidBeanImpl的源代碼如下:

          //面向接口編程,實現ValidBean接口

          public class ValidBeanImpl implements ValidBean

          {

          ??? //根據輸入的用戶名和密碼判斷是否有效

          ??? public boolean valid(String username,String pass)

          ??? {

          ??????? //有效,返回true

          ??????? if (username.equals("scott") && pass.equals("tiger"))

          ??????? {

          ??????????? return true;

          ??????? }

          ??????? return false;

          ??? }

          }

          注意:上面的業務邏輯組件非常簡單,它只是一個示意。如果是真實的應用,業務邏輯組件應該通過DAO組件來實現業務邏輯方法。

          應用的業務邏輯控制器,Action則負責調用業務邏輯組件的方法,并根據業務邏輯組件方法的返回值,確定如何響應用戶請求。下面是該示例應用控制器的代碼:

          //業務控制器繼承Action

          public class LoginAction extends Action

          {

          ??? //action控制器將調用的業務邏輯組件

          ??? private ValidBean vb;

          ??? //依賴注入業務邏輯組件的setter方法

          ??? public void setVb(ValidBean vb)

          ??? {

          ??????? this.vb = vb;

          ??? }

          ??? //必須重寫該核心方法,該方法actionForm將表單的請求參數封裝成值對象

          ??? public ActionForward execute(ActionMapping mapping, ActionForm form,

          ?????? HttpServletRequest request, HttpServletResponse response)throws
          ?????? Exception

          ??? {

          ??????? //form由ActionServlet轉發請求時創建,封裝了所有的請求參數

          ??????? LoginForm loginForm = (LoginForm)form;

          ??????? //獲取username請求參數

          ??????? String username = loginForm.getUsername();

          ??????? //獲取pass請求參數

          ??????? String pass = loginForm.getPass();

          ??????? //下面為服務器端的數據校驗

          ??????? String errMsg = "";

          ??????? //判斷用戶名不能為空

          ??????? if (username == null || username.equals(""))

          ??????? {

          ??????????? errMsg += "您的用戶名丟失或沒有輸入,請重新輸入";

          ??????? }

          ??????? //判斷密碼不能為空

          ??????? else if(pass == null || pass.equals(""))

          ??????? {

          ??????????? errMsg += "您的密碼丟失或沒有輸入,請重新輸入";

          ??????? }

          ??????? //如果用戶名和密碼不為空,才調用業務邏輯組件

          ??????? else

          ??????? {

          ??????????? //vb是業務邏輯組件,由容器注入

          ??????????? if (vb.valid(username,pass))

          ??????????? {

          ??????????????? return mapping.findForward("welcome");

          ??????????? }

          ??????????? else

          ??????????? {

          ??????????????? errMsg = "您的用戶名和密碼不匹配";

          ??????????? }

          ??????? }

          ??????? //判斷是否生成了錯誤信息

          ??????? if (errMsg != null && !errMsg.equals(""))

          ??????? {

          ??????????? //如果有錯誤信息,將錯誤信息保存在request里,并跳轉到input對應的
          ??????????? forward對象

          ??????????? request.setAttribute("err" , errMsg);

          ??????????? return mapping.findForward("input");

          ??????? }

          ??????? else

          ??????? {

          ??????????? //如果沒有錯誤信息,跳轉到welcome對應的forward對象

          ??????????? return mapping.findForward("welcome");

          ??????? }

          ??? }

          }

          在本應用中,使用了Struts的客戶端數據校驗,讓Action繼承ValidatorActionForm即可。ActionForm的代碼非常簡單,此處不再贅述。

          為了完成數據校驗,還應該編寫數據校驗規則文件。在struts-config.xml文件的尾部,另有一個plug-in用來加載校驗文件,其中validator-rules.xml文件位于struts壓縮包的lib下,直接復制過來即可使用,而validator.xml必須自己編寫,validator.xml文件如下:

          <?xml version="1.0" encoding="GBK"?>

          <!-- 驗證規則文件的文件頭,包括DTD等信息 -->

          <!DOCTYPE form-validation PUBLIC

          ????????? "-//Apache Software Foundation//DTD Commons Validator Rules
          ????????? Configuration 1.1.3//EN"

          ????????? "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">

          <!-- 驗證文件的根元素 -->

          <form-validation>

          ??? <!-- 所有需要驗證的form都放在formset里 -->

          <formset>

          ??? <!-- 需要驗證的form名,該名與struts里配置的名相同 -->

          ??? <form name="loginForm">

          ??????? <!-- 指定該form的username域必須滿足的規則:必填、模式匹配 -->

          ??????? <field property="username" depends="required,mask">

          ??????? ??? <arg key="loginForm.username" position="0"/>

          ??????????? <var>

          ??????????????? <!-- 確定匹配模式的正則表達式 -->

          ??????????? <var-name>mask</var-name>

          ??????????? <var-value>^[a-zA-Z]+$</var-value>

          ??????????? </var>

          ??????? </field>

          ??????? <!-- 指定該form的pass域必須滿足的規則:必填 -->

          ??????? <field property="pass" depends="required">

          ??????????? <msg name="required" key="pass.required"/>

          ??????? ??? <arg key="loginForm.pass" position="0"/>

          ??????? </field>

          ??? </form>

          </formset>

          </form-validation>

          上面示例程序的結構非常清晰:表現層組件(Action)配置在action-servlet.xml文件中,而業務邏輯層組件(vb)配置在applicationContext.xml文件中,如果應用中有DAO組件,將DAO組件配置在dao-context.xml文件中。將3個文件放在plug-in元素里一起加載。

          文本框:圖6.3  DelegatingRequestProcessor整合策略的登錄失敗效果DelegatingRequestProcessor會將請求轉發到Action,該Action已經處于IoC容器管理之下,因此,可以方便地訪問容器中的其他Bean。

          通過配置文件可以看出,Action根本無須type屬性,即struts-config.xml中Action根本沒有實例化過,DelegatingRequestProcessor將請求轉發給Spring容器中的同名Bean。這種轉發的時機非常早,避免了創建struts-config.xml配置文件中的Action,因而性能非常好。

          圖6.3是采用這種整合策略的執行效果。

          6.4.4 使用DelegatingActionProxy

          使用DelegatingRequestProcessor簡單方便,但有一個缺點,RequestProcessor是Struts的一個擴展點,也許應用程序本身就需要擴展RequestProcessor,而DelegatingRequest- Processor已經使用了這個擴展點。

          為了重新利用Struts的RequestProcessor這個擴展點,有兩個做法:

          ?? ● 應用程序的RequestProcessor不再繼承Struts的RequestProcessor,改為繼承DelegatingRequestProcessor。

          ?? ● 使用DelegatingActionProxy。

          前者常常有一些未知的風險,而后者是Spring推薦的整合策略。使用Delegating- ActionProxy與DelegatingRequestProcessor的目的都只有一個,將請求轉發給Spring管理的Bean。

          DelegatingRequestProcessor直接替換了原有的RequestProcessor,在請求轉發給action之前,轉發給Spring管理的Bean;而DelegatingActionProxy則被配置成Struts的Action,即所有的請求先被ActionServlet截獲,請求被轉發到對應的Action,而action的實現類全都是DelegatingActionProxy,DelegatingActionProxy再將請求轉發給Spring容器的Action。

          可以看出,使用DelegatingActionProxy比使用DelegatingRequestProcessor要晚一步轉發到Spring的context。但通過這種方式可以避免占用擴展點。

          與使用DelegatingRequestProcessor相比,使用DelegatingActionProxy僅需要去掉controller配置元素,并將所有的action實現類改為DelegatingActionProxy即可。詳細的配置文件如下:

          <!-- XML文件的版本和編碼集 -->

          <?xml version="1.0" encoding="gb2312"?>

          <!-- struts配置文件的文件頭,包括DTD等信息 -->

          <!DOCTYPE struts-config PUBLIC

          ????????? "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"

          ????????? "http://struts.apache.org/dtds/struts-config_1_2.dtd">

          <!-- struts配置文件的根元素 -->

          <struts-config>

          ??? <!-- 配置formbean,所有的formbean都放在form-beans元素里定義 -->

          ??? <form-beans>

          ??????? <!-- 定義了一個formbean,確定formbean名和實現類 -->

          ??????? <form-bean name="loginForm" type="lee.LoginForm"/>

          ??? </form-beans>

          ??? <!-- 定義action部分,所有的action都放在action-mapping元素里定義 -->

          ??? <action-mappings>

          ??????? <!-- 這里只定義了一個action。必須配置action的type元素為
          ??? ??? DelegatingActionProxy -->

          ??????? <action path="/login" type="org.springframework.web.struts.
          ??????? DelegatingActionProxy"

          ??????????? name="loginForm" scope="request" validate="true" input=
          ??????????? "/login.jsp" >

          ??????????? <!-- 定義action內的兩個局部forward元素 -->

          ??????????? <forward name="input" path="/login.jsp"/>

          ??????????? <forward name="welcome" path="/welcome.html"/>

          ??????? </action>

          ??? </action-mappings>

          ??? <!-- 加載國際化的資源包 -->

          ??? <message-resources parameter="mess"/>

          ??? <!-- 裝載驗證的資源文件 -->

          ??? <plug-in className="org.apache.struts.validator.ValidatorPlugIn">

          ??????? <set-property property="pathnames" value="/WEB-INF/validator-
          ??????? rules.xml,/WEB-INF/validation.xml" />

          ??????? <set-property property="stopOnFirstError" value="true"/>

          ??? </plug-in>

          ??? <!-- 裝載Spring配置文件,隨應用啟動創建ApplicationContext實例 -->

          ??? <plug-in className="org.springframework.web.struts. ContextLoaderPlugIn">
          ??????? <set-property property="contextConfigLocation"

          ??????????? value="/WEB-INF/applicationContext.xml,

          ?????????????????? /WEB-INF/action-servlet.xml"/>

          ??? </plug-in>

          </struts-config>

          DelegatingActionProxy接收ActionServlet轉發過來的請求,然后轉發給Application- Context管理的Bean,這是典型的鏈式處理。

          通過配置文件可以看出,struts-config.xml文件中配置了大量DelegatingActionProxy實例,Spring容器中也配置了同名的Action。即Struts的業務控制器分成了兩個部分:第一個部分是Spring的DelegatingActionProxy,這個部分沒有實際意義,僅僅完成轉發;第二個部分是用戶的Action實現類,該實現類負責真實的處理。

          這種策略的性能比前一種策略的效果要差一些,因為需要多創建一個Delegating- ActionProxy實例。而且,J2EE應用中Action非常多,這將導致大量創建DelegatingActionProxy實例,使用一次之后,等待垃圾回收機制回收——這對性能的影響不可避免。

          圖6.4是DelegatingActionProxy的執行效果。

          文本框:圖6.4  DelegatingActionProxy整合策略的登錄成功效果注意:使用DelegatingActionProxy的整合策略,可避免占用Struts的RequestProcessor擴展點,但降低了整合性能。

          6.4.5 使用ActionSupport代替Action

          前面已經介紹了,Spring與Struts的整合還有一種策略,讓Struts的Action顯式獲取Spring容器中的Bean。在這種策略下,Struts的Action不接受IoC容器管理,Action的代碼與Spring API部分耦合,造成代碼污染。這種策略也有其好處:代碼的可讀性非常強,Action的代碼中顯式調用業務邏輯組件,而無須等待容器注入。

          Action中訪問ApplicationContext有兩種方法:

          ?? ● 利用WebApplicationContextUtils工具類。

          ?? ● 利用ActionSupport支持類。

          通過WebApplicationContextUtils,可以顯式獲得Spring容器的引用(請參閱6.4.1節的內容),而ActionSupport類則提供了一個更簡單的方法getWebApplicationContext(),該方法可直接獲取Spring容器的引用。

          所謂ActionSupport類,是指Spring提供了系列擴展。Spring擴展了Struts的Action,在Struts的Action后加上Support后綴,Spring擴展的Action有如下幾個:

          ?? ● ActionSupport。

          ?? ● DispatchActionSupport。

          ?? ● LookupDispatchActionSupport。

          ?? ● MappingDispatchActionSupport。

          下面的示例將展示這種整合策略,在這種整合策略下,Struts的Action改為繼承Spring擴展后的Action,下面是應用的Action代碼:

          //新的業務控制器,繼承Spring的ActionSupport類

          public class LoginAction extends ActionSupport

          {

          ??? //依然將ValidBean作為成員變量

          ??? private ValidBean vb;

          ??? //構造器,注意:不可在構造器中調用getWebApplicationContext()方法

          ??? public LoginAction()

          ??? {

          ??? }

          ??? //完成ValidBean的初始化

          ??? public ValidBean getVb()

          ??? {

          ??????? return(ValidBean)getWebApplicationContext().getBean("vb");

          ??? }

          ??? //必須重寫該核心方法,該方法actionForm將表單的請求參數封裝成值對象

          ??? public ActionForward execute(ActionMapping mapping, ActionForm form,

          ?????? HttpServletRequest request, HttpServletResponse response)throws
          ?????? Exception

          ??? {

          ??????? //form由ActionServlet轉發請求時創建,封裝了所有的請求參數

          ??????? LoginForm loginForm = (LoginForm)form;

          ??????? //獲取username請求參數

          ??????? String username = loginForm.getUsername();

          ??????? //獲取pass請求參數

          ??????? String pass = loginForm.getPass();

          ??????? //下面為服務器端的數據校驗

          ??????? String errMsg = "";

          ??????? //判斷用戶名不能為空

          ??????? if (username == null || username.equals(""))

          ??????? {

          ??????????? errMsg += "您的用戶名丟失或沒有輸入,請重新輸入";

          ??????? }

          ??????? //判斷密碼不能為空

          ??????? else if(pass == null || pass.equals(""))

          ??????? {

          ??????????? errMsg += "您的密碼丟失或沒有輸入,請重新輸入";

          ??????? }

          ??????? //如果用戶名和密碼不為空,才調用業務邏輯組件

          ??????? else

          ??????? {

          ??????????? //vb是業務邏輯組件,通過上面的初始化方法獲得

          ??????????? if (getVb().valid(username,pass))

          ??????????? {

          ??????????????? return mapping.findForward("welcome");

          ??????????? }

          ??????????? else

          ??????????? {

          ??????????????? errMsg = "您的用戶名和密碼不匹配";

          ??????????? }

          ??????? }

          ??????? //判斷是否生成了錯誤信息

          ??????? if (errMsg != null && !errMsg.equals(""))

          ??????? {

          ??????????? //如果有錯誤信息,將錯誤信息保存在request里,并跳轉到input對應的
          ??????????? //forward對象

          ??????????? request.setAttribute("err" , errMsg);

          ??????????? return mapping.findForward("input");

          ??????? }

          ??????? else

          ??????? {

          ??????????? //如果沒有錯誤信息,跳轉到welcome對應的forward對象

          ??????????? return mapping.findForward("welcome");

          ??????? }

          ??? }

          }

          在上面的Action代碼中,Action顯式獲取容器中的業務邏輯組件,而不是依靠Spring容器的依賴注入。在這種整合策略下,表現層的控制器組件不再接受IoC容器管理。因此,沒有控制器上下文,應將原有的action-servlet.xml文件刪除,并修改plug-in元素,不要加載該文件。還要修改Action配置,將Action配置的type元素修改成實際的處理類。這????? 種整合策略也有一個好處:代碼的可讀性更強,對傳統Struts應用開發的改變很小,容易使用。

          將該Action部署在struts-config.xml中,Struts將負責創建該Action。struts-config.xml文件的源代碼如下:

          <!-- XML文件的版本和編碼集 -->

          <?xml version="1.0" encoding="gb2312"?>

          <!-- Struts配置文件的文件頭,包括DTD等信息 -->

          <!DOCTYPE struts-config PUBLIC

          ????????? "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"

          ????????? "http://struts.apache.org/dtds/struts-config_1_2.dtd">

          <!-- struts配置文件的根元素 -->

          <struts-config>

          ??? <!-- 配置formbean,所有的formbean都放在form-beans元素里定義 -->

          ??? <form-beans>

          ??????? <!-- 定義了一個formbean,確定formbean名和實現類 -->

          ??????? <form-bean name="loginForm" type="lee.LoginForm"/>

          ??? </form-beans>

          ??? <!-- 定義action部分,所有的action都放在action-mapping元素里定義 -->

          ??? <action-mappings>

          ??????? <!-- 這里只定義了一個action。action的類型為ActionSupport的子類 -->

          ??????? <action path="/login" type="type="lee.LoginAction"

          ??????????? name="loginForm" scope="request" validate="true" input=
          ??????????? "/login.jsp" >

          ??????????? <!-- 定義action內的兩個局部forward元素 -->

          ??????????? <forward name="input" path="/login.jsp"/>

          ??????????? <forward name="welcome" path="/welcome.html"/>

          ??????? </action>

          ??? </action-mappings>

          ??? <!-- 加載國際化的資源包 -->

          ??? <message-resources parameter="mess"/>

          ??? <!-- 裝載驗證的資源文件 -->

          ??? <plug-in className="org.apache.struts.validator.ValidatorPlugIn">

          ??????? <set-property property="pathnames" value="/WEB-INF/validator-
          ??????? rules.xml,/WEB-INF/validation.xml" />

          ??????? <set-property property="stopOnFirstError" value="true"/>

          ??? </plug-in>

          </struts-config>

          此時,Spring無須使用配置Action的配置文件,這種配置方式非常簡單。只需要業務邏輯組件的配置文件,業務邏輯組件的配置文件與前面的示例沒有任何改變。

          該配置文件中的業務邏輯組件由Spring容器負責實現,而ActionSupport能夠先定位Spring容器,然后獲得容器的業務邏輯組件。

          這種整合策略的執行效果與前面兩種整合策略的執行效果完全相同。從代碼中分析可見,在這種整合策略下,業務控制器再次退回到Struts起初的設計。僅由strutsconfig.xml中Action充當,從而避免了像DelegatingActionProxy整合策略的性能低下,因為可以只需要創建實際的Action實例。

          注意:在這種整合策略下,Struts開發者的改變最小,最接近傳統Struts應用開發者的習慣。但這種整合策略會造成代碼污染,因為Action類必須繼承Spring的ActionSupport類。

          posted on 2009-07-19 10:23 jadmin 閱讀(76) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 葵青区| 文化| 密山市| 石楼县| 重庆市| 措勤县| 岱山县| 四川省| 石嘴山市| 新余市| 仙桃市| 都匀市| 哈巴河县| 镶黄旗| 大埔县| 平果县| 武宣县| 威海市| 垣曲县| 休宁县| 阳泉市| 祥云县| 惠水县| 建湖县| 津南区| 丹棱县| 南昌县| 隆尧县| 巴南区| 鄂尔多斯市| 天镇县| 田阳县| 平定县| 安阳县| 体育| 沁源县| 浦县| 巩留县| 彰武县| 延津县| 大悟县|