官术网_书友最值得收藏!

2.1 MVC框架的王者:Struts 2

Struts 2是當今最吸引眼球,也是使用最廣泛的基于Java的MVC框架。該框架比其前身Struts 1.x更強大,也更容易使用。雖然Struts 2是Struts 1.x的升級版,但在技術實現上幾乎和Struts 1.x一點關系都沒有。實際上,Struts 2是從Webwork發展而來的。Struts 2借用了Struts的知名度和Webwork的優良的設計和理念,成為新的MVC框架的王者。

2.1.1 Struts 2與MVC模式

MVC這個詞也許很多讀者并不陌生,可能耳朵都聽得磨出繭子來了。MVC實際上是三個英文單詞的首字母的組合。M表示Model(模型), V表示View(視圖), C表示Controller (控制器)。基于MVC模式的應用程序從邏輯上被分為Model-View-Controller三部分。也可以換句話說,所有從邏輯上可以分成Model-View-Controller三部分的應用程序都是基于MVC模式的(包括B/S和C/S結構的應用程序)。

那么MVC的這三個部分到底有什么作用呢?讓我們先來回顧一下傳統的Java Web程序是如何設計的。在MVC模式受到廣泛關注之前,我們可能會這樣設計Web應用程序。

在工程中建立很多的JSP頁面和Servlet類。Web程序的用戶接口主要是JSP頁面,那么網頁設計人員就用各種工具設計了很漂亮的JSP頁面(有可能是HTML頁面,然后由開發人員將這些頁面轉成JSP頁面)。下一步,也是最核心的一步,就是為系統添加業務邏輯。開發人員可能會在JSP中添加大量的JSTL標簽以及Java代碼來處理需要動態生成的頁面元素。當JSP頁面需要提交請求時,會提交給另一個JSP頁面,也可能會提交給Servlet。然后在這些JSP頁面或Servlet中處理相應的業務邏輯(包括訪問數據庫等操作),最后返回給JSP頁面,并以用戶期望的格式顯示處理結果。

從上面的處理過程來看,并沒有什么不妥。但如果要發生下面的情況應該怎么辦呢?

當JSP頁面的顯示風格有變化時,可能會修改原來的代碼。例如,在JSP頁面中原來是以列表的方式顯示處理結果的,但現在要以樹形結構顯示處理結果。在這種情況下,修改JSP頁面是必然的,但服務端程序(JSP頁面或Servlet)返回的數據格式有可能并不符合JSP頁面的要求,或者需要對返回的數據進一步加工才能滿足需求。這時如果按傳統的系統結構,就需要修改原來的JSP頁面或Servlet中的代碼。從技術上看,這么做沒有任何問題。但這也違背了設計模式的一個重要原則:對修改關閉,對擴展開放。也就是在添加或修改系統的功能時,應盡量采用擴展的方式,而不是修改原來的代碼。這樣做可以大大避免由于修改原來的代碼而引發的連鎖反應。

那么如果不修改服務端程序的代碼,應該如何做呢?聰明的程序員也許會想到另外一招。就是在服務端再添加一個Servlet(當然也可以使用JSP頁面,不過處理客戶端請求最好用Servlet),這個Servlet作為JSP頁面和處理業務邏輯的Servlet的橋梁。也就是說,JSP頁面并不直接將信息提交給處理業務邏輯的Servlet,而是提交給剛才新添加的Servlet。而由這個新添加的Servlet再訪問處理業務邏輯的Servlet。當需要對返回數據進行二次加工時,并不需要修改那個處理業務邏輯的Servlet,而只需要修改那個中間的Servlet的代碼即可。由于這個Servlet并不處理任何業務邏輯,而只是對返回的數據進行加工,因此,可以完全重寫這個Servlet。

對于JSP頁面來說,可以只向這個中間的Servlet提交信息。當服務端需要改變處理業務邏輯的模塊時,只需要修改這個中間的Servlet即可。而這一步對JSP頁面是完全透明的。從這一點可以看出,這個中間的Servlet起到了一個控制的作用。對于客戶端來說,可以控制服務端返回的數據。對于服務端來說,可以決定將客戶端提交過來的請求交給哪個服務端程序來處理。那么我們就可以將這個中間的Servlet看做是一個Controller(控制器)。這種模式也就是MVC模式。其中M可以看做處理業務邏輯的Servlet, V可以看做是采集用戶數據的JSP頁面,而C則可以看做是這個中間的Servlet。

在Struts 2中也采用了類似的方式,只是并不是用Servlet來實現的。在Struts 2中采用了過濾器的方式來截獲客戶端的請求,并根據請求來調用Struts 2中的控制器。Struts 2中的控制器也被稱為Action對象。Action對象可以是任何類的對象實例,包括POJO類。而Struts 2 MVC中的M也并不是Servlet,而是一個或多個處理業務邏輯的JavaBean的對象實例。讀者在2.1.3節將會看到MVC模式在Struts 2中的真實應用。

2.1.2 Struts 2最新版的下載與安裝

在筆者寫本書時,Struts 2的最新版本是Struts 2.1.6。讀者可以從下面的網址下載Struts 2的最新版本:

http://struts.apache.org

在下載完Struts 2的壓縮包后,將其解壓。在lib目錄中包含了當前Struts 2發行版所帶的所有jar文件。但基本的Struts 2應用程序只需要下面7個jar文件:

· struts2-core-2.1.6.jar

· xwork-2.1.2.jar

· struts2-convention-plugin-2.1.6.jar

· ognl-2.6.11.jar

· freemarker-2.3.13.jar

· commons-logging-1.0.4.jar

· commons-fileupload-1.2.1.jar

在找到上面7個jar文件后,將這些jar文件復制到WEB-INF\lib目錄中,并在WEB-INF\web.xml文件中添加如下的代碼:

          <filter>
              <filter-name>struts2</filter-name>
              <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAnd
          ExecuteFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>struts2</filter-name>
              <url-pattern>*.action</url-pattern>
          </filter-mapping>

2.1.3 通過一個計算加減法的Web程序來體驗MVC模式的好處

在這一節我們來做一個計算加減法的Struts 2應用程序。其中加法和減法分別由兩個模型(Model)類完成。這兩個模型類由Action類來調用。當JSP頁面采集了兩個操作數后,會將數據提交給Action,然后Action根據不同的需求調用加法或減法模型類來計算業務邏輯,并對處理結果進行二次加工。

1 編寫計算加法的模型類。

Addition類負責計算兩個操作數的加法,代碼如下:

          package net.blogjava.nokiaguy.models;
          public class Addition
          {
              public int add(int x, int y)
              {
              return x + y;
            }
        }

2 編寫計算減法的模型類。

Subtraction類負責計算兩個操作數的減法,代碼如下:

        package net.blogjava.nokiaguy.models;
        public class Subtraction
        {
            public int sub(int x, int y)
            {
            return x - y;
            }
        }

3 編寫CalcAction類。

CalcAction類是一個調用Addition和Subtraction類的Action類,代碼如下:

        package net.blogjava.nokiaguy.actions;
        import net.blogjava.nokiaguy.models.Addition;
        import net.blogjava.nokiaguy.models.Subtraction;
        public class CalcAction
        {
            //  獲得客戶端提交的兩個操作數的值
            private int operand1;
            private int operand2;
            //  向客戶端返回結果Action類加工過的處理結果
            private String result;
            .
            //  此處省略了屬性的getter和setter方法
            //  處理業務邏輯的方法
            public String execute()
            {
                  Addition addition = new Addition();
                //  調用add方法執行業務邏輯
                  int value = addition.add(operand1, operand2);
                  //  加工處理結果
                  result = operand1 +"+" + operand2 + "=" + value;
                  return "success";
            }
        }

從CalcAction類的代碼可以看出,在execute方法中只調用了Addition類。如果需要調用Subtraction類,可以修改execute方法,或將該方法名改成execute1,并另外寫一個execute方法來調用Subtraction。由于JSP頁面只向CalcAction類提交請求,而且只從result屬性中獲得處理結果。因此,服務端的業務邏輯切換對于客戶端(JSP頁面)是透明的。

4 配置struts.xml文件。

struts.xml文件是Struts 2中的核心文件。在src目錄中建立一個struts.xml文件,并輸入如下的內容:

        <? xml version="1.0" encoding="UTF-8" ? >
        <! DOCTYPE struts PUBLIC
              "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
              "http://struts.apache.org/dtds/struts-2.0.dtd">
        <struts>
            <package name="struts2" namespace="/" extends="struts-default">
                  <! --  配置CalcAction類  -->
                  <action name="calc" class="net.blogjava.nokiaguy.actions.CalcAction">
                      <result name="success">/WEB-INF/calc.jsp
                      </result>
                  </action>
                <! --  使用通配符為所有在WEB-INF目錄中的JSP頁面指定一個對應的Action  -->
                  <action name="*_jsp">
                      <result>/WEB-INF/{1}.jsp
                      </result>
                  </action>
            </package>
        </struts>

由于本例中所有的JSP頁面都放在了WEB-INF目錄中,而且該目錄中的資源不允許直接被客戶端訪問,因此,在這里需要使用通配符為每一個位于WEB-INF目錄中的JSP頁面指定一個對應的Action。比如在WEB-INF目錄中有一個calc.jsp頁面,那么可以通過如下的URL來訪問這個JSP頁面:

http://localhost:8080/sshregister/calc_jsp.action

5 編寫calc.jsp頁面。

calc.jsp頁面有兩個功能:采集兩個操作數和顯示處理結果。在WEB-INF目錄中建立一個calc.jsp頁面,并輸入如下的代碼:

        <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
        <! --  引用Struts 2的標簽庫  -->
        <%@ taglib prefix="s" uri="/struts-tags"%>
        <html>
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>計算器</title>
        </head>
        <body>
        <! --  顯示處理結果  -->
        <s:property value="result"/>
        <! --  顯示采集兩個操作數的表單,并向calc提交請求  -->
        <s:form action="calc">
          <s:textfield  label="操作數1" name="operand1" />
          <s:textfield  label="操作數2" name="operand2" />
          <s:submit value="計算"/>
        </s:form>
        </body>
        </html>

到現在為止,這個例子已經編寫完成了,啟動Tomcat后,在瀏覽器地址欄中輸入如下的URL:

http://localhost:8080/sshregister/calc_jsp.action在頁面中的兩個文本框中分別輸入43和56,單擊【計算】按鈕,將會顯示如圖2.1所示的頁面。

圖2.1 計算加法

如果將CalcAction類中的execute方法名改成execute1,并加入如下的execute方法:

          public String execute()
          {
              Subtraction subtraction = new Subtraction();
              //  調用sub方法執行業務邏輯
              int value = subtraction.sub(operand1, operand2);
              //  加工處理結果
              result = operand1 +"-" + operand2 + "=" + value;
              return "success";
          }

這時再單擊圖2.1所示頁面上的【計算】按鈕,則會顯示如圖2.2所示的頁面。

圖2.2 計算減法

從上面的測試過程可以看出,JSP頁面和模型類的代碼都未修改,而只修改的Action類(Controller)就可以改變JSP頁面的顯示結果,而且更改了服務端的業務邏輯。

主站蜘蛛池模板: 都匀市| 丰镇市| 连州市| 离岛区| 津市市| 佛学| 柯坪县| 黎川县| 海兴县| 呼和浩特市| 涿鹿县| 遂宁市| 乌审旗| 文登市| 大关县| 治多县| 锡林郭勒盟| 海南省| 凤山市| 化德县| 菏泽市| 安顺市| 桐梓县| 和硕县| 孟州市| 邢台县| 万安县| 丰县| 沂水县| 抚松县| 来安县| 东乌珠穆沁旗| 曲松县| 察隅县| 宜昌市| 崇仁县| 洪洞县| 赞皇县| 布尔津县| 新昌县| 沧州市|