程序 人生

          程序 人生

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            11 Posts :: 2 Stories :: 18 Comments :: 0 Trackbacks

          ? Struts快速學(xué)習(xí)指南 素材來自于《Programming Jakarta Struts》一書??
          1.???? Struts簡介
          Struts 是一個技術(shù)框架,由Craig R. McClanahan編寫,并且在2000年的時候捐獻給了ASF,目前,有很多組織和個人參與Struts框架的開發(fā),使得Struts保持高速成長,同時,利用Struts開發(fā)的應(yīng)用越來越多,使其成為web應(yīng)用MVC模式中VC部分事實上的標(biāo)準(zhǔn)。
          1.1? Web技術(shù)歷史
          1.1.1?????????? CGI
          web應(yīng)用開發(fā)中歷史上,CGI(common gateway interface)是最早使用的一種技術(shù),通過為不同的平臺,不同的web server編寫插件編寫應(yīng)用接口,來滿足通過web方式編寫應(yīng)用的需求。當(dāng)時流行的方式包含NSAPI/ISAPI,使用Perl來編寫CGI程序。CGI最大的問題就是線程并發(fā)的問題,當(dāng)時給很多人的感覺是CGI訪問速度慢,其主要原因是應(yīng)用程序所編寫的CGI沒有考慮多線程。
          1.1.2?????????? Servlet
          ??? 作為一種跨平臺語言的服務(wù)器端技術(shù),其一經(jīng)產(chǎn)生就備受矚目,采用Servlet開發(fā)的應(yīng)用,不用考慮平臺,多線程等讓人頭疼的問題,使得開發(fā)人員專注于業(yè)務(wù)邏輯的實現(xiàn),大大解放了生產(chǎn)力。但是,在Servlet中嵌入html無疑是開發(fā)人員的噩夢,與同時期微軟的ASP相比,Servlet在開發(fā)效率方面讓人不敢恭維。
          1.1.3?????????? Java Server Pages
          JSP從很大程度上時參考了ASP的想法,使得采用Java語言開發(fā)服務(wù)器端應(yīng)用非常容易,同時因為java與生俱來的跨平臺、安全性、易用性優(yōu)勢,當(dāng)然,還有開發(fā)人員的高工資 ,使得JSP逐漸在Web服務(wù)器端應(yīng)用開發(fā)中占據(jù)了主流位置。
          ?
          2.???? Struts安裝
          Struts作為一個J2EE 框架,很容易和你的web應(yīng)用結(jié)合起來,你僅僅需要作以下幾個步驟:
          1、? 下在Struts1.1 二進制壓縮包,將壓縮包解壓到%STRUTS_HOME%目錄,目錄結(jié)構(gòu)如下如示:
          ?
          2、? 建立你的標(biāo)準(zhǔn)web應(yīng)用程序,所謂標(biāo)準(zhǔn)應(yīng)用程序是指在web應(yīng)用程序的根目錄下有一個WEB-INFO目錄,WEB-INF下有classes,lib目錄,classes下面有個web.xml文件。本文后續(xù)假設(shè)你的web應(yīng)用在%WEB_ROOT%目錄下。
          3、? 將%STRUTS_HOME%/lib下所有文件copy到%WEB_ROOT%/WEB-INF/lib下。
          4、? 配置%WEB_ROOT%/WEB-INF/classes/web.xml以滿足Struts需要,具體如下:
          1、? 在配置文件中映射ActionServlet,ActionServlet用于接受所有訪問者的請求。在Struts應(yīng)用中,所有對應(yīng)用程序的請求,都會被WEB SERVER定向到ActionServlet進行統(tǒng)一控制、分配處理,ActionServlet可以看作是Struts框架的核心,樞紐。
          ?? <web-app>?
          ?<servlet>
          ? <servlet-name>controller</servlet-name>
          ? <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
          ?</servlet>
          </web-app>
          ?
          2、? 配置servlet映射,通過servlet映射可以將用戶訪問web應(yīng)用的擴展名映射到具體處理的servlet,例如,將所有以.do為擴展名的頁面的請求交給ActionServlet處理。
          <web-app>?
          ?<servlet>
          ? <servlet-name>controller</servlet-name>
          ? <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
          ?</servlet>
          ?<servlet-mapping>
          ? <servlet-name>controller</servlet-name>
          ? <url-pattern>*.do</url-pattern>
          ?</servlet-mapping>
          </web-app>
          ? 另外,也可以采用如下方式進行映射,該方式將所有對/action/目錄下文件的訪問請求交給ActionServlet處理。
          <web-app>?
          ?<servlet>
          ? <servlet-name> controller </servlet-name>
          ? <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
          ?</servlet>
          ?<servlet-mapping>
          ? <servlet-name>controller</servlet-name>
          ? <url-pattern>>/action/*</url-pattern>
          ?</servlet-mapping>
          </web-app>
          ?
          3、? 配置ActionServlet的初始化參數(shù),Struts1.1有一些指定的初始化參數(shù),用于指明Struts應(yīng)用所需要的配置文件,debug等級等。
          <web-app>?
          ?<servlet>
          ? <servlet-name>controller</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</param-value>
          ? </init-param>
          ? <init-param>
          ?? <param-name>host</param-name>
          ?? <param-value>localhost</param-value>
          ? </init-param>
          ? <init-param>
          ?? <param-name>port</param-name>
          ?? <param-value>7001</param-value>
          ? </init-param>
          ?</servlet>
          ?<servlet-mapping>
          ? <servlet-name> controller </servlet-name>
          ? <url-pattern>*.do</url-pattern>
          ?</servlet-mapping>
          </web-app>
          初始化參數(shù)利用<init-param>進行配置,配置采用名稱-值對的方式,一個<param-name>對應(yīng)一個<param-value>,初始化參數(shù)可以任意定義,例如host,port,但是有一些在Struts1.1中是具有特別意義的,列舉如下:
          表2-1. Struts1.1中用到的初始化參數(shù)
          參數(shù)名?含義/默認值
          config ?以相對路徑的方式指明Struts應(yīng)用程序的配置文件位置。如不設(shè)置,則默認值為/WEB-INF/struts-config.xml。
          config/sub1 ?以相對路徑的方式指明子應(yīng)用程序的配置文件位置,一般來說,很少用到子應(yīng)用程序,在此不多描述。
          debug ?設(shè)置Servlet的debug級別,控制日志記錄的詳細程度。默認為0,記錄相對最少的日志信息。
          detail ?設(shè)置Digester的debug級別,Digester是Struts框架所使用的用來解析xml配置文件的一個框架,通過該設(shè)置,可以查看不同詳細等級的解析日志。默認為0,記錄相對最少的日志信息。

          4、? 配置標(biāo)簽庫,標(biāo)簽庫是Struts自帶的一些組件庫,采用JSP規(guī)范中Tag-lib的方式供大家使用,正是因為存在這么豐富的標(biāo)簽庫,使得采用Struts的開發(fā)才顯得這么方便,高效。

          ? <web-app>
          ?<servlet>
          ? <servlet-name>controller</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</param-value>
          ? </init-param>
          ? <init-param>
          ?? <param-name>host</param-name>
          ?? <param-value>localhost</param-value>
          ? </init-param>
          ? <init-param>
          ?? <param-name>port</param-name>
          ?? <param-value>7001</param-value>
          ? </init-param>
          ?</servlet>
          ?
          ?<servlet-mapping>
          ? <servlet-name>controller</servlet-name>
          ? <url-pattern>*.do</url-pattern>
          ?</servlet-mapping>
          ?
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
          ?</taglib>
          ?
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
          ?</taglib>
          ?
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
          ?</taglib>
          </web-app>
          標(biāo)簽庫采用<taglib>定義,<taglib>含有兩個子元素,<taglib-uri>和<taglib-location>,<taglib-uri>用戶定義標(biāo)簽庫的唯一表示符,可以理解為名字,以后要在jsp頁面中使用這個標(biāo)簽庫,靠的就是它。<taglib-location>指明標(biāo)簽庫存在的物理路徑,當(dāng)然,和配置文件一樣,也是相對路徑。
          5、? 設(shè)置welcome文件列表(可選步驟)
          <welcome-file-list>
          ?<welcome-file>index.jsp</welcome-file>
          </welcome-file-list>
          6、? 設(shè)置錯誤處理(可選步驟),通常的http訪問異常包含404 Not Found和500 Internal Error,為了提供給用戶更為友好的顯示,可以做如下配置:
          <web-app>
          ?<error-page>
          ? <error-code>404</error-code>
          ? <location>/common/404.jsp</location>
          ?</error-page>
          ?
          ?<error-page>
          ? <error-code>500</error-code>
          ? <location>/common/500.jsp</location>
          ?</error-page>
          </web-app>
          通過如上配置,當(dāng)用戶訪問應(yīng)用中不存在的頁面時,將會將用戶導(dǎo)向到/common/404.jsp頁面。同樣地,當(dāng)出現(xiàn)異常錯誤時,將會把/common/500.jsp顯示給用戶。
          7、? 最后,一個完整的web.xml示例如下:
          <?xml version="1.0" encoding="UTF-8"?>
          ?
          <!DOCTYPE web-app
          ??? PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
          ??? "<web-app>?
          ?<servlet>
          ? <servlet-name>storefront</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</param-value>
          ? </init-param>???
          ? <init-param>
          ?? <param-name>debug</param-name>
          ?? <param-value>3</param-value>
          ? </init-param>
          ? <init-param>
          ?? <param-name>detail</param-name>
          ?? <param-value>3</param-value>
          ? </init-param>
          ? <load-on-startup>1</load-on-startup>
          ?</servlet>
          ?
          ?<servlet-mapping>
          ? <servlet-name>storefront</servlet-name>
          ? <url-pattern>/action/*</url-pattern>
          ?</servlet-mapping>
          ?
          ?<welcome-file-list>
          ? <welcome-file>index.jsp</welcome-file>??
          ?</welcome-file-list>
          ?
          ?<error-page>
          ? <error-code>404</error-code>
          ? <location>/common/404.jsp</location>
          ?</error-page>
          ?<error-page>
          ? <error-code>500</error-code>
          ? <location>/common/500.jsp</location>
          ?</error-page>
          ?
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
          ?</taglib>
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
          ?</taglib>
          ?<taglib>
          ? <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
          ?</taglib>
          </web-app>
          1、? 到此為止,Struts的開發(fā)環(huán)境安裝算是告一段落。
          1.???? Struts框架
          在介紹Struts框架之前,先來看看web開發(fā)的兩種模式,這兩種模式自JSP開發(fā)流行以來,就爭論不斷,它們分別是JSP Model 1和JSP Model 2。
          1.1? JSP Model 1
          下圖是JSP Model 1 的構(gòu)架示意圖:
          ?
          用戶通過瀏覽器之間訪問web應(yīng)用的JSP頁面, JSP提供UI顯示,JavaBeans處理數(shù)據(jù)庫訪問和業(yè)務(wù)邏輯。這種開發(fā)方式最大的優(yōu)勢是直接、簡單,對于小型應(yīng)用,可以很方便、快速地進行開發(fā)。
          1.2? JSP Model 2
          下圖是JSP Model 2 的構(gòu)架示意圖:
          ?
          JSP Model 2 和JSP Model 1 最大的區(qū)別是引入了MVC模式的概念,即M(Model:業(yè)務(wù)邏輯),V(View:系統(tǒng)UI),C(Controller:控制)分離,用戶的所有請求提交給Controller,由Controller進行統(tǒng)一分配,并且采用推的方式將不同的UI顯示給用戶。這樣做得好處是:
          1、? 可以統(tǒng)一控制用戶的行為,例如在Controller中添加統(tǒng)一日志記錄等功能是非常方便的。
          2、? 職責(zé)分離,有利于各部分的維護。用戶不直接訪問分散的UI,這樣可以通過配置文件或則流程定義的方式,在不同的環(huán)節(jié)、時間將不同的頁面推向給用戶。
          ?
          1.3? Struts
          通過了解JSP Model 1和JSP Model 2,我想大家心里都已經(jīng)有了選擇,在這里,我不想說哪一種構(gòu)架更好,在不同的環(huán)境中,使用恰到好處的技術(shù)才是最好的。普遍來說,MVC分離是個不錯的選擇。
          Struts框架正是MVC分離的一個杰出作品。首先我們來看一下Struts1.1的UML圖,以便于我們對Struts有個全局的了解:
          ?
          先不用急著看懂這張圖,在下面的學(xué)習(xí)過程中,我們會慢慢地了解這張圖中各個組件的含義。
          接下來,我們從MVC的角度對Struts框架進行探索。
          1.3.1?????????? Controller
          首先介紹MVC中的C,上面提到了,JSP Model 1 和JSP Model 2 最大的卻別就是C,那么在Struts中,這個C是什么呢?他是如何實現(xiàn)的呢?下面我們再來看看這個圖:
          ?這是JSP Model 2的構(gòu)架圖,也是Struts的構(gòu)架圖,Struts使用一個Servlet作為Controller,處理用戶的請求,并分派給Model進行業(yè)務(wù)處理,在合適的時候?qū)⒑线m的View推向給用戶。這個Servlet是org.apache.struts.action.ActionServlet或其子類。ActionServlet類擴展自javax.servlet.http.HttpServlet類,其職責(zé)是將http請求提交給合適的處理器(Processor)進行處理。關(guān)于處理器我們在稍后會介紹,是org.apache.struts.action.RequestProcessor 或其子類的一個實例。
          1.3.1.1??? Controller(控制器)機制
          J2EE的前端控制器(Front Controller)設(shè)計模式中利用一個前端控制器來接受所有客戶請求,為應(yīng)用提供一個中心控制點,在該控制點上,可以很方便地添加一些全局性的,如加密、國際化、日志等通用操作。Controller的實現(xiàn)機制正是建立在前端控制器的設(shè)計模式基礎(chǔ)上。
          前面我們介紹過,Struts的控制器擁有一些職責(zé),其中最主要的是以下幾個:
          ??????????????? 接收客戶請求。
          ??????????????? 映射請求到指定的業(yè)務(wù)操作。
          ??????????????? 獲取業(yè)務(wù)操作的結(jié)果并以有效的方式提供給客戶。
          ??????????????? 根據(jù)業(yè)務(wù)操作的結(jié)果和當(dāng)前的狀態(tài)把不同的? 推向給客戶。
          在Struts框架中,控制器中不同的組件負責(zé)不同的控制職責(zé),下圖是Struts框架中關(guān)于控制器部分的一個組件圖:

          ?在上圖中,很明顯地可以看出,ActionServlet處于核心位置,那么,我們就先來了解一下ActionServlet。
          1.3.1.2??? ActionServlet類
          org.apache.struts.action.ActionServlet在????? 應(yīng)用程序中扮演接收器的角色,所有客戶端的請求在被其它類處理之前都得通過ActionServlet 的控制。
          當(dāng) ActionServlet的實例接收到一個??? 請求,不管是通過?? 方法或??? 方法,ActionServlet的process( )方法被調(diào)用并用以處理客戶請求。process( )方法實現(xiàn)顯示如下:
          protected void process(HttpServletRequest request,HttpServletResponse response)
          ? throws IOException, ServletException {
          ?
          ? RequestUtils.selectApplication( request, getServletContext(? ) );
          ? getApplicationConfig( request ).getProcessor(? ).process( request, response );
          }
          該方法的實現(xiàn)很簡單,RequestUtils.selectApplication( request, getServletContext(? ) );語句是用來根據(jù)用戶訪問的上下文路徑來選擇處理的應(yīng)用,如果你只有一個Struts配置文件,就表示你只有一個Struts應(yīng)用。關(guān)于如何建立多個Struts應(yīng)用,本教程不作詳細講解,請參考相應(yīng)資料。getApplicationConfig( request ).getProcessor(? ).process( request, response );語句用來獲取一個處理器,并將客戶請求提交給處理器處理。
          1.3.1.3??? Struts初始化處理流程
          根據(jù)在?????? 中配置的初始化參數(shù),?????? 容器將決定在在容器的第一次啟動,或第一次客戶請求ActionServlet的時機加載ActionServlet ,不管哪種方式加載,和其它?????? 一樣,ActionServlet的init( )方法將被調(diào)用,開始初始化過程。讓我們來看看在初始化過程中將發(fā)生些什么,理解了這些,對于我們???? 和擴展自己的應(yīng)用更加得心應(yīng)手。
          ?????????? 初始化框架的內(nèi)部消息綁定,這些消息用來輸出提示,警告,和錯誤信息到日志文件中。org.apache.struts.action.ActionResources用來獲取內(nèi)部消息;
          ?????????? 加載?????? 中定義的不同參數(shù),用以控制ActionServlet的不同行為,這些參數(shù)包括config? debug? detail????? convertNull ;
          ?????????? 加載并初始化?????? 中定義的??????? 名稱和?????? 映射信息。通過初始化,框架的各種?? 被注冊,?? 用來在下一步校驗配置文件的有效性;
          4、??????? 為默認應(yīng)用加載并初始化????? 配置文件,配置文件即初始化參數(shù)config指定的文件。默認配置文件被解析,產(chǎn)生一個ApplicationConfig對象存于ServletContext中。可以通過關(guān)鍵字org.apache.struts.action.APPLICATION從ServletContext中獲取ApplicationConfig;
          ???????????????? 配置文件中指定的每一個消息資源都被加載,初始化,并存在ServletContext的合適區(qū)域 基于每個message-resources元素的key屬性 ,如果key屬性沒有設(shè)置,則為org.apache.struts.action.MESSAGE;
          ???????????????? 配置文件中聲明的每一個數(shù)據(jù)源被加載并且初始化,如果沒有配置數(shù)據(jù)源,這一步跳過;
          ?????????? 加載并初始化????? 配置文件中指定的插件。每一個插件的init()方法被調(diào)用;
          ?????????? 當(dāng)默認應(yīng)用加載完成,init()方法判斷是否有應(yīng)用模塊需要加載,如果有,重復(fù)步驟 - 萬成應(yīng)用模塊的加載。
          下圖是對上面文字說明的圖形化表示:
          ?


          RequestProcessor類
          前面提到過,當(dāng)ActionServlet接收到客戶請求后,會進行一連串的初始化操作,然后,就會將客戶請求轉(zhuǎn)交給合適的處理器進行處理,這個合適的處理器就是org.apache.struts.action.RequestProcessor或其子類的一個實例(根據(jù)Struts配置文件中的配置)。提供了默認實現(xiàn),如果需要自定義這些行為,可以重載這個類定義自己的處理行為,當(dāng)你想要自定義操作時,Struts推薦你重載這個類而不是ActionServlet。
          下面的代碼片斷提供了RequestProcessor的默認行為實現(xiàn)代碼:
          public void process(HttpServletRequest request, HttpServletResponse response)
          ? throws IOException, ServletException {
          ?
          ??? // Wrap multipart requests with a special wrapper
          ??? request = processMultipart(request);
          ?
          ??? // Identify the path component we will use to select a mapping
          ??? String path = processPath(request, response);
          ??? if (path == null) {
          ????? return;
          ??? }
          ??? if (log.isInfoEnabled(? )) {
          ????? log.info("Processing a '" + request.getMethod(? ) +
          ??????? "' for path '" + path + "'");
          ??? }
          ?
          ??? // Select a Locale for the current user if requested
          ??? processLocale(request, response);
          ?
          ??? // Set the content type and no-caching headers if requested
          ??? processContent(request, response);
          ??? processNoCache(request, response);
          ?
          ??? // General-purpose preprocessing hook
          ??? if (!processPreprocess(request, response)) {
          ????? return;
          ??? }
          ?
          ??? // Identify the mapping for this request
          ??? ActionMapping mapping = processMapping(request, response, path);
          ??? if (mapping == null) {
          ????? return;
          ??? }
          ?
          ??? // Check for any role required to perform this action
          ??? if (!processRoles(request, response, mapping)) {
          ????? return;
          ??? }
          ?
          ??? // Process any ActionForm bean related to this request
          ??? ActionForm form = processActionForm(request, response, mapping);
          ??? processPopulate(request, response, form, mapping);
          ??? if (!processValidate(request, response, form, mapping)) {
          ????? return;
          ??? }
          ?
          ??? // Process a forward or include specified by this mapping
          ??? if (!processForward(request, response, mapping)) {
          ????? return;
          ??? }
          ??? if (!processInclude(request, response, mapping)) {
          ????? return;
          ??? }
          ?
          ??? // Create or acquire the Action instance to process this request
          ??? Action action = processActionCreate(request, response, mapping);
          ??? if (action == null) {
          ????? return;
          ??? }
          ?
          ??? // Call the Action instance itself
          ??? ActionForward forward =
          ????? processActionPerform(request, response, action, form, mapping);
          ?
          ??? // Process the returned ActionForward instance
          ??? processActionForward(request, response, forward);
          }

          ?


          接下來,讓我們一步一步地了解process()方法到底做了什么。
          1、??????????? 調(diào)用processMultipart( )方法。如果HttpServletRequest是POST方式,且請求為multipart/form-data ,Struts框架將請求對象包裝成處理multipart 請求專用的請求對象,否則,只是簡單地返回原有的請求對象。一般來說,除非需要處理文件上傳,否則不用關(guān)心multipart 功能的具體細節(jié)。
          2、??????????? 調(diào)用processPath( ) 方法,該方法用來從請求URL中獲應(yīng)用取路徑部分。獲取到的信息在稍后的步驟中用于選擇合適的Struts Action調(diào)用。
          3、??????????? 調(diào)用processLocale( ) 方法處理一些國際化的事務(wù)。
          4、?????????? 調(diào)用方法來決定processContent( )請求的content type編碼(encoding)方式。content type可以配合在配置文件中,也可以在jsp文件中配置,默認為text/html。
          5、?????????? 根據(jù)noCache屬性的設(shè)置調(diào)用processNoCache( ) 方法,如果noCache設(shè)置為true。則添加合適的響應(yīng)頭到響應(yīng)對象中,使得頁面保留在瀏覽器的Cache中。這些響應(yīng)頭包含Pragma, Cache-Control, 和Expires 。
          6、??????????? 調(diào)用processPreprocess( )方法,這個方法在這兒設(shè)置一個鉤子,方法的默認實現(xiàn)只是簡單地返回true,這樣給了自定義處理器的開發(fā)者提供了一個合適的地方讓你添加自己的業(yè)務(wù)邏輯。因為這個方法在調(diào)用Action之前被調(diào)用,如果你重載這個方法,只需要返回false,則Action就不會被調(diào)用。例如,你可以重載這個方法用戶檢查客戶session,如果不通過就返回false。
          7、??????????? 調(diào)用processMapping( )方法,根據(jù)客戶請求信息中的path信息來決定是否返回ActionMapping對象實例。如果不能夠找到path的映射,則客戶將會得到一個error響應(yīng)。
          8、??????????? 通過調(diào)用processRoles( )方法檢查是否為Action配置了安全角色。如果配置了角色要求,則請求對象的isUserInRole( )方法被調(diào)用,如果用戶屬于這些角色,則客戶會得到顯示一個error響應(yīng)。
          9、??????????? 調(diào)用processActionForm( )方法檢查是否存在為ActionMapping配置的ActionForm 。如果存在,則在有效區(qū)域內(nèi)查找是否存在該ActionForm的實例,存在,則復(fù)用,不存在,則創(chuàng)建一個實例。然后將實例保存與再配置文件中配置好的有效區(qū)域(request,session,application)內(nèi),并用Action元素的name屬性作為該實例的關(guān)鍵字。
          10、?????? 調(diào)用processPopulate( )方法,如果存來存在為ActionMapping配置的ActionForm,則封裝請求對象中的數(shù)據(jù)到ActionForm中,在進行封裝之前,先調(diào)用ActionForm的reset( )方法進行屬性值的默認化。
          11、???????? 調(diào)用processValidate( )方法。如果ActionForm被配置好,并且action元素的屬性validate被設(shè)置為true ,則進一步調(diào)用validate( )方法進行規(guī)則校驗。如果validate( )方法校驗失敗,就會保存一個ActionErrors對象到請求區(qū)域中,請求將會自動重定向到action映射的input屬性所指定的頁面中。如果校驗通過或在action映射中沒有配置ActionForm,則繼續(xù)處理請求。
          12、???????? 根據(jù)action映射是否配置了forward屬性或include屬性來決定下一步操作。如果配置了任意一個,則相應(yīng)地調(diào)用RequestDispatcher對象的forward( )方法或include( )方法,調(diào)用后,對客戶請求的處理結(jié)束。否則,繼續(xù)處理請求。
          13、???????? 調(diào)用processActionCreate( )方法創(chuàng)建或獲取一個Action對象實例處理請求。processActionCreate( )方法會在緩存中查找是否存在已經(jīng)創(chuàng)建好的Action實例,如果存在,則復(fù)用,否則,則重新創(chuàng)建并將其村于緩存中。
          14、?????? 調(diào)用processActionPerform( )方法,該方法用于在一個try/catch代碼塊中調(diào)用action實例的execute( )方法,這樣確保action的execute( )方法一旦發(fā)生執(zhí)行異常能夠被RequestProcessor捕獲。
          15、?????? 調(diào)用processActionForward( )方法,并傳入action的execute( )方法所返回的ActionForward對象實例,方法通過檢查ActionForward對象實例,決定采用redirect或forword方式進行重定向。究竟采用redirect還是forword取決于forward元素的redirect屬性值。
          擴展RequestProcessor
          如果不想利用Struts提供的處理器,則可以擴展它。通過兩個步驟即可實現(xiàn):
          1、? 創(chuàng)建一個新的類,該類必須是org.apache.struts.action.RequestProcessor的子類;
          2、? 在Struts配置文件中進行聲明,例如:(粗體部分為你的自定義處理器類)
          <controller
          ? contentType="text/html;charset=UTF-8"
          ? debug="3"
          ? locale="true"
          ? nocache="true"
          ? processorClass="com.struts.framework.CustomRequestProcessor"/>

          1.1.1.1??? Action類
          如果說ActionServlet是Struts框架的入口,RequestProcessor是消化過濾系統(tǒng),則org.apache.struts.action.Action類可以說是整個框架的心臟。他是客戶請求和業(yè)務(wù)操作的連接橋,也可以將其看作是業(yè)務(wù)操作的客戶代理。
          在前面對ReqeustProcessor類的學(xué)習(xí)中,我們了解到一旦確定并得到了一個action實例,ReqeustProcessor會調(diào)用action的execute()方法處理客戶請求,你需要擴展action類,并實現(xiàn)它的execute()方法,在此方法中添加你自己的處理代碼。下面給出是一個示例,這個action用來處理用戶的登錄請求:
          package com.oreilly.struts.storefront.security;
          ?
          import java.util.Locale;
          import javax.servlet.http.*;
          import org.apache.struts.action.*;
          import com.oreilly.struts.storefront.customer.view.UserView;
          import com.oreilly.struts.storefront.framework.exceptions.BaseException;
          import com.oreilly.struts.storefront.framework.UserContainer;
          import com.oreilly.struts.storefront.framework.StorefrontBaseAction;
          import com.oreilly.struts.storefront.framework.util.IConstants;
          import com.oreilly.struts.storefront.service.IStorefrontService;
          ?
          /**
          ?* Implements the logic to authenticate a user for the Storefront application.
          ?*/
          public class LoginAction extends StorefrontBaseAction {
          ? /**
          ?? * Called by the controller when the user attempts to log in to the
          ?? * Storefront application.
          ?? */
          ? public ActionForward execute( ActionMapping mapping,
          ??????????????????????????????? ActionForm form,
          ??????????????????????????????? HttpServletRequest request,
          ??????????????????????????????? HttpServletResponse response )
          ? throws Exception{
          ?
          ??? // The email and password should have already been validated by the ActionForm
          ??? String email = ((LoginForm)form).getEmail(? );
          ??? String password = ((LoginForm)form).getPassword(? );
          ?
          ??? // Log in through the security service
          ??? IStorefrontService serviceImpl = getStorefrontService(? );
          ??? UserView userView = serviceImpl.authenticate(email, password);
          ?
          ??? // Create a single container object to store user data
          ??? UserContainer existingContainer = null;
          ??? HttpSession session = request.getSession(false);
          ??? if ( session != null ){
          ????? existingContainer = getUserContainer(request);
          ????? session.invalidate(? );
          ??? }else{
          ????? existingContainer = new UserContainer(? );
          ??? }
          ?
          ??? // Create a new session for the user
          ??? session = request.getSession(true);
          ?
          ??? // Store the UserView in the container and store the container in the session
          ??? existingContainer.setUserView(userView);
          ??? session.setAttribute(IConstants.USER_CONTAINER_KEY, existingContainer);
          ?
          ??? // Return a Success forward
          ??? return mapping.findForward(IConstants.SUCCESS_KEY);
          ? }
          }
          ?
          1.1.1.1.1????? Action類緩沖
          Action類被設(shè)計為線程安全的,在每個應(yīng)用中每個Action類只會被實例化一次,供所有線程共享。RequestProcessor利用一個HashMap用來保存Action實例。
          思考題?
          所有線程共享一個Action類實例意味著什么?我們在編程中需要注意些什么呢?
          ?
          1.1.1.2??? ActionForward類
          從前面的介紹我們已經(jīng)了解到,Action的execute( )方法返回一個ActionForward對象。ActionForward對象是JSP頁面、Java servlet等web資源的抽象表現(xiàn)。
          ActionForward的用途是為了減少應(yīng)用和物理資源(JSP頁面,Java servlet)的耦合,物理資源只需要在配置文件中指定(利用name,path屬性和forward元素的redirect屬性),而不是在代碼中指定。RequestDispatcher利用ActionForward來執(zhí)行重定向操作。
          要在Action中返回一個ActionForward對象,你可以動態(tài)地創(chuàng)建一個ActionForward 對象,不過更為通用的解決方案是,通過在Struts配置文件中進行action映射,然后通過關(guān)鍵字去查找一個ActionForward 。下面是代碼示例:
          ? return mapping.findForward( "Success" );
          上面的代碼中,"Success"作為參數(shù)被傳遞到ActionMapping的findFoward( )方法中,findFoward( )方法在Struts配置文件的global-forwards區(qū)域,以及被調(diào)用的action的forward元素中查找名字和"Success"相匹配的元素。下面是action元素中的forward示例:
          <action
          ?? input="/security/signin.jsp"
          ?? name="loginForm"
          ?? path="/signin"
          ?? scope="request"
          ?? type="com.oreilly.struts.storefront.security.LoginAction"
          ?? validate="true">
          ?? <forward name="Success" path="/index.jsp" redirect="true"/>
          ?? <forward name="Failure" path="/security/signin.jsp" redirect="true"/>
          ?</action>

          1.1.1.1??? Action和業(yè)務(wù)邏輯
          思考題?
          Action屬于MVC中的Controller還是Model?為什么?
          ?
          1.1.1.2??? 使用Struts內(nèi)置的Action
          Struts1.1框架的org.apache.struts.actions包中包含了5個內(nèi)置的Action,用來執(zhí)行一些通用的操作,你可以把它們用在你的項目中,以節(jié)省你的開發(fā)時間。接下來我們分別介紹這5個內(nèi)置的Action。
          1.1.1.2.1????? org.apache.struts.actions.ForwardAction類
          很多情況下,你僅僅需要引導(dǎo)客戶從一個JSP頁面跳轉(zhuǎn)到另外一個JSP頁面,按照我們通常的做法,可以做一個鏈接讓用戶直接訪問要跳轉(zhuǎn)到的頁面。但是MVC模式不推薦你這么做,因為,Controller的職責(zé)就是接收所有的客戶請求,然后將客戶請求提交給一個合適的模塊進行處理,并將合適的UI推給用戶,如果直接方式JSP頁面,則跳過了Controller的控制,則無法享受Controller所提供的優(yōu)點。為了解決這個問題,并且不用你去為了執(zhí)行一個簡單的重定向操作而創(chuàng)建一個Action類 ,Struts框架提供了ForwardAction類,這個Action只是簡單地執(zhí)行一個重定向操作,重定向的目的地通過parameter屬性配置。要使用ForwardAction類,只需要在Struts配置文件中將Action的type屬性配置為org.apache.struts.actions.ForwardAction:
          <action
          ? input="/index.jsp"
          ? name="loginForm"
          ? path="/viewsignin"
          ? parameter="/security/signin.jsp"
          ? scope="request"
          ? type="org.apache.struts.actions.ForwardAction"
          ? validate="false"/>
          </action>
          當(dāng)你訪問/viewsignin的時候,就會自動重定向到/security/signin.jsp。
          1.1.1.2.2????? org.apache.struts.actions.IncludeAction類
          暫略
          1.1.1.2.3????? org.apache.struts.actions.DispatchAction類
          暫略
          1.1.1.2.4????? org.apache.struts.actions.LookupDispatchAction類
          暫略
          1.1.1.2.5????? org.apache.struts.actions.SwitchAction類
          暫略
          1.1.2?????????? Model
          Struts沒有定義具體的Model層的實現(xiàn),Model層通常是和業(yè)務(wù)邏輯緊密相關(guān)的,還通常有持續(xù)化的要求,Struts目前沒有考慮到這一層,但是,不管在開源世界還是商業(yè)領(lǐng)域,都有一些都別優(yōu)秀的工具可以為Model層次的開發(fā)提供便利,例如優(yōu)秀的O/R Mapping開源框架Hibernate。
          1.1.3?????????? View
          通常,Web應(yīng)用的UI由以下文件組成:
          ????????? HTML
          ????????? JSP
          而JSP中通常包含以下組件:
          ????????? 自定義標(biāo)簽
          ????????? DTO(Data Transfer Object數(shù)據(jù)傳輸對象)
          在Struts中,還包含了以下兩種常用的組件:
          ????????? Struts ActionForms
          ????????? 資源綁定(java resource bundles),例如將標(biāo)簽的顯示內(nèi)容,錯誤提示的內(nèi)容通過配置文件來配置,這樣可以為實現(xiàn)國際化提供基礎(chǔ)。
          由此可見,Struts對于傳統(tǒng)的Web UI所作的擴充就是Struts ActionForms和資源綁定,接下來對其進行進一步描述。
          1.1.3.1??? 使用 Struts ActionForm
          在Struts框架中,ActionForm負責(zé)在用戶和業(yè)務(wù)邏輯層之間來回地傳遞用戶輸入的數(shù)據(jù)??蚣軙詣邮占脩糨斎氩⒁詅orm bean的方式將這些數(shù)據(jù)傳遞給Action,然后,form bean可以被傳遞到業(yè)務(wù)層。不過,為了減少表示層和業(yè)務(wù)層的耦合,不建議將ActionForm 直接傳遞給業(yè)務(wù)層,而建議代之為DTO。即在Action中利用form bean的數(shù)據(jù)創(chuàng)建合適的DTO,然后傳遞給業(yè)務(wù)層。下面的步驟描述了Struts框架在每一次請求中,是如何處理ActionForm的:
          1、???? 檢查是否已經(jīng)配置ActionForm映射到Action;
          2、???? 如果某一個ActionForm被映射到Action,利用配置文件中action元素的name屬性查找相匹配的ActionForm配置信息;
          3、???? 檢查是否已經(jīng)存在該ActionForm的實例(instance);
          4、???? 如果存在該ActionForm的實例,并且符合當(dāng)前請求的需要,則重用這個實例;
          5、???? 否則,創(chuàng)建該ActionForm的實例,并且將其保存在合適的生存區(qū)域中(生存區(qū)域 (scope)的設(shè)置請查看action元素,scope表示該實例的生存期限,一般來說,有request,session,application等幾種);
          6、???? 調(diào)用ActionForm實例的reset()方法;
          7、???? 遍歷請求參數(shù),根據(jù)不同的參數(shù)名,調(diào)用ActionForm實例和參數(shù)名相對應(yīng)的setter方法,設(shè)置參數(shù)值到ActionForm實例中;
          8、? 最后,如果validate屬性設(shè)置為true,則調(diào)用ActionForm實例的validate()方法,該方法可以返回任何錯誤,主要為校驗錯誤。
          對于每一個需要傳遞form數(shù)據(jù)的HTML頁面,必須使用一個ActionForm,同一個ActionForm可以被多個不同的頁面使用,只要HTMLFORM域和ActionForm的屬性相匹配即可。
          下面是一個ActionForm的示例:
          package com.oreilly.struts.banking.form;
          ?
          import javax.servlet.http.HttpServletRequest;
          import org.apache.struts.action.Action;
          import org.apache.struts.action.ActionError;
          import org.apache.struts.action.ActionErrors;
          import org.apache.struts.action.ActionForm;
          import org.apache.struts.action.ActionMapping;
          import org.apache.struts.util.MessageResources;
          /**
          ?* This ActionForm is used by the online banking appliation to validate
          ?* that the user has entered an accessNumber and a pinNumber. If one or
          ?* both of the fields are empty when validate( ) is called by the
          ?* ActionServlet, error messages are created.
          ?*/
          public class LoginForm extends ActionForm {
          ? // The user's private ID number
          ? private String pinNumber;
          ? // The user's access number
          ? private String accessNumber;
          ?
          ? public LoginForm(? ) {
          ??? super(? );
          ??? resetFields(? );
          ? }
          ? /**
          ?? * Called by the framework to validate the user has entered values in the
          ?? * accessNumber and pinNumber fields.
          ?? */
          ? public ActionErrors validate(ActionMapping mapping, HttpServletRequest req ){
          ??? ActionErrors errors = new ActionErrors(? );
          ?
          ??? // Get access to the message resources for this application.
          ??? // There's no easy way to access the resources from an ActionForm.
          ??? MessageResources resources =
          ????? (MessageResources)req.getAttribute( Action.MESSAGES_KEY );
          ?
          ??? // Check and see if the access number is missing.
          ??? if(accessNumber == null || accessNumber.length(? ) == 0) {
          ????? String accessNumberLabel = resources.getMessage( "label.accessnumber" );
          ????? ActionError newError =
          ??????? new ActionError("global.error.login.requiredfield", accessNumberLabel );
          ????? errors.add(ActionErrors.GLOBAL_ERROR, newError);
          ??? }
          ?
          ??? // Check and see if the pin number is missing.
          ??? if(pinNumber == null || pinNumber.length(? ) == 0) {
          ????? String pinNumberLabel = resources.getMessage( "label.pinnumber" );
          ????? ActionError newError =
          ??????? new ActionError("global.error.login.requiredfield", pinNumberLabel );
          ????? errors.add(ActionErrors.GLOBAL_ERROR, newError);
          ??? }
          ??? // Return the ActionErrors, if any.
          ??? return errors;
          ? }
          ?
          ? /**
          ?? * Called by the framework to reset the fields back to their default values.
          ?? */
          ? public void reset(ActionMapping mapping, HttpServletRequest request) {
          ??? // Clear out the accessNumber and pinNumber fields.
          ??? resetFields(? );
          ? }
          ? /**
          ?? * Reset the fields back to their defaults.
          ?? */
          ? protected void resetFields(? ) {
          ??? this.accessNumber = "";
          ??? this.pinNumber = "";
          ? }
          ?
          ? public void setAccessNumber(String nbr) {
          ??? this.accessNumber = nbr;
          ? }
          ?
          ? public String getAccessNumber(? ) {
          ??? return this.accessNumber;
          ? }
          ?
          ? public String getPinNumber(? ) {
          ??? return this.pinNumber;
          ? }
          ? public void setPinNumber(String nbr) {
          ??? this.pinNumber = nbr;
          ? }
          }
          Struts框架提供的ActionForm實現(xiàn)了一些方法,到現(xiàn)在為止,最重要的兩個方法是reset()和validator():
          public void reset( ActionMapping mapping, HttpServletRequest request );
          public ActionErrors validate( ActionMapping mapping, HttpServletRequest request );
          ?
          ActionForm對于這兩個方法的默認實現(xiàn)是不執(zhí)行任何操作,你可以重載這兩個方法來執(zhí)行具體的邏輯。
          當(dāng)寫好了ActionForm類之后,需要通知Struts應(yīng)用程序它的存在,以及action和ActionForm之間的映射關(guān)系。在Struts中,是通過配置文件來實現(xiàn)這一目的的。第一步,將應(yīng)用所需要用到的所有ActionForm在配置文件的form-beans這一段加以描述,下面的片斷描述了如何通知Struts應(yīng)用程序這三個ActionForm的存在。
          <form-beans>
          ?<form-bean
          ?? name="loginForm"
          ?? type="com.oreilly.struts.banking.form.LoginForm"/>?
          ?<form-bean
          ?? name="accountInformationForm"
          ?? type="org.apache.struts.action.DynaActionForm">
          ?? <form-property name="accounts" type="java.util.ArrayList"/>
          ?</form-bean>?
          ?<form-bean
          ?? name="accountDetailForm"
          ?? type="org.apache.struts.action.DynaActionForm">
          ?? <form-property
          ???? name="view"
          ???? type="com.oreilly.struts.banking.view.AccountDetailView"/>
          ?</form-bean>???
          </form-beans>
          每一個form bean的name屬性必須唯一,type屬性定義了該form bean的類,該類必須實現(xiàn)Struts ActionForm類。下一步就是建立action和form-bean的聯(lián)系,form-bean可以和一到多個action建立聯(lián)系,通過在action元素的屬性中引用form-bean的name即可完成映射,下面的片斷顯示了LoginAction和form-bean的映射,我們之前已經(jīng)看過這個片段:
          <action
          ? path="/login"
          ? type="com.oreilly.struts.banking.action.LoginAction"
          ? scope="request"
          ? name="loginForm"
          ? validate="true"
          ? input="/login.jsp">
          ? <forward name="Success" path="/action/getaccountinformation" redirect="true"/>
          ? <forward name="Failure" path="/login.jsp" redirect="true"/>
          </action>
          ?
          在Struts1.1中,添加了一種新類型的action form ,叫做org.apache.struts.action.DynaActionForm,這種類型的action form可以配置為action的映射,它會自動處理HTML form中的數(shù)據(jù)并將其傳遞到Action。DynaActionForm 如何做到自動處理HTML form數(shù)據(jù)的呢?DynaActionForm內(nèi)部使用一個Map來存放HTML field數(shù)據(jù)。
          在接下來的一節(jié)中,我們詳細了解一下DynaActionForm。
          1.1.1.1??? 使用DynaActionForm
          從上一節(jié)的介紹,我們可以看出,使用ActionForm 和我們自己來編寫類獲取HTML from值,在進行處理相比,有不少優(yōu)勢。ActionForm所封裝的數(shù)據(jù)和行為時幾乎每一個web 應(yīng)用程序都需要的,而且在一個應(yīng)用中會多次用到,例如一個信息實體的增加和修改,可能從不同的角度,不同的頁面實現(xiàn)信息實體的增、改,通過ActionForm就可以復(fù)用,復(fù)用可以統(tǒng)一規(guī)則,減少開發(fā)時間和維護工作量。但是,現(xiàn)在對ActionForm的使用越來越少,為什么呢?
          第一,?????????? 也是一個最大的問題,會使得項目中存在很多ActionForm類,增加了整個項目類的數(shù)目和維護復(fù)雜度,有的開發(fā)人員為了避開這個問題,使用一個很大的,包含所有HTML from屬性的ActionForm 來和所有action映射,這種方式我認為問題更多,完全失去了封裝的味道。
          第二,?????????? 當(dāng)需要添加或者刪除一個HTML from 屬性時,如果ActionForm 需要用到這些屬性,就得修改ActionForm ,并且要重新編譯。
          基于這些原因,在Struts1.1框架中,添加了一種新類型的ActionForm,這種ActionForm可以動態(tài)變化從而避免創(chuàng)建具體的ActionForm類。這種ActionForm的基類是org.apache.struts.action.DynaActionForm,當(dāng)然,DynaActionForm是從ActionForm擴展而來的。對于應(yīng)用來說,DynaActionForm和ActionForm在以下三個方面會有些不同:
          ????????? ActionForm的屬性定義
          ????????? validate()方法
          ????????? reset()方法
          DynaActionForm的屬性不同于ActionForm,ActionForm的屬性是通過具體的類,具體的setter,getter方法來進行屬性值的設(shè)置,獲取,而DynaActionForm是在Struts的配置文件中定義的。
          對reset()方法調(diào)用的時機和ActionForm并無不同,只是相對來說,在reset()方法被調(diào)用的時候,你擁有比較少的控制權(quán)。當(dāng)然,可以通過擴展DynaActionForm,重載reset()方法。
          對于從UI端輸入的數(shù)據(jù)的校驗,相對來說有些復(fù)雜,它是通過Struts Validator組件來實現(xiàn)的,稍后會詳細介紹它。
          1.1.1.1.1????? 配置DynaActionForm
          要使用DynaActionForm,首先得在Struts配置文件中添加form-bean元素。在配置文件中,DynaActionForm和ActionForm的不同之處在于,DynaActionForm需要添加一些form-property元素,form-property用來指定HTML form中的field名字,Struts框架會通過這些名字的匹配,自動將HTML form 各個field的值封裝到DynaActionForm實例中。下面的片斷是關(guān)于DynaActionForm的配置文件示例 :
          <form-beans>
          ? <form-bean
          ??? name="loginForm"
          ??? type="org.apache.struts.action.DynaActionForm">
          ?
          ??? <!-在下面制定Form的屬性 -->
          ??? <form-property
          ????? name="email"
          ????? type="java.lang.String "/>
          ??? <form-property
          ????? name="password"
          ????? type="java.lang.String "/>
          ?
          ??? <!-可以為屬性設(shè)置默認值 -->
          ??? <form-property
          ????? initial="false"
          ????? name="rememberMe"
          ????? type="java.lang.Boolean "/>
          ? </form-bean>
          <form-beans>
          當(dāng)你HTML form中添加了一個屬性,需要在DynaActionForm中添加一個屬性時,就不需要去修改具體的ActionForm類,只需要在配置文件中添加一個form-property元素即可,大大提高了可擴展能力。
          前面我們已經(jīng)了解到,ActionForm的reset()方法默認不進行任何操作,在DynaActionForm中,reset()方法默認將所有屬性設(shè)置為默認值,如果在配置文件中沒有為該屬性設(shè)置默認值,將會按照java編程語言的規(guī)范根據(jù)屬性的類型為其進行初始化,例如:數(shù)字(int ,double,float)的將會初始化為0,Ojbect類型將為初始化為null。
          注意:在配置文件中定義的form-property的type屬性,其值為一個java類名,因此對于java語言中的主類型,如ini,long必須定義為java.lang.Int,java.lang.Long,其它主類型依次類推。
          1.1.1.1.1????? 使用DynaActionForm執(zhí)行校驗規(guī)則
          ?同ActionForm一樣,DynaActionForm也沒有提供validate()方法的默認操作,幸運的是,Struts提供了另外一種框架來幫助大家解決校驗的問題,這就是Struts Validator框架。Struts Validator 框架由David Winterfeldt編寫,現(xiàn)在已經(jīng)成為Struts主分發(fā)的一部分,它提供基于規(guī)則的校驗,對于常用的校驗,如必填項目,email,電話等等提供了現(xiàn)成的規(guī)則,只需要通過配置文件進行配置即可。關(guān)于Struts Validator框架的詳細介紹,見后續(xù)章節(jié)。
          1.1.1.2???? Validator 框架
          Struts允許在ActionForm的validator()方法中添加校驗代碼,對用戶輸入的數(shù)據(jù)進行規(guī)則校驗,這能很好地工作,但是,這存在一些限制,舉個簡單的例子,一個必填項現(xiàn)在不是必填項了,要滿足這個簡單的需求就需要更改ActionForm類的validator()方法,再進行重新編譯,很麻煩。本節(jié)我們來學(xué)習(xí)Validator框架,看它是如何解決校驗問題的。
          1.1.1.2.1????? Validator的安裝、配置
          Validator目前是Jakarta Commons 項目的一部分,它也被包含在Struts主分發(fā)里面,可以直接使用Struts中自帶的Validator庫,也可以去網(wǎng)站上下載
          http://jakarta.apache.org/commons/。
          Validator需要一些其它庫的支持,例如Jakarta ORO,不過沒關(guān)系,Struts分發(fā)包里面都包含了,你只需要按照第2章介紹的將Struts安裝到你的應(yīng)用中,就一切ok。
          1.1.1.2.1.1??????????? 配置校驗規(guī)則
          前面提到過,Validator是通過校驗規(guī)則來實施校驗,這些校驗規(guī)則被配置在配置文件中,這意味著不需要修改源代碼就可以方便地更改校驗規(guī)則,是不是感覺很不錯?Validator所需要的配置文件有兩個:validation-rules.xml和validation.xml。
          1.1.1.2.1.2??????????? validation-rules.xml
          在validation-rules.xml文件中配置了一些全局性的校驗規(guī)則,使得你在應(yīng)用程序中使用校驗而不用關(guān)注實現(xiàn)細節(jié)。這個配置文件是Validator框架自帶的,可以用在所有Struts應(yīng)用中。它默認配置了許多很常用的規(guī)則,一般來說,不用去更改它,除非需要擴展或修改這些默認的校驗規(guī)則。
          建議:即使你需要擴展一些規(guī)則,也不要去修改validation-rules.xml,而是通過新的配置文件去定義你所擴展的校驗規(guī)則。
          validator-rules_1_1.dtd定義了validation-rules.xml文件的結(jié)構(gòu),根元素是form-validation,它包含一到多個global元素,global元素包含一到多個validator元素。
          每一個validator元素定義了一個唯一的校驗規(guī)則。下面是validation-rules.xml文件中的一個片斷,用來定義必填項(required)校驗規(guī)則:
          <validator
          ? name="required"
          ? classname="org.apache.struts.util.StrutsValidator"
          ? method="validateRequired"
          ? methodParams="java.lang.Object,
          ??? org.apache.commons.validator.ValidatorAction,
          ??? org.apache.commons.validator.Field,
          ??? org.apache.struts.action.ActionErrors,
          ??? javax.servlet.http.HttpServletRequest"
          ? msg="errors.required">
          </validator>
          下表詳細介紹了validator元素每個屬性的具體含義:
          序號?屬性?解釋
          1.??????? ?name?賦予校驗規(guī)則一個唯一的名稱,便于在validation-rules.xml文件和應(yīng)用指定的其它校驗文件中引用。
          2.??????? ?classname?指定含有具體校驗規(guī)則Java Class名,org.apache.struts.util.StrutsValidator是Validator框架自帶的一個Java Class,它實現(xiàn)了一些很常用的校驗規(guī)則。
          3.??????? ?method?指定含有具體校驗規(guī)則Java Class的具體方法,一個校驗規(guī)則有實現(xiàn)校驗的Java Class的一個方法來實現(xiàn)。
          4.??????? ?methodParams?聲明method屬性所指定的方法的參數(shù),參數(shù)之間用逗號分隔。
          5.??????? ?msg?msg是用來指定當(dāng)校驗不通過時,Validator框架所給出的提示信息。它的值是應(yīng)用所配置的資源文件中的一個關(guān)鍵字,當(dāng)校驗失敗時,Validator框架利用msg所指定的值到應(yīng)用配置的資源文件中去查找匹配記錄。Validator框架默認使用以下提示信息:
          ?? errors.required={0} is required.
          ?? errors.minlength={0} cannot be less than {1} characters.
          ?? errors.maxlength={0} cannot be greater than {1} characters.
          ?? errors.invalid={0} is invalid.??
          ?? errors.byte={0} must be a byte.
          ?? errors.short={0} must be a short.
          ?? errors.integer={0} must be an integer.
          ?? errors.long={0} must be a long.
          ?? errors.float={0} must be a float.
          ?? errors.double={0} must be a double.??
          ?? errors.date={0} is not a date.
          ?? errors.range={0} is not in the range {1} through {2}.
          ?? errors.creditcard={0} is not a valid credit card number.
          ?? errors.email={0} is an invalid email address
          可以將上面的這些信息添加到你的Struts應(yīng)用所配置的資源文件(例如:ApplicationResources.properties)中,也可以修改這些值之后,將其添加到配置文件中,示例如下:
          ?errors.required={0} 是必填項。
          6.??????? ?depends?depends指定在本校驗規(guī)則的前置校驗規(guī)則,下面的片斷定義了一個最小長度的校驗規(guī)則,含義是在進行最小長度校驗之前,會先調(diào)用required校驗規(guī)則確保數(shù)據(jù)不為空:
          <validator
          ? name="minLength"
          ? classname="org.apache.struts.util.StrutsValidator"
          ? method="validateMinLength"
          ? methodParams="java.lang.Object,
          ??? org.apache.commons.validator.ValidatorAction,
          ??? org.apache.commons.validator.Field,
          ??? org.apache.struts.action.ActionErrors,
          ??? javax.servlet.http.HttpServletRequest"
          ? depends="required"
          ? msg="errors.minlength">
          </validator>
          如果存在多個前置校驗規(guī)則,則可以用以下的方式進行聲明,各校驗規(guī)則之間用逗號分隔:
          depends="required,integer"
          如果前置校驗規(guī)則失敗,則后續(xù)的校驗規(guī)則不會被執(zhí)行。
          7.??????? ?jsFunctionName?可選屬性。用來指定JavaScript函數(shù)的名字。
          The final attribute supported by the validator element is the jsFunctionName attribute. This optional attribute allows you to specify the name of the JavaScript function. By default, the Validator action name is used.
          ?
          前面已經(jīng)介紹了,org.apache.struts.util.StrutsValidator是Validator框架自帶的一個校驗規(guī)則類,其實現(xiàn)了一些常用的校驗規(guī)則,其包含的校驗方法(method)如下所列:
          ?"?????????? validateByte? 檢查值能夠安全地轉(zhuǎn)換為byte
          "???????? validateCreditCard? 檢查值是一個有效的信用卡號碼
          "???????? validateDate 檢查值是一個有效的日期
          "???????? validateDouble檢查值能夠安全地轉(zhuǎn)換為double
          "???????? validateEmail? 檢查值是一個有效的Email地址
          "???????? validateFloat? 檢查值能夠安全地轉(zhuǎn)換為double
          "???????? validateInteger? 檢查值能夠安全地轉(zhuǎn)換為int
          "???????? validateLong檢查值能夠安全地轉(zhuǎn)換為long
          "???????? validateMask檢查值符合掩碼規(guī)則,掩碼采用規(guī)則表達式的方式
          "???????? validateMinLength 檢查值的長度大于等于指定長度
          "???????? validateMaxLength檢查值的長度小于指定長度
          "???????? validateRange檢查值的有效范圍在指定范圍內(nèi)
          "???????? validateRequired檢查值不為null或長度>0
          "???????? validateShort 檢查值能夠安全地轉(zhuǎn)換為short
          1.1.1.1.1.1??????????? validation.xml
          Validator框架所需要的第二個配置文件是validation.xml,這個配置文件是具體應(yīng)用(項目)所特定的,可以根據(jù)你的應(yīng)用(項目)情況進行自定義配置。它描述了具體的ActionForm使用validation-rules.xml文件中的哪個校驗規(guī)則進行校驗。
          validation_1_1.dtd定義了validation.xml的結(jié)構(gòu),根元素為form-validation,其包含0到多個global元素和一到多個formset元素:
          <!ELEMENT form-validation (global*, formset+)>
          global元素包含0到多個constant子元素:
          <!ELEMENT global (constant*)>
          constant子元素和Java里面常量的含義是一樣的,下面的片斷定義了兩個常量:
          <global>
          ?<constant>
          ? <constant-name>phone</constant-name>
          ? <constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
          ?</constant>
          ?<constant>
          ? <constant-name>zip</constant-name>
          ? <constant-value>^\d{5}(-\d{4})?$</constant-value>
          ?</constant>
          </global>
          上面的片斷包含了兩個常量,phone 和zip,這些常量在所有formset元素中有效,在formset中通過名稱引用這些常量。
          下面的片斷展示了一個簡單的validation.xml文件說明:
          代碼片斷 3.3.3.3.1.3.1
          <form-validation>
          ?<global>
          ? <constant>
          ?? <constant-name>phone</constant-name>
          ?? <constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
          ? </constant>????????????????
          ?</global>
          ?<formset>??
          ? <form name="checkoutForm">
          ?? <field
          ???? property="phone"
          ???? depends="required,mask">
          ???? <arg0 key="registrationForm.firstname.displayname"/>
          ???? <var>
          ?????? <var-name>mask</var-name>
          ?????? <var-value>${phone}</var-value>
          ???? </var>????
          ??? </field>???
          ?? </form>???????????
          ? </formset>??
          </form-validation>
          在上面的代碼片斷中,var元素應(yīng)用了在global中定義了phone常量,用來配合對phone屬性的校驗。
          formset元素可以包含兩個子元素,constant和form。constant元素和global區(qū)域定義的constant元素格式和用途一樣,只不過作用范圍不同,在formset中定義的constant元素其作用范圍只限于該formset覆蓋區(qū)域。Formset元素中的form元素至少要出現(xiàn)一次。DTD描述如下:
          <!ELEMENT formset (constant*, form+)>
          form元素定義了需要進行校驗的域,其name屬性對應(yīng)應(yīng)用中分配給form的標(biāo)識,在Struts框架中,就是在Struts配置文件中form-beans區(qū)域定義的ActionForm的name屬性。
          下面是form元素的DTD定義:
          <!ELEMENT form (field+)>
          field元素指明了JavaBean中需要被校驗的屬性。在上面的代碼片斷中,在Struts中,ActionForm就是這個需要被校驗的JavaBean。在代碼片斷 3.3.3.3.1.3.1中,定義了對Struts配置文件中名稱為checkoutForm的ActionForm所擁有的名稱為phone的屬性的校驗說明,表示checkoutForm的phone屬性為必填項而且符合${phone}所定義的正則表達式的掩碼規(guī)則。field元素的屬性在下表中具體描述:
          屬性?描述
          property?JavaBean(在Struts為ActionForm)中需要被校驗的屬性的名稱。
          depends?應(yīng)用于property指定屬性的校驗規(guī)則列表,多個校驗規(guī)則之間用逗號分隔。
          page?這個屬性在應(yīng)用于"向?qū)?模式的form中,用來確保不會跳頁訪問。
          indexedListProperty?不會用
          表3.3.3.3.1.3.1 field元素的屬性列表
          field元素包含以下幾個子元素,DTD定義如下:
          <!ELEMENT field (msg?, arg0?, arg1?, arg2?, arg3?, var*)>
          msg子元素允許你為該field指定一個提示信息,校驗規(guī)則將會使用這個指定的提示信息替代規(guī)則默認的提示信息,msg子元素的值必須是應(yīng)用資源文件的一個關(guān)鍵字(key)。例如:
          <field property="phone" depends="required,mask">
          ? <msg name="mask" key="phone.invalidformat"/>
          ? <arg0 key="registrationForm.firstname.displayname"/>
          ? <var>
          ??? <var-name>mask</var-name>
          ??? <var-value>${phone}</var-value>
          ? </var>??????????????
          </field>
          msg子元素支持三個屬性,DTD定義如下:
          <!ATTLIST msg name???? CDATA #IMPLIED
          ???????????????? key????? CDATA #IMPLIED
          ???????????????? resource CDATA #IMPLIED >
          name 屬性指定了msg將使用的校驗規(guī)則名稱,屬性值必須是在validation-rules.xml 文件中定義的校驗規(guī)則。
          key 屬性指定了一個資源文件的關(guān)鍵字,當(dāng)校驗失敗是,該關(guān)鍵字所代表的信息將會添加到ActionError中。如果你想設(shè)置一個明確的文本而不是資源文件的關(guān)鍵字,則可以將resource屬性設(shè)置位false,這種情況下,可以將key屬性設(shè)置為一個明確的文本,如"電話格式不正確!"。
          ?field元素可以包含至多四個額外的子元素,它們分別命名為arg0, arg1, arg2和arg3,它們用來向提示信息中添加額外的信息,arg0定義了第一個可替換的值,arg1定義了第二個可替換的值,以此類推。每個arg元素支持三個屬性,name, key和resource,其含義和之前我們看到的msg元素的同名屬性含義一致。下面是一段應(yīng)用arg元素的示例:
          <field property="phone" depends="required,mask,minLength">
          ? <arg0 key="registrationForm.firstname.displayname"/>
          ? <arg1 name="minlength" key="${var:minLength}" resource="false"/>
          ? <var>
          ?? <var-name>mask</var-name>
          ?? <var-value>${phone}</var-value>
          ? </var>????
          ? <var>
          ?? <var-name>minLength</var-name>
          ?? <var-value>5</var-value>
          ? </var>????????
          </field>?
          field元素包含的最后一個子元素是var元素,field元素可以包含0到多個var元素,var 元素可以設(shè)置該field所用到的校驗規(guī)則的參數(shù),var-name參數(shù)名,var-value指定參數(shù)值。例如設(shè)置mask規(guī)則的具體的正則表達式:
          ?<var-name>mask</var-name>
          ?<var-value>${phone}</var-value>
          設(shè)置minLength規(guī)則的最小長度:
          <var-name>minLength</var-name>
          <var-value>5</var-value>
          當(dāng)然,這個參數(shù)可以被arg元素應(yīng)用,應(yīng)用語法為:${var:var-name}。
          1.1.1.1.1.1??????????? 插入Validator
          每一個Struts應(yīng)用需要知道是否使用了Validator框架,可以通過PlugIn(插件)機制將Validator框架配置到Struts應(yīng)用中。
          下面的代碼演示了如何將Validator作為一個插件加入到Struts應(yīng)用中,在Struts應(yīng)用的配置文件Struts-config.xml中加入如下代碼片段:
          <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
          ? <set-property
          ??? property="pathnames"
          ??? value="/WEB-INF/validator-rules.xml,/WEB-INF/validator.xml"/>
          </plug-in>
          粗體部分pathnames屬性的值用來指定Validator框架所使用的配置文件,多個配置文件之間用逗號分隔。
          當(dāng)應(yīng)用啟動的時候,Struts框架將調(diào)用ValidatorPlugIn的init()方法。Validator框架的配置文件將會加載到內(nèi)存中供應(yīng)用使用。在init()方法被調(diào)用之前,pathnames所指定的值將會傳遞給ValidatorPlugIn的實例,ValidatorPlugIn實例將會依據(jù)這個值去加載配置文件。
          1.1.1.2??? 使用帶校驗的ActionForm
          你不能使用標(biāo)準(zhǔn)的Struts ActionForm去和Validator配合使用。你必須使用專門為Validator框架設(shè)計的ActionForm的子類?,F(xiàn)在有兩個子類可以選擇,取決于你是否打算使用動態(tài)ActionForms。下面的圖直觀地顯示了ActionForm以及它的后代:
          ?
          如果你打算使用動態(tài)ActionForm,為了和Validator框架配合使用,你可以使用DynaValidatorForm,否則,可以使用ValidatorForm。從圖上看出,DynaValidatorForm有個子類叫做DynaValidatorActionForm,ValidatorForm有個子類叫做ValidatorActionForm,這兩個子類在其父類的名字中間加了個"Action",這兩個類有什么作用呢?
          同樣,根據(jù)你是否打算使用動態(tài)ActionForm,你可以使用DynaValidatorActionForm或ValidatorActionForm,來配合使用Validator框架,當(dāng)使用這兩個類時,它們將action的path屬性傳遞給Validator,Validator使用action的名字去查找使用的校驗規(guī)則。而使用DynaValidatorForm和ValidatorForm,則是使用的ActionForm 的name屬性去查找匹配校驗規(guī)則。(???)
          1.1.1.1.1????? 示例
          第一步,在Struts-config.xml中配置一個ActionForm,示例如下:
          <form-bean
          ? name="checkoutForm"
          ? type="org.apache.struts.validator.DynaValidatorForm">
          ? <form-property name="firstName" type="java.lang.String"/>
          ? <form-property name="lastName" type="java.lang.String"/>
          ? <form-property name="address" type="java.lang.String"/>???
          ? <form-property name="city" type="java.lang.String"/>
          ? <form-property name="state" type="java.lang.String"/>
          ? <form-property name="postalCode" type="java.lang.String"/>
          ? <form-property name="country" type="java.lang.String"/>
          ? <form-property name="phone" type="java.lang.String"/>???
          </form-bean>
          第二步,在Struts-config.xml中配置一個Action,示例如下:
          <action
          ?? input="/checkout.jsp"
          ?? name="checkoutForm"
          ?? path="/checkout"
          ?? scope="request"
          ?? type="com.ort.struts.example.checkOutAction"
          ?? validate="true">
          ?</action>
          ?
          第三布,在validation.xml文件中定義如下:
          <formset>
          ? <constant>
          ??? <constant-name>phone</constant-name>
          ??? <constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
          ? </constant>????????????????
          ? <constant>
          ??? <constant-name>zip</constant-name>
          ??? <constant-value>^\d{5}(-\d{4})?$</constant-value>
          ? </constant>??????????????????????
          ? <form name="checkoutForm">
          ??? <field
          ????? property="firstName"
          ????? depends="required,mask">
          ????? <arg0 key="label.firstName"/>??????????
          ????? <var>
          ??????? <var-name>mask</var-name>
          ??????? <var-value>^[a-zA-Z]*$</var-value>
          ????? </var>?????????????????
          ??? </field>
          ??? <field
          ????? property="postalCode"
          ????? depends="required,mask">
          ????? <arg0 key="registrationForm.zip"/>
          ????? <var>
          ??????? <var-name>mask</var-name>
          ??????? <var-value>${zip}</var-value>
          ????? </var>
          ??? </field>
          ??? <field
          ????? property="phone"
          ????? depends="required,mask">
          ????? <arg0 key="registrationForm.phone"/>
          ????? <var>
          ??????? <var-name>mask</var-name>
          ??????? <var-value>${phone}</var-value>
          ????? </var>
          ??? </field>????????
          ? </form>???????????
          ?</formset>??
          </form-validation>
          第四部,編寫HTML頁面如下:
          暫略

          ?


          1.???? JSP 自定義標(biāo)簽庫
          1.1? 概述
          在JSP開發(fā)中會遇到一些重復(fù)的工作。而使用自定義標(biāo)簽庫是一種方法,可以用來將這些功能封裝起來并在多個項目中重新用到它。此外,應(yīng)用邏輯還可以包含在基于服務(wù)器的資源中,比如JavaBeans。這種架構(gòu)顯示出使用自定義標(biāo)簽庫可以更快更容易地開發(fā)基于Web的應(yīng)用程序。
          有關(guān)JavaBeans和自定義標(biāo)簽庫的最初想法是:在程序員研究那些包含商務(wù)邏輯(business logic)的類的同時,Web設(shè)計師可以同步進行頁面設(shè)計。然后,Web設(shè)計師可以通過使用簡單的"連線"將JSP頁面和這些類聯(lián)系起來。盡管使用JavaBean會減少在JSP頁面中寫代碼的數(shù)量,但你還是得寫程序去使用這些Beans。
          然而使用自定義標(biāo)簽庫則是一種完全無需在JSP中寫代碼的好辦法。這并不是說自定義標(biāo)簽庫會取代JavaBeans,它們都是用來分離實際內(nèi)容和顯示形式的。JavaBeans在用于商務(wù)邏輯被重用的設(shè)計中作用更為明顯。JavaBeans通常能在不同項目的各種頁面中被用到。另一方面,自定義標(biāo)簽庫則是一個特殊頁面的自定義形式,即便如此,將它重新利用到其他程序中也是很常見的。得到自定義標(biāo)簽庫的一種方法是自己建一個。但為什么不使用現(xiàn)成的呢?比如Jakarta Taglibs項目(源自Apache Software Foundation)就提供了一些自定義標(biāo)簽庫,它們可以在不同的JSP應(yīng)用程序中重復(fù)使用。
          1.2? Struts包含的標(biāo)簽庫
          Struts框架提供了一系列的框架組件,同時,他也提供了一系列的標(biāo)簽(Tag)用于和框架進行交互。Struts提供的標(biāo)簽包含在以下四個標(biāo)簽庫(Tag libraries)中:
          "???????? HTML
          "???????? Bean
          "???????? Logic
          "???????? Template
          這四個標(biāo)簽庫所包含的標(biāo)簽功能各自截然不同,從標(biāo)簽庫的名字我們可以看出其功能,如,HTML標(biāo)簽庫是用來包裝HTML控件的。
          1.3? 在Struts應(yīng)用中使用標(biāo)簽庫
          和使用其它標(biāo)簽庫一樣,使用Struts提供的標(biāo)簽庫只需要簡單的兩步:
          1、? 在web.xml中聲明標(biāo)簽庫:
          <taglib>
          ? <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
          </taglib>
          ?
          <taglib>
          ? <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
          ? <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
          </taglib>
          ?
          2、? 在JSP頁面中引入標(biāo)簽庫:
          <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
          <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
          ?
          1.4? Struts HTML標(biāo)簽庫
          HTML標(biāo)簽庫中的標(biāo)簽列表
          標(biāo)簽名?描述
          base?包裝HTML的base元素
          button?包裝HTML的 button類型的input元素
          cancel?包裝HTML cancel 按鈕
          checkbox?包裝HTML checkbox 類型的輸入域
          errors?有條件地顯示一些error消息,顯示ActionErrors信息
          file?包裝HTML文件上傳輸入域
          form?定義HTML form 元素
          frame?包裝HTML frame 元素
          hidden?包裝HTML hidden 輸入域
          html?包裝 HTML中的 html 元素
          image?包裝 "image"類型的輸入域
          img?包裝HTML的 img 元素
          javascript?包裝根據(jù)ValidatorPlugIn提供的校驗規(guī)則所提供的javascript校驗?zāi)_本
          link?包裝超鏈接
          messages?有條件地顯示一些提示信息,顯示ActionMessages信息
          multibox?包裝多選輸入框
          option?包裝一個選擇輸入框
          options?包裝一批選擇輸入框
          optionsCollection?包裝一批選擇輸入框集
          password?包裝密文輸入框
          radio?包裝單選輸入框
          reset?包裝"重置"功能的按鈕
          rewrite?包裝一個URL
          select?包裝一個選擇輸入框
          submit?包裝一個提交按鈕
          text?包裝一個文本輸入框
          textarea?包裝一個備注輸入框
          在這里,不打算對每一個標(biāo)簽的使用進行詳細說明,要想了解每一個標(biāo)簽的使用,請查看Struts官方文檔。
          接下來,我們著重學(xué)習(xí)一下幾個非常重要的標(biāo)簽的使用,舉一反三,通過這幾個標(biāo)簽的使用,我想,即使不去看官方文檔,也能夠?qū)ζ渌鼧?biāo)簽的使用有個基本的了解。
          1.1.1?????????? form標(biāo)簽
          Struts的form標(biāo)簽是最重要的標(biāo)簽之一,他包裝了HTML的標(biāo)準(zhǔn)form標(biāo)簽,提供了將HTML form和ActionForm 連接起來的功能。
          HTML form中的每一個域?qū)?yīng)ActionForm的一個屬性,當(dāng)提交HTML from后,Struts根據(jù)匹配關(guān)系,將HTML from域的值賦給ActionForm的同名屬性。下表列舉了form標(biāo)簽的屬性,并且針對每一個屬性加以詳細說明:
          Struts form標(biāo)簽屬性列表
          Name?Description
          action?form提交的目標(biāo)地址,action用來選擇一個Struts Action對提交后的客戶請求進行處理。通過和action的path屬性進行匹配來選擇Struts Action。
          如果在web.xml中設(shè)置的servlet映射是擴展名映射,則可以用以下方式進行Action匹配(擴展名可以不作為匹配內(nèi)容):
          <html:form action="login.do" focus="accessNumber">
          上面的語句表示form提交后,交給path屬性值為login的Action進行處理
          如果在web.xml中設(shè)置的servlet映射是路徑映射,則action的值必須完全匹配Struts Action的path屬性值,例如:
          <html:form action="login" focus="accessNumber">
          enctype?提交form使用的編碼方式
          focus?頁面初始化時光標(biāo)定位的輸入控件名
          method?提交請求的HTTP方式('POST' or 'GET')
          name?對應(yīng)的ActionForm的名字 ,如果不指定,則使用Struts Action在配置文件中name屬性所指定的ActionForm。
          onreset?當(dāng)form重置時執(zhí)行的Javascript
          onsubmit?當(dāng)form提交時執(zhí)行的javascript
          scope?與form對應(yīng)的ActionForm的有效區(qū)域,可以為request 或session
          style?CSS樣式表The CSS styles to be applied to this HTML element.
          styleClass?CSS樣式類別
          styleId?HTML元素的ID
          target?form提交的目標(biāo)frame
          type?form對應(yīng)的ActionForm的類名
          ?
          1.2? Struts Logic標(biāo)簽庫
          Struts Logic標(biāo)簽庫中包含的標(biāo)簽列表
          Tag name?Description
          empty?如果標(biāo)簽parameter,propertie等屬性所指定的變量值為null或空字符串,則處理標(biāo)簽包含的內(nèi)容
          equal?如果標(biāo)簽parameter,propertie等屬性所指定的變量的值等于標(biāo)簽value屬性所指定的值,則處理標(biāo)簽所包含的內(nèi)容,如:
          <logic:equal value="modify" property="action"? name="projectForm">
          ??? <bean:message key="project.project_modify"/>
          </logic:equal>
          上面的示例表示,如果projectForm的action屬性等于modify,則處理<bean:message key="project.project_modify"/>語句。
          forward?Forward control to the page specified by the ActionForward entry.
          greaterEqual?Evaluate the nested body content of this tag if the requested variable is greater than or equal to the specified value.
          greaterThan?Evaluate the nested body content of this tag if the requested variable is greater than the specified value.
          iterate?Repeat the nested body content of this tag over a specified collection.
          lessEqual?Evaluate the nested body content of this tag if the requested variable is less than or equal to the specified value.
          lessThan?Evaluate the nested body content of this tag if the requested variable is less than the specified value.
          match?Evaluate the nested body content of this tag if the specified value is an appropriate substring of the requested variable.
          messagesNotPresent ?Generate the nested body content of this tag if the specified message is not present in this request.
          messagesPresent?Generate the nested body content of this tag if the specified message is present in this request.
          notEmpty?Evaluate the nested body content of this tag if the requested variable is neither null nor an empty string.
          notEqual?Evaluate the nested body content of this tag if the requested variable is not equal to the specified value.
          notMatch?Evaluate the nested body content of this tag if the specified value is not an appropriate substring of the requested variable.
          notPresent?Generate the nested body content of this tag if the specified value is not present in this request.
          present?Generate the nested body content of this tag if the specified value is present in this request.
          redirect?Render an HTTP redirect.
          ?
          執(zhí)行比較功能的標(biāo)簽通用屬性表
          Name?Description
          name?The name of a bean to use to compare against the value attribute. If the property attribute is used, the value is compared against the property of the bean, instead of the bean itself.
          parameter?The name of a request parameter to compare the value attribute against.
          property?The variable to be compared is the property (of the bean specified by the name attribute) specified by this attribute. The property reference can be simple, nested, and/or indexed.
          scope?The scope within which to search for the bean named by the name attribute. All scopes will be searched if not specified.
          value?The constant value to which the variable, specified by another attribute(s) of this tag, will be compared.
          ?
          示例:
          To check whether a particular request parameter is present, you can use the Logic present tag:
          <logic:present parameter="id">
          ? <!-- Print out the request parameter id value -->
          </logic:present>
          To check whether a collection is empty before iterating over it, you can use the notEmpty tag:
          <logic:notEmpty name="userSummary" property="addresses">
          ? <!-- Iterate and print out the user's addresses -->
          </logic:notEmpty>
          Finally, here's how to compare a number value against a property within an ActionForm:
          <logic:lessThan property="age" value="21">?
          ? <!-- Display a message about the user's age -->
          </logic:lessThan>
          1.1? Struts Bean標(biāo)簽庫
          Struts Bean標(biāo)簽庫中的標(biāo)簽列表
          Tag name?Description
          cookie?Define a scripting variable based on the value(s) of the specified request cookie.
          define?Define a scripting variable based on the value(s) of the specified bean property.
          header?Define a scripting variable based on the value(s) of the specified request header.
          include?Load the response from a dynamic application request and make it available as a bean.
          message?Render an internationalized message string to the response.
          page?Expose a specified item from the page context as a bean.
          parameter?Define a scripting variable based on the value(s) of the specified request parameter.
          resource?Load a web application resource and make it available as a bean.
          size?Define a bean containing the number of elements in a Collection or Map.
          struts?Expose a named Struts internal configuration object as a bean.
          write?Render the value of the specified bean property.
          ?
          1.2? Struts Template標(biāo)簽庫
          Struts Template標(biāo)簽庫中的標(biāo)簽列表
          Tag name?Description
          insert?Retrieve (or include) the specified template file, and then insert the specified content into the template's layout. By changing the layout defined in the template file, any other file that inserts the template will automatically use the new layout.
          put?Create a request-scope bean that specifies the content to be used by the get tag. Content can be printed directly or included from a JSP or HTML file.
          get?Retrieve content from a request-scope bean, for use in the template layout.
          ?

          1.???? 示例
          示例實現(xiàn)了一個簡單的項目信息CRUD(添加、查詢、更新、刪除)+分頁顯示的功能。
          其中項目有如下屬性:
          ????????? 項目編號
          ????????? 項目名稱
          ????????? 項目所屬區(qū)域(區(qū)域存在與一個字典表中)
          ????????? 項目分成比例(0.00%--100.00%)
          ?
          數(shù)據(jù)庫結(jié)構(gòu)定義如下所示(采用Oracle8i數(shù)據(jù)庫,如果采用其它數(shù)據(jù)庫請作相應(yīng)變化):
          SITES --區(qū)域表
          Name?Datatype?Null Option?Comment?Is PK
          SITECODE?VARCHAR2(10)?NOT NULL?區(qū)域號?Yes
          SITENAME?VARCHAR2(30)?NOT NULL?區(qū)域名稱?No
          ?
          PROJECTS --項目表
          Name?Datatype?Null Option?Comment?Is PK
          PROJECTCODE?VARCHAR2(10)?NOT NULL?項目編號?Yes
          PROJECTNAME?VARCHAR2(30)?NOT NULL?項目名稱?No
          SITECODE?VARCHAR2(10)?NOT NULL?所屬區(qū)域號?
          DISCOUNT?NUMBER?NULL?項目分成比例?
          ?
          附:在ORACLE8i中創(chuàng)建數(shù)據(jù)表的語句為:
          --創(chuàng)建區(qū)域表
          CREATE TABLE SITES (
          ?SITECODE VARCHAR2(10) NOT NULL,
          ?SITENAME VARCHAR2(30) NOT NULL
          );
          --添加主鍵
          ALTER TABLE SITES
          ?????? ADD? ( CONSTRAINT SITES_PKSITECODE PRIMARY KEY (SITECODE)
          ?????? USING INDEX );?
          --創(chuàng)建項目信息表
          CREATE TABLE PROJECTS(
          ?PROJECTCODE VARCHAR2(10) NOT NULL,
          ?PROJECTNAME VARCHAR2(30) NOT NULL,
          ?SITECODE VARCHAR2(10) NOT NULL,
          ?DISCOUNT NUMBER NULL
          );
          --添加主鍵索引
          ALTER TABLE PROJECTS
          ?????? ADD? ( CONSTRAINT PROJECTS_PKPROJECTCODE PRIMARY KEY (PROJECTCODE)
          ?????? USING INDEX );?
          --添加外鍵索引
          CREATE INDEX FK_PROJECTSSITECODE ON PROJECTS
          (
          ?????? SITECODE? ASC
          );
          --添加外鍵約束
          ?ALTER TABLE PROJECTS
          ?????? ADD? ( CONSTRAINT FK_PROJECTSSITECODE
          ????????????? FOREIGN KEY (SITECODE)
          ???????????????????????????? REFERENCES SITES ) ;
          --創(chuàng)建區(qū)域表
          CREATE TABLE SITES (
          ?SITECODE VARCHAR2(10) NOT NULL,
          ?SITENAME VARCHAR2(30) NOT NULL
          );
          --添加主鍵
          ALTER TABLE SITES
          ?????? ADD? ( CONSTRAINT SITES_PKSITECODE PRIMARY KEY (SITECODE)
          ?????? USING INDEX );?
          --創(chuàng)建項目信息表
          CREATE TABLE PROJECTS(
          ?PROJECTCODE VARCHAR2(10) NOT NULL,
          ?PROJECTNAME VARCHAR2(30) NOT NULL,
          ?SITECODE VARCHAR2(10) NOT NULL,
          ?DISCOUNT NUMBER NULL
          );
          --添加主鍵索引
          ALTER TABLE PROJECTS
          ?????? ADD? ( CONSTRAINT PROJECTS_PKPROJECTCODE PRIMARY KEY (PROJECTCODE)
          ?????? USING INDEX );?
          --添加外鍵索引
          CREATE INDEX FK_PROJECTSSITECODE ON PROJECTS
          (
          ?????? SITECODE? ASC
          );
          --添加外鍵約束
          ?ALTER TABLE PROJECTS
          ?????? ADD? ( CONSTRAINT FK_PROJECTSSITECODE
          ????????????? FOREIGN KEY (SITECODE)
          ???????????????????????????? REFERENCES SITES ) ;
          ?
          1.1? 命名規(guī)范
          1、? 所有jsp,action映射路徑均為小寫字母,如有需要可以使用小寫字母+數(shù)字:例如:
          /projectlist,/projetlist.jsp
          2、? 所有<html:form>中的元素(如文本框,列表框等)名稱都使用java規(guī)范的變量命名方式(變量由一個或多個單詞組成,第一個單詞小寫,第一個單詞后的單詞首字母大寫),例如:
          <html:text styleClass="input" maxlength="10" property="projectCode" size="30"/>
          3、? 其它方面均遵守SUN推薦的編碼規(guī)范。
          1.2? 文件
          1.2.1?????????? projectlist.jsp
          該jsp頁面用來顯示項目信息列表,并提供查詢功能。同時,提供按鈕將用戶導(dǎo)向到添加、修改、刪除功能。
          1.2.2?????????? projectform.jsp
          在執(zhí)行添加、修改操作之前,需要提供一個form供用戶輸入數(shù)據(jù),在執(zhí)行刪除操作之前,需要提供一個form將被刪除數(shù)據(jù)顯示出來,供用戶確認。該jsp頁面就是用來滿足這些需要,提供對單條項目信息的顯示,根據(jù)具體的操作類型(創(chuàng)建、修改、刪除),數(shù)據(jù)被顯示在可編輯的輸入控件中或不可編輯的label(文本標(biāo)簽)上。
          1.2.3?????????? success.jsp
          添加、修改、刪除等操作正常完成后,提供一個頁面顯示"恭喜"信息,使得用戶能夠清楚知道自己的行為已經(jīng)生效 。
          1.2.4?????????? failed.jsp
          添加、修改、刪除等操作異常失敗,提供一個頁面顯示"失敗"信息,使得用戶能夠清楚知道自己的行為已經(jīng)失敗 。
          1.2.5?????????? ProjectListSearchAction.java
          "Project"+"List"+"Search"+"Action",組成了這個Action的名字,這是我個人的命名風(fēng)格,表示這個Action會處理項目列表和查詢事務(wù)。在projectlist.jsp被裝載之前,ProjectListSearchAction需要將數(shù)據(jù)加載到scope指定的地方,供projectlist.jsp顯示,當(dāng)用戶從projectlist.jsp中提交查詢請求,該Action需要處理查詢,并加載數(shù)據(jù),供projectlist.jsp顯示。
          1.2.6?????????? ProjectFormLoadAction
          這個Action用來處理在顯示projectform.jsp之前,將所需要的數(shù)據(jù)加載到scope指定的范圍中,供projectform使用。
          ?
          1.2.7?????????? ProjectFormSaveAction.java
          這個Action用來處理用戶在projectform.jsp中提交的數(shù)據(jù),根據(jù)用戶的操作類型,完成具體的操作,并將合適的提示頁面(success.jsp or failed.jsp)顯示給用戶。
          1.2.8?????????? web.xml
          在Struts安裝那一節(jié),我們已經(jīng)知道web.xml文件的作用,通過這個文件,我們可以將ActionServlet配置好,用以截獲用戶對Struts應(yīng)用的訪問請求。下面是示例程序所用的web.xml內(nèi)容:
          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "<web-app>
          ? <display-name>simpledemo</display-name>
          ? <description>Demo for using STRUTS to do some thing about CRUD(Create,Read,Update,Delete) and any more....</description>
          ? <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</param-value>
          ??? </init-param>
          ??? <init-param>
          ????? <param-name>debug</param-name>
          ????? <param-value>2</param-value>
          ??? </init-param>
          ??? <load-on-startup>2</load-on-startup>
          ? </servlet>
          ? <servlet>
          ??? <servlet-name>debugjsp</servlet-name>
          ??? <description>Added to compile JSPs with debug info</description>
          ??? <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
          ??? <init-param>
          ????? <param-name>classdebuginfo</param-name>
          ????? <param-value>true</param-value>
          ??? </init-param>
          ??? <load-on-startup>3</load-on-startup>
          ? </servlet>
          ? <servlet-mapping>
          ??? <servlet-name>action</servlet-name>
          ??? <url-pattern>*.do</url-pattern>
          ? </servlet-mapping>
          ? <servlet-mapping>
          ??? <servlet-name>debugjsp</servlet-name>
          ??? <url-pattern>*.jsp</url-pattern>
          ? </servlet-mapping>
          ? <session-config>
          ??? <session-timeout>20</session-timeout>
          ? </session-config>
          ? <welcome-file-list>
          ??? <welcome-file>projectsearch.do</welcome-file>
          ? </welcome-file-list>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
          ? </taglib>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
          ? </taglib>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
          ? </taglib>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-template.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-template.tld</taglib-location>
          ? </taglib>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-tiles.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
          ? </taglib>
          ? <taglib>
          ??? <taglib-uri>/WEB-INF/struts-nested.tld</taglib-uri>
          ??? <taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
          ? </taglib>
          </web-app>
          1.1.1?????????? 資源文件
          使用資源文件來放置標(biāo)簽顯示值,提示信息等,如果你的Struts應(yīng)用有國際化的要求,那么資源文件一定要好好地利用,就算沒有國際化需求,使用資源文件也可以統(tǒng)一應(yīng)用程序用語(例如統(tǒng)一的提示信息,標(biāo)簽信息等),而且當(dāng)用語發(fā)生變化(如"小時"變成"鐘頭" ),很容易統(tǒng)一進行修改。下面是示例程序所用到的資源文件內(nèi)容(application.properties):
          #System global labels
          button_cancel = 取消
          button_edit = 修改
          button_delete = 刪除
          button_save = 保存
          button_submit = 確認
          ?
          #lables for project
          projectcontroller.title = 管理項目
          project.project_create = 添加項目
          project.project_modify = 修改項目
          project.project_list = 已添加項目列表
          project.projectcode = 項目代碼
          project.projectname = 項目名稱
          project.discount = 項目分成比例
          project.site = 所屬小區(qū)
          # Standard error messages for validator framework checks
          errors.required={0} is required.
          errors.minlength={0} cannot be less than {1} characters.
          errors.maxlength={0} cannot be greater than {2} characters.
          errors.invalid={0} is invalid.
          errors.byte={0} must be an byte.
          errors.short={0} must be an short.
          errors.integer={0} must be an integer.
          errors.long={0} must be an long.
          errors.float={0} must be an float.
          errors.double={0} must be an double.
          errors.date={0} is not a date.
          errors.range={0} is not in the range {1} through {2}.
          errors.creditcard={0} is not a valid credit card number.
          errors.email={0} is an invalid e-mail address.
          那么,如何在Struts應(yīng)用中引用資源文件呢?
          首先需要在Struts配置文件(Struts-config.xml)中指明配置文件的路徑,在配置文件中添加如下一行信息:
          <message-resources parameter="ApplicationResources_CN" />
          parameter所指的就是配置文件,注意,為什么這里指明的是applicationResources_CN,而不是上面提到的application.properties?這是為了能在Struts中正確顯示中文,利用jdk自帶的native2ascii程序?qū)pplication.properties作了編碼轉(zhuǎn)換,編碼轉(zhuǎn)換后的文件名為ApplicationResources_CN.properties,擴展名可以省略。
          需要注意的是,改配置文件一定要放在classpath范圍內(nèi),一般放置在WEB-INF/classes目錄下,如果放在classes的子目錄下,其指引方式和java包一樣,例如在WEB-INF/classes/com目錄下,則應(yīng)該用如下語句指引:
          <message-resources parameter="com.ApplicationResources_CN" />
          小技巧
          進行中文編碼轉(zhuǎn)換的命令如下:
          native2ascii -encoding gb2312 application.properties ApplicationResources_CN.properties
          在配置文件聲明了對資源文件的引用之后,就可以在Struts提供的標(biāo)簽以及校驗框架等其它地方使用這些資源,具體使用方法請查看相關(guān)標(biāo)簽和配置文件說明。
          1.1.2?????????? struts-config.xml
          該文件定義了Struts應(yīng)用中的Action,ActionForm,插件,資源引用等信息,示例程序struts-config.xml文件內(nèi)容如下:
          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "
          <struts-config>
          ? <form-beans>
          ????? <!--項目增、刪、改form定義 begin-->
          ??? <form-bean name="projectForm" type="com.ort.strutsdemo.simpledemo.ui.ProjectForm">
          ??? </form-bean>
          ??? <!--項目增、刪、改form定義 結(jié)束-->
          ??? <!--進入項目增、刪、改界面之前參數(shù)傳遞Form begin-->
          ??? <form-bean name="projectLoadForm" type="org.apache.struts.action.DynaActionForm">
          ????? <form-property name="action" size="10" type="java.lang.String" initial="create"/>
          ????? <form-property name="projectCode" size="30" type="java.lang.String" initial=""/>
          ??? </form-bean>
          ??? <!--進入項目增、刪、改界面之前參數(shù)傳遞Form end-->
          ??? <!--項目查詢Form定義 Begin-->
          ??? <form-bean name="projectSearchForm" type="org.apache.struts.action.DynaActionForm">
          ??????? <form-property name="projectCode" size="10" type="java.lang.String" initial=""/>
          ??????? <form-property name="projectCodeSign" size="10" type="java.lang.String" initial=""/>
          ??????? <form-property name="projectName" size="10" type="java.lang.String" initial=""/>
          ??????? <form-property name="projectNameSign" size="10" type="java.lang.String" initial=""/>
          ??????? <form-property name="page" size="10" type="java.lang.Integer" initial="1"/>
          ??????? <form-property name="pageCount" size="10" type="java.lang.Integer" initial="1"/>
          ??? </form-bean>
          ??? <!--項目查詢Form定義 End-->
          ? </form-beans>
          ? <global-forwards>
          ??? <forward name="projectlist" path="/projectlist.jsp" />
          ??? <forward name="projectform" path="/projectform.jsp" />
          ??? <forward name="failed" path="/failed.jsp" />
          ??? <forward name="success" path="/success.jsp" />
          ? </global-forwards>
          ?
          ? <action-mappings>
          ??? <action input="projectform" name="projectForm" path="/projectformsave" scope="request" type="com.ort.strutsdemo.simpledemo.controller.ProjectFormSaveAction" validate="true">
          ????? <forward name="success" path="/projectsearch.do" redirect="true" />
          ????? <forward name="success.return" path="/projectsearch.do" redirect="true" />
          ????? <forward name="cancel" path="/projectsearch.do" redirect="true" />
          ????? <forward name="failed" path="/failed.jsp" />
          ????? <forward name="failed.return" path="/projectsearch.do" />
          ??? </action>
          ??? <action input="projectlist" name="projectLoadForm" path="/projectformload" scope="request" type="com.ort.strutsdemo.simpledemo.controller.ProjectFormLoadAction" validate="false">
          ????? <forward name="success" path="/projectform.jsp" />
          ????? <forward name="failed" path="/failed.jsp" />
          ????? <forward name="failed.return" path="/projectsearch.do" redirect="true" />
          ??? </action>
          ???? <action input="projectlist" name="projectSearchForm" path="/projectsearch" scope="request" type="com.ort.strutsdemo.simpledemo.controller.ProjectListSearchAction" validate="false">
          ????? <forward name="success" path="/projectlist.jsp"/>
          ????? <forward name="failed" path="/failed.jsp" />
          ????? <forward name="failed.return" path="/projectsearch.do" redirect="true" />
          ??? </action>
          ? </action-mappings>
          ? <controller>
          ??? <set-property property="inputForward" value="true" />
          ? </controller>
          ? <message-resources parameter="ApplicationResources_CN" />
          ? <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
          ??? <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
          ? </plug-in>
          </struts-config>
          1.1? CRUD
          CRUD(Create,Retrieve or Read?,Update,Delete)是信息管理系統(tǒng)中經(jīng)常要執(zhí)行的操作的簡稱。接下來我們分別描述這幾種操作的執(zhí)行流程。
          1.1.1?????????? 查詢項目信息
          執(zhí)行項目信息查詢列表顯示的文件請求處理順序如下:
          1、? ProjectListSearchAction
          2、? projectlist.jsp
          ?
          ProjectListSearchAction代碼如下:
          package com.ort.strutsdemo.simpledemo.controller;
          ?
          /**
          ?* <p>Title: Struts Training </p>
          ?* <p>Description: Struts內(nèi)部培訓(xùn)Demo</p>
          ?* <p>Copyright: Copyright (c) 2004</p>
          ?* <p>Company: </p>
          ?* @author Liuz
          ?* @version 1.0
          ?*/
          import org.apache.struts.action.*;
          import javax.servlet.http.*;
          import com.ort.strutsdemo.simpledemo.business.BusinessDelegate;
          import com.boss.module.operation.object.Project;
          import com.ort.strutsdemo.simpledemo.Constants;
          import com.ort.strutsdemo.simpledemo.controller.exception.ExceptionBean;
          import com.boss.module.operation.object.searchresult.help.ResultSetIterator;
          import com.ort.strutsdemo.simpledemo.ui.ProjectForm;
          import com.boss.module.operation.object.searchgene.ProjectSearchGene;
          ?
          /**
          ?*
          ?* <p>Title: Struts Training </p>
          ?* <p>Description: 項目查詢結(jié)果數(shù)據(jù)的裝載</p>
          ?* <p>Copyright: Copyright (c) 2004</p>
          ?* <p>Company: ORT</p>
          ?* @author Liuz
          ?* @version 1.0
          ?*/
          public class ProjectListSearchAction
          ??? extends Action {
          ??? BusinessDelegate businessDelegate = null;
          ??? public ActionForward execute(ActionMapping actionMapping,
          ???????????????????????????????? ActionForm actionForm,
          ???????????????????????????????? HttpServletRequest request,
          ???????????????????????????????? HttpServletResponse response) {
          ??????? try {
          ??????????? DynaActionForm form = (DynaActionForm) actionForm;
          ??????????? //定義分頁所需要變量
          ??????????? int page= ((Integer)form.get("page")).intValue();
          ??????????? int pageSize = 5;
          ??????????? int allSize = 0;
          ??????????? int pageCount = 0;
          ??????????? //獲取用戶輸入查詢值,并形成查詢條件
          ??????????? String projectCode = (String)form.get("projectCode");
          ??????????? String projectCodeSign = (String)form.get("projectCodeSign");
          ??????????? String projectName = (String)form.get("projectName");
          ??????????? String projectNameSign = (String)form.get("projectNameSign");
          ??????????? ProjectSearchGene searchGene = new ProjectSearchGene(); //searchGene為一查詢精靈,用以處理查詢操作,在此不用過多關(guān)注,有機會在另文介紹
          ??????????? searchGene.setProjectCode(projectCode, projectCodeSign);
          ??????????? searchGene.setProjectName(projectName, projectNameSign);
          ?
          ?
          ??????????? //裝載當(dāng)前頁面所需要顯示項目列表數(shù)據(jù)
          ???????????? BusinessDelegate businessDelegate = BusinessDelegate.getInstance(); //業(yè)務(wù)層操作,不用關(guān)注
          ???????????? ResultSetIterator projectIterator = businessDelegate.
          ???????????????? getProjectIterator(searchGene,pageSize);
          ???????????? java.util.List projects = projectIterator.getElements(page);
          ???????????? if (projects == null) {
          ???????????????? projects = new java.util.ArrayList();
          ???????????? }
          ???????????? //將項目列表查詢結(jié)果放置到請求對象中
          ??????????? request.removeAttribute(Constants.PROJECT_LISTFORM_KEY);
          ??????????? request.setAttribute(Constants.PROJECT_LISTFORM_KEY, projects);
          ??????????? //計算總頁數(shù)
          ??????????? allSize = projectIterator.getAllSize();
          ??????????? pageCount = (allSize % pageSize == 0) ? allSize / pageSize :
          ??????????????? allSize / pageSize + 1;
          ?????????? // System.err.print(pageCount);
          ??????????? form.set("pageCount", new Integer(pageCount));
          ?
          ??????????? //裝載當(dāng)前頁面所需要現(xiàn)實小區(qū)信息
          ??????????? ResultSetIterator siteIterator = businessDelegate.getSitesIterator();
          ??????????? java.util.List sites = siteIterator.getElements(1);
          ??????????? request.getSession().setAttribute(Constants.SITE_LISTFORM_KEY,
          ????????????????????????????????????????????? sites);
          ??????????? //重定向到mapping中配置的input頁面
          //??????????? return actionMapping.findForward("success");
          ??????????? return actionMapping.getInputForward();
          ??????? }
          ??????? catch (Exception ex) {
          ??????????? com.ipbs.util.Log.println(
          ??????????????? "[ProjectListSearchAction.java][Exception]:" + ex.getMessage());
          ??????????? ExceptionBean exception = new ExceptionBean();
          ??????????? exception.setErrorMsg(Constants.getExceptionMsg(ex));
          ??????????? exception.setReturnPath(actionMapping.findForward("failed.return").
          ??????????????????????????????????? getPath());
          ??????????? request.setAttribute(Constants.EXCEPTION_BEAN, exception);
          ??????????? return actionMapping.findForward("failed");
          ??????? }
          ??? }
          }
          在上面的代碼中,應(yīng)用了一個常量類(Constants),為了讓大家看得更加明白,將其代碼顯示如下:
          package com.ort.strutsdemo.simpledemo;
          ?
          /**
          ?* <p>Title: Struts Training </p>
          ?* <p>Description: Struts內(nèi)部培訓(xùn)Demo</p>
          ?* <p>Copyright: Copyright (c) 2004</p>
          ?* <p>Company: </p>
          ?* @author Liuz
          ?* @version 1.0
          ?*/
          ?
          public class Constants {
          ? public static final String PROJECT_SINGLEFORM_KEY = "projectForm";
          ? public static final String PROJECT_LISTFORM_KEY = "PROJECTS";
          ? public static final String PROJECT_SEARCHFORM_KEY = "SEARCHPROJECTS";
          ? public static final String PROJECT_CONTROLLERFORM_KEY = "PROJECTCONTROLLER";
          ? public static final String SITE_LISTFORM_KEY = "SITES";
          ? public static final String SITE_SINGLEFORM_KEY = "SITE";
          ?
          ? public static final String EXCEPTION_BEAN = "EXCEPTIONBEAN";
          ? /**
          ?? * 通過識別異常的基礎(chǔ)類型,返回易懂的提示信息
          ?? * @param ex Exception 異常
          ?? * @return String 異常的描述信息
          ?? */
          ? public static final String getExceptionMsg(Exception ex){
          ????? String returnMsg="";
          ????? if(ex!=null){
          ????????? if (ex instanceof com.boss.module.operation.command.exception.AlreadyExistException){
          ????????????? returnMsg = "數(shù)據(jù)已存在!";
          ????????????? return returnMsg;
          ????????? }else if (ex instanceof com.boss.module.operation.command.exception.DbException){
          ????????????? returnMsg = "數(shù)據(jù)庫錯誤!";
          ????????????? return returnMsg;
          ????????? }else if(ex instanceof com.boss.module.operation.command.exception.InvalidObjectException){
          ????????????? returnMsg = "無效的數(shù)據(jù)!";
          ????????????? return returnMsg;
          ????????? }else if(ex instanceof com.boss.module.operation.command.exception.InvalidPkException){
          ????????????? returnMsg = "無效的主鍵!";
          ????????????? return returnMsg;
          ????????? }else if(ex instanceof com.boss.module.operation.command.exception.NotFoundException){
          ????????????? returnMsg = "數(shù)據(jù)不存在!";
          ????????????? return returnMsg;
          ????????? }else if(ex instanceof com.boss.module.operation.command.exception.UnAuthorizationException){
          ????????????? returnMsg = "無權(quán)限!";
          ????????????? return returnMsg;
          ????????? }else if(ex instanceof com.boss.module.operation.object.searchresult.exception.IteratorException){
          ????????????? returnMsg = "獲取列表數(shù)據(jù)異常!";
          ????????????? return returnMsg;
          ????????? }
          ????? }
          ??? return returnMsg;
          ? }
          }
          ?
          projectlist.jsp內(nèi)容如下:
          <%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
          <%@ taglib uri="/WEB-INF/struts-nested.tld" prefix="nested" %>
          <%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>
          <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
          <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
          <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
          <%@ page contentType="text/html; charset=GB2312" %>
          ?
          <html:html>
          <head>
          <!-projectlist.title為資源引用-->
          <title><bean:message key="projectlist.title"/></title>
          <link href="css/main.css" rel="stylesheet" type="text/css">
          <meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head>
          <body bgcolor="#ffffff">
          <html:form action="projectsearch">
          ??? <table width="70%"? border="0" align="center" cellpadding="3" cellspacing="1" class="tablebodycolor">
          ??? <tr class="tdbodycolor">
          ????? <td colspan="2" class="tdheadcolor">
          ????????????? <bean:message key="project.project_search"/>
          ????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td width="15%"><div align="right"><bean:message key="project.projectcode"/></div></td>
          ????? <td width="85%">
          ????????? <html:select property="projectCodeSign">
          ????????????? <html:option value="like">like</html:option>
          ????????????? <html:option value="not like">not like</html:option>
          ????????????? <html:option value="=">equal</html:option>
          ????????????? <html:option value="<>">not equal</html:option>
          ????????? </html:select>
          ?<html:text styleClass="input" maxlength="30" property="projectCode" size="30"/>
          ????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td><div align="right"><bean:message key="project.projectname"/></div></td>
          ????? <td>
          ????????? <html:select property="projectNameSign">
          ????????????? <html:option value="like">like</html:option>
          ????????????? <html:option value="not like">not like</html:option>
          ????????????? <html:option value="=">equal</html:option>
          ????????????? <html:option value="<>">not equal</html:option>
          ????????? </html:select>
          ????????? <html:text styleClass="input" maxlength="30" property="projectName" size="30"/>
          ????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ?
          ?? <tr class="tdbodycolor">
          ????? <td colspan="2"><div align="center">
          ????????? <html:hidden property="page"/>
          ????????? <html:hidden property="pageCount"/>
          ??????? <html:submit><bean:message key="button_search"/></html:submit>
          ????? </div></td>
          ??? </tr>
          ??? </tr>
          ? </table>
          </html:form>
          <table width="70%" border="0" align="center" cellpadding="2" cellspacing="1" class="tablebodycolor">
          ? <tr class="tdheadcolor">
          ??? <td height="19" colspan="6" class="tdbodycolor">
          ?????? <input type="button" name="button_create"
          ??????????? value="<bean:message key="button_create"/>" onclick="javascript:window.location='projectformload.do?action=create'"/>
          ??? </td>
          ? </tr>
          </table>
          <table width="70%" border="0" align="center" cellpadding="2" cellspacing="1" class="tablebodycolor">
          ? <tr class="tdheadcolor">
          ??? <td height="19" colspan="6" class="tdbodycolor"><bean:message key="project.project_list"/></td>
          ? </tr>
          ? <tr class="tdheadcolor">
          ??? <td width="92"><div align="center"><bean:message key="project.projectcode"/></div></td>
          ??? <td width="182"><div align="center"><bean:message key="project.projectname"/></div></td>
          ??? <td width="70"><div align="center"><bean:message key="project.discount"/></div></td>
          ??? <td width="139"><div align="center"><bean:message key="project.site"/></div></td>
          ??? <td width="83"><div align="center"><bean:message key="button_edit" /></div></td>
          ??? <td width="83"><div align="center"><bean:message key="button_delete"/></div></td>
          ? </tr>
          ? <logic:iterate id="project" name="PROJECTS">
          ? <tr class="tdbodycolor">
          ??? <td><div align="center"><bean:write name="project" property="projectCode"/></div></td>
          ??? <td><div align="center"><bean:write name="project" property="projectName"/></div></td>
          ??? <td><div align="center"><bean:write name="project" property="discount"/></div></td>
          ??? <td><div align="center"><bean:define id="site" name="project" property="site">
          ?????????????????????????? </bean:define>
          ?????????????????????????? <bean:write name="site" property="siteName"/></div></td>
          ??? <td><div align="center">
          ??????? <input type="button" name="button_edit"
          ??????????? value="<bean:message key="button_edit"/>" onclick="javascript:window.location='projectformload.do?action=modify&projectCode=<bean:write name="project" property="projectCode"/>'"/>
          ??? </div></td>
          ??? <td><div align="center">
          ?????? <input type="button" name="button_delete"
          ??????????? value="<bean:message key="button_delete"/>" onclick="javascript:window.location='projectformload.do?action=delete&projectCode=<bean:write name="project" property="projectCode"/>'"/>
          ??? </div></td>
          ? </tr>
          ? </logic:iterate>
          </table>
          ?
          <!------分頁----->
          <script language="javascript">
          ?function firstPage(){
          ??????????? document.projectSearchForm.page.value = 1;
          ??????????? document.projectSearchForm.submit();
          ?}
          ??????? function previousPage(){
          ??????????? document.projectSearchForm.page.value = parseInt(document.projectSearchForm.page.value)-1;
          ??????????? document.projectSearchForm.submit();
          ??????? }
          ??????? function nextPage(){
          ??????????? document.projectSearchForm.page.value = parseInt(document.projectSearchForm.page.value)+1;
          ??????????? document.projectSearchForm.submit();
          ??????? }
          ??????? function lastPage(){
          ??????????? document.projectSearchForm.page.value = document.projectSearchForm.pageCount.value;
          ??????????? document.projectSearchForm.submit();
          ??????? }
          </script>
          <table width=600 cellspacing="0" cellpadding="0" align="center">
          ??????? <tr>
          ????????? <td colspan=2><br>
          ????????????? <div align="center">
          ??<bean:define id="currPageOb" property="page" name="projectSearchForm"/>
          ??????????????? <bean:define id="pageCountOb" property="pageCount" name="projectSearchForm"/>
          ??????????????? <%int currPage = ((Integer)(currPageOb)).intValue();
          ??????????????? int pageCount = ((Integer)(pageCountOb)).intValue();%>
          ??????????????? <%if(currPage>1){%>
          ?????? ?????????? <a href="javascript:firstPage();">首頁</a>
          ????????? ?? <a href="javascript:previousPage();">上一頁</a>
          ??????????????? <%}%>
          ??????????????? <%if(pageCount>currPage){%>
          ????????? ?? <a href="javascript:nextPage();">下一頁</a>
          ???????????????????? ?<a href="javascript:lastPage();">末頁</a>
          ??????????????? <%}%>
          ??????????????? 當(dāng)前頁:<%=currPage%>,
          ??????????????? 共<%=pageCount%>頁
          ????????????? </div>
          ???????????? </td>
          ??????? </tr>
          </table>
          <!------分頁----->
          ?
          </body>
          </html:html>
          界面顯示如下:
          ?
          1.1.1?????????? 創(chuàng)建項目信息
          執(zhí)行項目信息查詢列表顯示的文件請求處理順序如下:
          1、? ProjectListSearchAction
          2、? projectlist.jsp
          3、? ProjectFormLoadAction
          4、? projectform.jsp
          5、? ProjectFormSaveAction
          6、? success.jsp or failed.jsp
          7、? ProjectListSearchAction
          ?
          ProjectFormLoadAction內(nèi)容如下:
          package com.ort.strutsdemo.simpledemo.controller;
          ?
          ?
          /**
          ?* <p>Title: Struts Training </p>
          ?* <p>Description: Struts內(nèi)部培訓(xùn)Demo</p>
          ?* <p>Copyright: Copyright (c) 2004</p>
          ?* <p>Company: </p>
          ?* @author Liuz
          ?* @version 1.0
          ?*/
          import org.apache.struts.action.*;
          import javax.servlet.http.*;
          import com.ort.strutsdemo.simpledemo.business.BusinessDelegate;
          import com.boss.module.operation.object.Project;
          import com.ort.strutsdemo.simpledemo.Constants;
          import com.ort.strutsdemo.simpledemo.controller.exception.ExceptionBean;
          import com.ort.strutsdemo.simpledemo.ui.ProjectForm;
          import com.boss.module.operation.object.searchresult.help.ResultSetIterator;
          ?
          public class ProjectFormLoadAction
          ??? extends Action {
          ? BusinessDelegate businessDelegate = null;
          ? public ActionForward execute(ActionMapping actionMapping,
          ?????????????????????????????? ActionForm actionForm,
          ?????????????????????????????? HttpServletRequest request,
          ?????????????????????????????? HttpServletResponse response) {
          ??? businessDelegate = BusinessDelegate.getInstance();
          ??? DynaActionForm form = (DynaActionForm)actionForm;
          ??? String action = (String)form.get("action");
          ??? String projectCode = (String)form.get("projectCode");
          ??? try {
          ??????? Project project = null;
          ??????? if ( ("create".equals(action))) {
          ??????????? project = new Project();
          ??????? }
          ??????? else {
          ??????????? project = businessDelegate.getProject(projectCode);
          ??????? }
          ??????? project.setAction(action);
          ??????? ProjectForm modifyForm = new ProjectForm();
          ??????? org.apache.commons.beanutils.PropertyUtils.copyProperties(
          ??????????? modifyForm, project);
          ??????? if (! ("create".equals(action))) {
          ??????????? modifyForm.setSiteCode(project.getSite().getSiteCode());
          ??????? }
          ??????? request.setAttribute(Constants.PROJECT_SINGLEFORM_KEY, modifyForm); //為下一個頁面,即projectform.jsp的顯示提供數(shù)據(jù)
          ??????? //裝載當(dāng)前頁面所需要顯示小區(qū)信息
          ??????? ResultSetIterator siteIterator = businessDelegate.getSitesIterator();
          ??????? java.util.List sites = siteIterator.getElements(1);
          ??????? request.getSession().setAttribute(Constants.SITE_LISTFORM_KEY,
          ????????????????????????????????????????? sites);
          ?
          ??????? return actionMapping.findForward("success");
          ??? }
          ??? catch (Exception ex) {
          ??????? com.ipbs.util.Log.println("[ProjectFormLoadAction.java][Exception]:"+ex.getMessage());
          ??????? ExceptionBean exception = new ExceptionBean();
          ??????? exception.setErrorMsg(Constants.getExceptionMsg(ex));
          ??????? exception.setReturnPath(actionMapping.findForward("failed.return").getPath());
          ??????? request.setAttribute(Constants.EXCEPTION_BEAN,exception);
          ??????? return actionMapping.findForward("failed");
          ??? }
          ? }
          }
          ?
          projectform.jsp內(nèi)容如下:
          <%
          /**
          ?* 文件名:projectform.jsp
          ?* 描述:在執(zhí)行添加、修改操作之前,需要提供一個form供用戶輸入數(shù)據(jù),在執(zhí)行刪除操作之前,
          ?*???? 需要提供一個form將被刪除數(shù)據(jù)顯示出來,供用戶確認。該jsp頁面就是用來滿足這些需要,
          ?*???? 提供對單條項目信息的顯示,根據(jù)具體的操作類型(創(chuàng)建、修改、刪除),數(shù)據(jù)被顯示在可編
          ?*???? 輯的輸入控件中或不可編輯的
          ?*
          ?*+------------------------------------------------------------------------------
          ?* 更改歷史
          ?* 更改時間?????????????????? 更改人??????? 目標(biāo)版本???????????? 更改內(nèi)容
          ?*+------------------------------------------------------------------------------
          ?* 2004-04-21 16:09????????? liuz???????? 1.00.000????????????? 創(chuàng)建
          ?*
          ?*
          ?*/
          %>
          <%@ page contentType="text/html; charset=GB2312" %>
          <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
          <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
          <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
          <html>
          <head>
          <title>
          <logic:equal value="modify" property="action"? name="projectForm">
          ??? <bean:message key="project.project_modify"/>
          </logic:equal>
          <logic:equal value="create" property="action" name="projectForm">
          ? <bean:message key="project.project_create"/>
          </logic:equal>
          <logic:equal value="delete" property="action" name="projectForm">
          ? <bean:message key="project.project_delete"/>
          </logic:equal>
          </title>
          <link href="css/main.css" rel="stylesheet" type="text/css">
          <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
          </head>
          <body bgcolor="#ffffff">
          ?
          <html:form action="/projectformsave" method="post" onsubmit="return validateProjectForm(this);">
          ? <table width="70%"? border="0" align="center" cellpadding="3" cellspacing="1" class="tablebodycolor">
          ??? <tr class="tdbodycolor">
          ????? <td colspan="2" class="tdheadcolor">
          ????????? <logic:equal value="modify" property="action" name="projectForm">
          ????? ??<bean:message key="project.project_modify"/>
          ????????? </logic:equal>
          ????????? <logic:equal value="create" property="action" name="projectForm">
          ????????????? <bean:message key="project.project_create"/>
          ????????? </logic:equal>
          ????????? <logic:equal value="delete" property="action" name="projectForm">
          ????????????? <bean:message key="project.project_delete"/>
          ????????? </logic:equal>
          ????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td width="15%"><div align="right"><bean:message key="project.projectcode"/></div></td>
          ????? <td width="85%">
          ????????? <logic:equal value="modify" property="action" name="projectForm">
          ????? ??<html:hidden property="projectCode" write="true"/>
          ????????? </logic:equal>
          ????????? <logic:notEqual value="modify" property="action" name="projectForm">
          ????????????? <html:text styleClass="input" maxlength="10" property="projectCode" size="30"/>
          ????????? </logic:notEqual>
          ????????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td><div align="right"><bean:message key="project.projectname"/></div></td>
          ????? <td><html:text styleClass="input" maxlength="30" property="projectName" size="30"/></td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td><div align="right"><bean:message key="project.discount"/></div></td>
          ????? <td><html:text styleClass="input" maxlength="10" property="discount" size="10"/>
          ????? %</td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td><div align="right"><bean:message key="project.site"/></div></td>
          ????? <td>
          ????????? <html:select property="siteCode">
          ????????????? <html:options? collection="SITES"? labelProperty="siteName"? property="siteCode"/>
          ????????? </html:select>
          ????? </td>
          ??? </tr>
          ??? <tr class="tdbodycolor">
          ????? <td colspan="2"><div align="center">
          ????????? <html:hidden property="action" />
          ??????? <html:submit><bean:message key="button_submit"/></html:submit>
          ???????????? <html:cancel><bean:message key="button_cancel"/>
          ???????????? </html:cancel>
          ????? </div></td>
          ??? </tr>
          ? </table>
          </html:form>
          <html:javascript formName="projectForm"
          ??????? dynamicJavascript="true"
          ???????? staticJavascript="false"/>
          <script language="Javascript1.1" src="staticJavascript.jsp"></script>
          </body>
          </html>
          界面顯示效果如下:
          ?圖6.3.2.1 修改項目圖
          ?圖6.3.2.2 添加項目圖
          ?圖6.3.2.3 刪除確認圖
          最后,信息新增、修改或刪除確認后,需要提交給ProjectFormSaveAction進行,ProjectFormSaveAction內(nèi)容如下:
          package com.ort.strutsdemo.simpledemo.controller;
          ?
          import org.apache.struts.action.*;
          import javax.servlet.http.*;
          import com.ort.strutsdemo.simpledemo.business.BusinessDelegate;
          import com.boss.module.operation.object.Project;
          import com.boss.module.operation.object.Site;
          import com.ort.strutsdemo.simpledemo.Constants;
          import com.ort.strutsdemo.simpledemo.ui.ProjectForm;
          import com.ort.strutsdemo.simpledemo.controller.exception.ExceptionBean;
          import com.ipbs.util.web.ParamUtils;
          /**
          ?*
          ?* <p>Title: Struts Training </p>
          ?* <p>Description: 項目管理功能頁面的導(dǎo)向,以及頁面所需要數(shù)據(jù)的初始化,同時,處理刪除操作</p>
          ?* <p>Copyright: Copyright (c) 2004</p>
          ?* <p>Company: </p>
          ?* @author Liuz
          ?* @version 1.0
          ?*/
          public class ProjectFormSaveAction
          ??? extends Action {
          ? BusinessDelegate businessDelegate = null;
          ? public ActionForward execute(ActionMapping actionMapping,
          ?????????????????????????????? ActionForm actionForm,
          ?????????????????????????????? HttpServletRequest request,
          ?????????????????????????????? HttpServletResponse response) {
          ??? businessDelegate = BusinessDelegate.getInstance();
          ??? ProjectForm form = (ProjectForm)actionForm;
          ??? ActionForward forward = null;
          ??? String action = form.getAction();
          ??? if (this.isCancelled(request)) {
          ??????? return (actionMapping.findForward("cancel"));
          ??? }
          ??? if("modify".equals(action)){
          ??????? forward = modifyProject(actionMapping, actionForm,
          ?????????????????????????????????????????? request, response);
          ??? }
          ??? else if ("create".equals(action)) {
          ????? forward = createProject(actionMapping, actionForm,request, response);
          ??? }else if("delete".equals(action)){
          ?????? forward = deleteProject(actionMapping, actionForm,request, response);
          ??? }
          ??? return forward;
          ? }
          ?
          ?
          ? public ActionForward modifyProject(ActionMapping actionMapping,
          ???????????????????????????????????? ActionForm actionForm,
          ??????????????????????????????????? HttpServletRequest request,
          ??????????????????????????????????? HttpServletResponse response
          ??????????????????????????????????? )
          {
          ???? ProjectForm form = (ProjectForm) actionForm;
          ???? String projectCode = form.getProjectCode();
          ???? String projectName = form.getProjectName();
          ???? String siteCode = form.getSiteCode();
          ???? double discount = form.getDiscount();
          ????? try{
          ????????? Site site = businessDelegate.getSite(siteCode);
          ????????? Project project = new Project();
          ????????? project.setProjectCode(projectCode);
          ????????? project.setProjectName(projectName);
          ????????? project.setDiscount(discount);
          ????????? project.setSite(site);
          ????????? businessDelegate.modifyProject(project);
          ????????? return actionMapping.findForward("success");
          ????? }catch(Exception ex){
          ????????? com.ipbs.util.Log.println(
          ????????????? "[ProjectFormSaveAction.java][Exception]:" + ex.getMessage());
          ????????? ExceptionBean exception = new ExceptionBean();
          ????????? exception.setErrorMsg(Constants.getExceptionMsg(ex));
          ????????? exception.setReturnPath(actionMapping.getPath());
          ????????? request.setAttribute(Constants.EXCEPTION_BEAN, exception);
          ????????? return actionMapping.findForward("failed");
          ????? }
          ? }
          ?
          ? public ActionForward createProject(ActionMapping actionMapping,
          ???????????????????????????????????? ActionForm actionForm,
          ??????????????????????????????????? HttpServletRequest request,
          ??????????????????????????????????? HttpServletResponse response
          ??????????????????????????????????? ) {
          ???? ProjectForm form = (ProjectForm) actionForm;
          ???? String projectCode = form.getProjectCode();
          ???? String projectName = form.getProjectName();
          ???? String siteCode = form.getSiteCode();
          ???? double discount = form.getDiscount();
          ???? try{
          ???????? Site site = businessDelegate.getSite(siteCode);
          ???????? Project project = new Project();
          ???????? project.setProjectCode(projectCode);
          ???????? project.setProjectName(projectName);
          ???????? project.setDiscount(discount);
          ???????? project.setSite(site);
          ???????? businessDelegate.createProject(project);
          ???????? return actionMapping.findForward("success");
          ???? }catch(Exception ex){
          ???????? com.ipbs.util.Log.println(
          ????????????? "[ProjectFormSaveAction.java][Exception]:" + ex.getMessage());
          ????????? ExceptionBean exception = new ExceptionBean();
          ????????? exception.setErrorMsg(Constants.getExceptionMsg(ex));
          ????????? exception.setReturnPath(actionMapping.getPath());
          ????????? request.setAttribute(Constants.EXCEPTION_BEAN, exception);
          ????????? return actionMapping.findForward("failed");
          ???? }
          ? }
          ?
          ? public ActionForward deleteProject(ActionMapping actionMapping,
          ???????????????????????????????????? ActionForm actionForm,
          ??????????????????????????????????? HttpServletRequest request,
          ??????????????????????????????????? HttpServletResponse response
          ??????????????????????????????????? ) {
          ???? ProjectForm form = (ProjectForm)actionForm;
          ???? String projectCode = form.getProjectCode();
          ???? try{
          ???????? businessDelegate.deleteProject(projectCode);
          ???????? request.removeAttribute(Constants.PROJECT_SINGLEFORM_KEY);
          ???????? return actionMapping.findForward("success");
          ???? }catch(Exception ex){
          ???????? com.ipbs.util.Log.println(
          ???????????? "[ProjectControllerAction.java][Exception]:" + ex.getMessage());
          ???????? ExceptionBean exception = new ExceptionBean();
          ???????? exception.setErrorMsg(Constants.getExceptionMsg(ex));
          ???????? exception.setReturnPath(actionMapping.findForward("failed.return").getPath());
          ???????? request.setAttribute(Constants.EXCEPTION_BEAN,exception);
          ???????? return actionMapping.findForward("failed");
          ?
          ???? }
          ? }
          ?
          }
          至此為止,該示例項目所使用的絕大部分內(nèi)容已經(jīng)介紹完了,因為時間問題,沒有對示例程序進行很詳細的一一講解,代碼上有些簡單的注釋,希望你能夠看明白,如果大家對以上代碼有疑問會發(fā)現(xiàn)什么問題,可以發(fā)郵件和我溝通(
          lzasp800@sina.com),另外,我保證上面的代碼是真實可運行的,如果用心看,也是可以看明白的(當(dāng)然只有文章中所列的代碼是無法通過編譯的)。
          個人覺得,做Struts項目非常重要的一個環(huán)節(jié)就是請求處理流程設(shè)計,這也是本示例強調(diào)的重點,弄清楚了這一點,看代碼也會容易很多。
          1.1.1?????????? 修改項目信息
          請求處理流程如下,具體文件內(nèi)容請查看前述內(nèi)容:
          1、? ProjectListSearchAction
          2、? projectlist.jsp
          3、? ProjectFormLoadAction
          4、? projectform.jsp
          5、? ProjectFormSaveAction
          6、? success.jsp or failed.jsp
          7、? ProjectListSearchAction
          ?
          1.1.2?????????? 刪除項目信息
          請求處理流程如下,具體文件內(nèi)容請查看前述內(nèi)容:
          1、? ProjectListSearchAction
          2、? projectlist.jsp
          3、? ProjectFormLoadAction
          4、? projectform.jsp
          5、? ProjectFormSaveAction
          6、? success.jsp or failed.jsp
          7、? ProjectListSearchAction
          ?

          ?

          posted on 2006-06-28 14:22 程序-人生 閱讀(4807) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 荔浦县| 广德县| 泰和县| 桃园市| 荣成市| 平遥县| 常德市| 赣州市| 枣庄市| 壤塘县| 永登县| 开鲁县| 永康市| 阜南县| 禹州市| 西华县| 海宁市| 郑州市| 苏尼特右旗| 林口县| 福海县| 石嘴山市| 彝良县| 英德市| 武义县| 平山县| 成都市| 庐江县| 囊谦县| 株洲县| 阳原县| 邻水| 石河子市| 禹城市| 潼南县| 达尔| 容城县| 稷山县| 兴安盟| 孝义市| 盖州市|