1. 程式人生 > >struts2學習筆記(三)—— struts2的常見配置

struts2學習筆記(三)—— struts2的常見配置

一、配置檔案的載入順序

  每次從客戶端傳送請求到伺服器都要先經過Struts2的核心過濾器StrutsPrepareAndExecuteFilter,這個過濾器有兩個功能:預處理和執行。在預處理中主要就是來載入配置檔案的。對應的是過濾器中的init方法,而執行是用來執行一組攔截器完成部分功能的,對應的是過濾器的doFilter方法。所以我們如果要去了解Struts2的配置檔案的載入順序,那麼我們需要查詢過濾器的init方法。

  

  在init方法中,呼叫了init的initDispatcher方法來載入配置檔案,進入到該程式碼中:

  

  我們發現這個方法又呼叫了dispatcher的init方法,進入init方法內部:

  

  這一系列程式碼就是用來載入Struts2的配置檔案的

 init_DefaultProperties(); // 載入org.apache.struts.default.properties,裡面配置的是struts2的所有常量
 init_TraditionalXmlConfigurations(); // 載入struts-default.xml、struts-plugin.xml、struts.xml
 init_LegacyStrutsProperties(); // 載入使用者自定義的struts.properties
 init_CustomConfigurationProviders(); //
載入使用者配置的提供物件 init_FilterInitParameters() ; // 載入web.xml init_AliasStandardObjects() ; // 載入標準物件

  根據上面的程式碼我們可以得出配置的載入順序為

* default.properties
* struts-default.xml
* struts-plugin.xml
* struts.xml			--- 配置Action以及常量(******)
* struts.properties		--- 配置常量
* web.xml			--- 配置核心過濾器及常量

   前三個配置檔案我們不用關心,是Struts2內部的配置檔案,我們無法修改,能修改的檔案就是struts.xml,struts.properties,web.xml。這幾個配置檔案的載入是有一定順序的。這三個配置檔案都可以修改Struts2的常量的值,要記住的是,後加載配置檔案中常量的值會將先載入的配置檔案中常量的值給覆蓋

二、struts.xml配置

  struts.xml是struts2的核心配置檔案,該檔案主要用來配置Action和請求的對應關係。

<!-- package:將Action配置封裝.就是可以在Package中配置很多action.
         name屬性: 給包起個名字,起到標識作用.隨便起.不能其他包名重複.
         namespace屬性:給action的訪問路徑中定義一個名稱空間
         extends屬性: 繼承一個指定包,通常都設定為struts-default,這樣該包中的Action就具有了Struts2框架預設的攔截器等功能了
         abstract屬性:包是否為抽象的; 標識性屬性.標識該包不能獨立執行.專門被繼承
      -->
    <package name="hello" namespace="/hello" extends="struts-default" >
        <!-- action元素:配置action類
             name屬性: 決定了Action訪問資源名.(name屬性和namespace屬性共同決定了訪問路徑)
             class屬性: action的完整類名
             method屬性: 指定呼叫Action中的哪個方法來處理請求,預設是execute方法
         -->
        <action name="HelloAction" class="cn.itheima.a_hello.HelloAction" method="hello" >
            <!-- result元素:結果配置 
                 name屬性: 標識結果處理的名稱.與action方法的返回值對應.
                 type屬性: 指定呼叫哪一個result類來處理結果,預設使用轉發.
                 標籤體:填寫頁面的相對路徑
            -->
            <result name="success" type="dispatcher" >/hello.jsp</result>
        </action>
    </package>
    <!-- 引入其他struts配置檔案 -->
    <include file="cn/itheima/b_dynamic/struts.xml"></include>

三、struts2常量配置

3.1 struts2預設常量配置位置

  

3.2 常量配置的方式

  • 在struts.xml檔案中通過<constant>元素配置常量最常用
    <!-- i18n:國際化. 解決post提交亂碼 -->
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    <!-- 指定訪問action時的字尾名 
        http://localhost:8080/struts2_day01/hello/HelloAction.do
    -->
    <constant name="struts.action.extension" value="action"></constant>
    <!-- 指定struts2是否以開發模式執行
            1.熱載入主配置.(不需要重啟即可生效)
            2.提供更多錯誤資訊輸出,方便開發時的除錯
     -->
    <constant name="struts.devMode" value="true"></constant>

     struts.properties檔案能配置的常量都可以在struts.xml中用<constant>元素來配置

  • 在struts.properties檔案中配置常量

    

  注意:和struts.xml一樣,struts.properties檔案也應該放在src目錄下

  • 在web.xml中通過初始化引數配置常量
    <!-- 配置常量 -->
      <context-param>
          <param-name>struts.i18n.encoding</param-name>
          <param-value>UTF-8</param-value>
      </context-param>

  之前我們介紹過Struts2配置檔案的載入順序(struts.xml>struts.properties>web.xml),後加載的配置檔案的常量的值會覆蓋先載入的配置檔案中常量的值。所以這個地方要注意。

四、分模組開發的配置

  在實際開發中我們更習慣使用struts.xml修改struts2的常量。但是這樣就會有一個問題,如果一個專案是團隊開發的,也就是很多人開發的,那麼團隊中的很多人就都需要去修改同一個struts.xml,因為這個檔案是Struts2的核心配置檔案。而這個檔案一旦改錯了一點,就會導致整個專案都會出現問題,所以struts2也支援分模組開發的配置,它提供了<include>標籤來解決這個問題。

  <include>元素用來在一個struts.xml配置檔案中包含其他的配置檔案,包含配置體現的是軟體工程中的“分而治之”原則。Struts2允許將一個配置檔案分解成多個配置檔案,從而提高配置檔案的可讀性。

  <!-- 包含了3個配置檔案 -->
    <!-- 不指定路徑,預設在src下 -->
    <include file="struts-shop.xml"/>
    <include file="struts-user.xml"/>
    <!-- 配置檔案在具體包中 -->
    <include file="cn/itcast/action/struts-product.xml"/>

  上面的3個配置檔案中,前兩個沒有指定檔案的所在路徑,表示該檔案在專案的src路徑下,如果配置檔案在具體的包中,那麼引入配置檔案時,需要包含檔案所在包的路徑。

  需要注意的是,每一個被包含的配置檔案都是標準的Struts2配置檔案,一樣包含DTD資訊、Struts2配置檔案的根元素資訊等。通過將Struts2的所有配置檔案都放在web專案的WEB-INF/classes路徑下,struts.xml檔案包含了其他的配置檔案,在Struts2框架自動載入struts.xml檔案時,完成載入所有的配置資訊。

五、Action類的配置

  在Struts2的應用開發中,Action作為框架的核心類,實現對使用者請求的處理,Action類被稱為業務邏輯控制器。一個Action類代表一次請求或呼叫,每個請求的動作都對應一個響應的Action類,一個Action類是一個獨立的工作單元。也就是說,使用者的每次請求,都會轉到一個響應的Action類裡面,由這個Action類來進行處理。簡而言之,Action就是用來處理一次使用者請求的物件

5.1 Action的編寫方式

【Action是一個POJO類】

  在Struts2中,Action可以不繼承特殊的類或不實現任何特殊的介面,僅僅是一個POJO。POJO全稱Plain Ordinary Java Object(簡單的Java物件),只要具有一部分getter/setter方法的那種類,就可以稱作POJO。一般在這個POJO類中,要有一個公共的無參的構造方法(採用預設的構造方法就可以)和一個execute()方法。定義格式如下:

public class ActionDemo1 {

    public String execute() {
        System.out.println("ActionDemo1執行了。。。");
        return null;
    }
}

  execute()方法的要求如下:

    • 方法的許可權修飾符為public
    • 返回一個字串,就是指示的下一個頁面的Result
    • 方法沒有引數

  也就是說,滿足上述要求的POJO都可算作是Struts2的Action實現。

【Action類實現一個Action的介面】 

   為了讓使用者開發的Action類更規範,Struts2提供一個Action介面,使用者在實現Action控制類時,可以實現Struts2提供的這個Action介面。

  Action介面定義了Struts的Action處理類應該實現的規範,Action介面中的具體程式碼如下所示。

public class ActionDemo2 implements Action{

    public String execute() {
        System.out.println("ActionDemo2執行了。。。");
        return null;
    }
}

   從上述程式碼中可以看出,Action介面位於com.opensymphony.xwork2包中。這個接口裡只定義了一個execute()方法,該方法返回一個字串。除此之外,該介面還定義了5個字串常量,它們的作用是統一execute()方法的返回值。

    

  由於Xwork的Action介面簡單,為開發者提供的幫助較小,所以在實際開發過程中,Action類很少直接實現Action介面。

【Action類繼承ActionSupport類】(推薦)

public class ActionDemo3 extends ActionSupport{

    public String execute() {
        System.out.println("ActionDemo3執行了。。。");
        return null;
    }
}

 

   ActionSupport類本身實現了Action介面,是Struts2中預設的Action介面實現類,所以繼承ActionSupport就相當於實現了Action介面。ActionSupport類還實現了Validateable、ValidationAware、TextProvider、LocaleProvider和Serializable等介面,為使用者提供更多的功能。

  ActionSupport類提供了許多預設方法,這些預設方法包括獲取國際化資訊的方法、資料校驗的方法、預設的處理使用者請求的方法等。實際上,ActionSupport類是Struts2預設的Action處理類,如果讓開發者的Action類繼承該ActionSupport類,則會大大簡化Action的開發。

5.2 Action的訪問

  Action的訪問不是難題,因為之前已經訪問過了,但是出現一個問題:一次請求現在對應一個Action,那麼如果請求很多就會對應多個Action。現在要處理的問題就是要讓一個模組的操作提交到一個Action中。我們可以通過<action>標籤中的method屬性來指定Action中某個方法的執行。

【方式一:通過配置method屬性完成】

  • 編寫頁面:
    <h2>客戶的管理</h2>
        <a href="${pageContext.request.contextPath }/saveCustomerAction.action">新增客戶</a><br>
        <a href="${pageContext.request.contextPath }/updateCustomerAction.action">修改客戶</a><br>
        <a href="${pageContext.request.contextPath }/deleteCustomerAction.action">刪除客戶</a><br>
        <a href="${pageContext.request.contextPath }/findCustomerAction.action">查詢客戶</a><br>
  • 編寫Action:
    public class CustomerAction extends ActionSupport{
        public String save(){
            System.out.println("CustomerAction中的save方法執行了...");
            return NONE;
        }
        
        public String delete(){
            System.out.println("CustomerAction中的delete方法執行了...");
            return NONE;
        }
        public String update(){
            System.out.println("CustomerAction中的update方法執行了...");
            return NONE;
        }
        public String find(){
            System.out.println("CustomerAction中的find方法執行了...");
            return NONE;
        }
    }
  • 配置Action:
    <package name="demo3" namespace="/" extends="struts-default">
       <action name="saveCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="save"></action>
      <action name="deleteCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="delete"></action>
       <action name="updateCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="update"></action>
       <action name="findCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="find"></action>
    </package>

     但是這種方法我們發現,同一個Action類被配置了很多次,只是修改了後面的method的值。那麼能不能配置簡單化呢?也就是一個Action類,只配置一次就好?這個時候我們就需要使用萬用字元的配置方式了。

【方式二:通過萬用字元的配置完成】(開發中常用)

  • 編寫頁面
    <h2>聯絡人的管理</h2>
        <a href="${pageContext.request.contextPath }/linkMan_save.action">新增聯絡人</a><br>
        <a href="${pageContext.request.contextPath }/linkMan_update.action">修改聯絡人</a><br>
        <a href="${pageContext.request.contextPath }/linkMan_delete.action">刪除聯絡人</a><br>
        <a href="${pageContext.request.contextPath }/linkMan_find.action">查詢聯絡人</a><br>
  • 編寫Action
    public class LinkManAction extends ActionSupport {
        public String save(){
            System.out.println("儲存聯絡人...");
            return NONE;
        }
        
        public String delete(){
            System.out.println("刪除聯絡人...");
            return NONE;
        }
        
        public String update(){
            System.out.println("修改聯絡人...");
            return NONE;
        }
        
        public String find(){
            System.out.println("查詢聯絡人...");
            return NONE;
        }
    }
  • 配置Action
    <!-- 萬用字元的配置 -->
    <action name="linkman_*" class="cn.itcast.struts2.action.LinkManAction" method="{1}"></action>

  在<action>的name屬性中使用的*代表任意字元,method中的{1}代表name屬性中出現的第一個*所代替的字元。

  這個時候我們就只配置一個就可以了,在上述程式碼中,當客戶端傳送/linkman_save.action這樣的請求時,action元素的name屬性就被設定成linkman_save,method屬性就被設定成save。當客戶端傳送/linkman_update.action這樣的請求是,action元素的name屬性就被設定為linkman_update,method屬性也被設定成update。

【方式三:動態方法訪問】(瞭解)

  動態方法訪問在Struts2中預設是不開啟的,如果想要使用,需要先去struts.xml中開啟一個常量。

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

  動態方法訪問主要的控制是在頁面端,所以編寫Action和配置Action都很簡單,關鍵是訪問路徑的編寫。

  • 編寫Action
    public class UserAction extends ActionSupport {
        public String save(){
            System.out.println("儲存使用者...");
            return NONE;
        }
        
        public String delete(){
            System.out.println("刪除使用者...");
            return NONE;
        }
        
        public String update(){
            System.out.println("修改使用者...");
            return NONE;
        }
        
        public String find(){
            System.out.println("查詢使用者...");
            return NONE;
        }
    }
  • 配置Action
    <!-- 動態方法訪問的配置 -->
    <action name="userAction" class="cn.itcast.struts2.action.UserAction"></action>
  • 頁面路徑的寫法
    <h2>使用者的管理</h2>
    <a href="${pageContext.request.contextPath }/userAction!save.action">新增使用者</a><br>
    <a href="${pageContext.request.contextPath }/userAction!update.action">修改使用者</a><br>
    <a href="${pageContext.request.contextPath }/userAction!delete.action">刪除使用者</a><br>
    <a href="${pageContext.request.contextPath }/userAction!find.action">查詢使用者</a><br>