struts2框架(四)攔截器,國際化,Ognl表達式

Intercetor, 即為攔截器。
1) 在Struts2中,把每一個功能都用一個個的攔截器實現;用戶想用struts的哪個功能的時候,可以自由組裝使用。
2)Struts2中,為了方法用戶對攔截器的引用,提供了攔截器棧的定義,里面可以包含多個攔截器。 文件夾(文件, 文件2) 攔截器棧(攔截器,攔截器2)
3)Struts2中,如果用戶沒有指定執行哪些攔截器,struts2有一個默認執行的棧,defaultStack;
一旦如果用戶有指定執行哪些攔截器,默認的攔截器棧就不會被執行
攔截器的設計,就是基于組件設計的應用!

1.自定義攔截器

1.1 編寫輔助測試用action

public class HelloAction extends ActionSupport{
    public HelloAction() {
        System.out.println("1. Action實例創建了");
    }
    
    @Override
    public String execute() throws Exception {
        System.out.println("3. 執行了請求處理的方法: execute");
        return super.execute();
    }
}

1.2 編寫攔截器類

public class HelloInterceptor implements Interceptor{
    
    // 啟動時候執行
    public HelloInterceptor(){
        System.out.println("創建了攔截器對象");
    }

    // 啟動時候執行
    @Override
    public void init() {
        System.out.println("執行了攔截器的初始化方法");
    }

    // 攔截器業務處理方法 (在訪問action時候執行? 在execute之前執行?)
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("2. 執行Action之前");
        
        // 調用下一個攔截器或執行Action  (相當于chain.doFilter(..)
        // 獲取的是: execute方法的返回值
        String resultFlag = invocation.invoke();
        
        System.out.println("4. 攔截器,業務處理-結束" + resultFlag);
        
        return resultFlag;
    }   

    @Override
    public void destroy() {
        System.out.println("銷毀....");
    }
}

1.3 進行相關配置

<struts>
    <package name="hello" extends="struts-default"> 
        <!-- 【攔截器配置】 -->
        <interceptors>      
            <!-- 配置用戶自定義的攔截器 -->
            <interceptor name="helloInterceptor" class="cn.itcast.a_interceptor.HelloInterceptor"></interceptor>
            
            <!-- 自定義一個棧: 要引用默認棧、自定義的攔截器 -->
            <interceptor-stack name="helloStack">
                <!-- 引用默認棧 (一定要放到第一行)-->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 引用自定義攔截器 -->
                <interceptor-ref name="helloInterceptor"></interceptor-ref>
            </interceptor-stack>            
        </interceptors>
                
        <!-- 【執行攔截器,第一種寫法: 當前包下所有的acntion都執行helloStack?!?
        <default-interceptor-ref name="helloStack"></default-interceptor-ref>
        -->
    
        <!-- Action配置 -->
        <action name="hello" class="cn.itcast.a_interceptor.HelloAction">
        
            <!--執行攔截器,第二種寫法: 只是在這一個Action中執行helloStack棧 
            <interceptor-ref name="defaultStackt"></interceptor-ref>
            <interceptor-ref name="helloInterceptor"></interceptor-ref>
            -->
            
            <!--執行攔截器,第三種寫法:執行用戶棧(與第二種寫法一樣, 只在當前aciton中執行自定義棧)-->
            <interceptor-ref name="helloStack"></interceptor-ref>            
        
            <result name="success">/index.jsp</result>
        </action>   
    
    </package>
</struts>

當我們訪問helloAction時效果如下:

可以看到,如過濾器一樣,攔截器的構造方法和初始化也是在tomcat服務器啟動時執行,當用戶訪問action時,先創建action實例,然后執行過濾器intercept方法,再執行action的execute方法,執行完后回到intercept。最扣在tomcat停止服務時會銷毀攔截器對象。生命周期時序圖如下:

2.國際化

對比servlet的國際化,struts里面更簡單

2.1 步驟

a). 寫資源文件
基礎名.properties  【默認的語言環境的配置】  
基礎名_語言簡稱_國家簡稱.properties
b). 讀取資源文件,再使用

程序:ResourceBundle (同servlet)
JSP:
1)jstl表親啊 (同servlet)
2)struts標簽獲取資源文件內容

2.2 實例

1. 寫資源文件

Msg.properties 默認的語言環境; 找不到配置就找它
Msg_en_US.properties 美國

2. 加載
<!-- struts.xml 通過常量加載資源文件 -->
    <constant name="struts.custom.i18n.resources" value="cn.acamy.config.msg"></constant>
3. 使用: 標簽name值直接寫配置文件中的key
<%@taglib uri="/struts-tags" prefix="s" %>
<s:text name="title"></s:text>
推薦用法:
  <s:i18n name="cn.acamy.config.msg">
        <s:text>  標簽必須放到標簽體中。
  </s:i18n>

3.Ognl表達式

OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。 Struts2框架使用OGNL作為默認的表達式語言。

3.1 OgnlContext 的用法

OGNL 有一個上下文(Context)概念,說白了上下文就是一個MAP結構,它實現了java.utils.Map 的接口。

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

import org.junit.Test;

// OgnlContext用法
public class OgnlDemo1 {

    /**
     * 1. Ognl表達式語言語言取值,取非根元素的值,必須用#號
     * @throws Exception
     */
    @Test
    public void testOgnl() throws Exception {
        // 創建一個Ognl上下文對象
        OgnlContext context = new OgnlContext();
        // 放入數據
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往非根元素放入數據, 取值的時候表達式要用"#"】
        context.put("user", user);
        
        // 獲取數據(map)
        // 先構建一個Ognl表達式, 再解析表達式
        Object ognl = Ognl.parseExpression("#user.name");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        
        System.out.println(value);
    }
    
    /**
     * 2. Ognl表達式語言語言取值,取根元素的值,不用帶#號
     * @throws Exception
     */
    @Test
    public void testOgn2() throws Exception {
        // 創建一個Ognl上下文對象
        OgnlContext context = new OgnlContext();
        // 放入數據
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往根元素放入數據】
        context.setRoot(user);
        
        // 獲取數據(map)
        // 先構建一個Ognl表達式, 再解析表達式
        Object ognl = Ognl.parseExpression("address.province");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        
        System.out.println(value);
    }
    
    /**
     * 3.Ognl對 靜態方法調用的支持
     * @throws Exception
     */
    @Test
    public void testOgn3() throws Exception {
        // 創建一個Ognl上下文對象
        OgnlContext context = new OgnlContext();
        
        // Ognl表單式語言,調用類的靜態方法
        //Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
        // 由于Math類在開發中比較常用,所以也可以這樣寫
        Object ognl = Ognl.parseExpression("@@floor(10.9)");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        System.out.println(value);
    }
}

3.2 ValueStack

ValueStack實際是一個接口,在Struts2中利用OGNL時,實際上使用的是實現了該接口的OgnlValueStack類,這個類是Struts2利用OGNL的基礎。
ValueStack貫穿整個 Action 的生命周期(每個 Action 類的對象實例都擁有一個ValueStack 對象). 相當于一個數據的中轉站. 在其中保存當前Action 對象和其他相關對象.Struts2框架把 ValueStack 對象保存在名為 “struts.valueStack” 的request請求屬性中。

3.2.1 ValueStack的獲取

    // 獲取值棧對象的2種方式
    private void getVs() {
        // 獲取值棧對象,方式1:
        HttpServletRequest request = ServletActionContext.getRequest();
        ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");

        // 獲取值棧對象,方式2:
        ActionContext ac = ActionContext.getContext();
        ValueStack vs2 = ac.getValueStack();

        System.out.println(vs1 == vs2);// true
    }

3.2.2 ValueStack的數據結構

通過調試可以看到:struts中的ValueStack為其實現類OgnlValueStack,核心包含了作為Map棧的OgnlContext對象和繼承了ArrayList的對象棧的CompoudRood對象,其中OgnlContext還封裝了CompoudRood對象。

數據結構圖如下:

對象棧: Struts  把動作和相關對象壓入 ObjectStack 中--List
Map棧: Struts 把各種各樣的映射關系(一些 Map 類型的對象) 壓入 ContextMap 中
    Struts 會把下面這些映射壓入 ContextMap 中
        parameters: 該 Map 中包含當前請求的請求參數
        request: 該 Map 中包含當前 request 對象中的所有屬性
        session: 該 Map 中包含當前 session 對象中的所有屬性
        application:該 Map 中包含當前 application  對象中的所有屬性
        attr: 該 Map 按如下順序來檢索某個屬性: request, session, application

3.3 Ognl表達式

3.3.1 #的作用

a) 用來區分訪問的是Map棧不審List棧

 #號主要用于訪問訪問Map棧信息,不使用#號主要用于訪問List(對象棧)信息。
 舉例:
      <s:property value="#request.username"/>
      <s:property value="#request.userpsw"/>
      <s:property value="address"/>    // 獲取對象棧信息(默認從棧頂檢索)

Struts2的property 標簽中value屬性值會特意的將其中的值以OGNL表達式的方式進行運行。

b) 在JSP頁面構建Map集合

格式:#{key:value,key:value...}
舉例
      Struts2的radio標簽主要任務是在頁面中顯示單選按鈕
      <s:radio list="#{'male':'男','female':'女'}" name="gender"></s:radio><br/>
      運行結果源碼:
       <input type="radio" name="gender" id="gendermale" value="male"/>男
       <input type="radio" name="gender" id="genderfemale" value="female"/>女

3.3.2 $號的作用

$號的作用
      在國際化資源文件中,引用OGNL表達式
      在Struts2配置文件中,引用OGNL表達式
舉例
      ognl.xml配置文件
       <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}">
              <result name="success">/ognl/ognl.jsp?username=${#request.username}</result>
       </action>
       在ognl.jsp中獲取攜帶的參數:
       <s:property value="%{#parameters.username[0]}"/>

3.3.3 %號的作用

$號的作用
      “%”符號的作用是在當Struts2標簽的屬性值為OGNL表達式時OGNL表達式卻被理解為字符串類型原樣輸出時,用于通知執行環境%{}里的是OGNL表達式。 
舉例
      Struts2中的textfield標簽主要用于在頁面中顯示一個文本輸入框數據。類似input
      <s:textfield value="#request.username"></s:textfield>
      此時#request.username被理解為一個普通的字符串,因此直接顯示。因為這里脫離了
      運行OGNL的環境即:<s:property value="OGNL表達式"/>環境。
      通知運行環境將#request.username以OGNL表達式運行:
      <s:textfield value="%{#request.username}"></s:textfield>
總結
       為了方便使用%{}我們可以在任何地方都直接添加%{}來確保運行OGNL表達式:
       <s:property value="%{#request.username}"/>

4.Struts2標簽

4.1 if/elseif/else標簽

if/elseif/else 基本的流程控制.‘If’標簽可單獨使用也可以和‘Else If’標簽和(或)一個多個‘Else’一起使用

<s:if test="#person.age<24">少年</s:if>
<s:elseif test="#person.age<26">中年</s:elseif>
<s:else>老年</s:else>

4.2 property標簽

用于輸出指定值:

格式:
<s:property value=“#name" default="a default value" />     
 default:可選屬性, 如果需要輸出的屬性值為null,則顯示該屬性指定的值
 escape:可選屬性,指定是否格式化HTML代碼。
 value:   可選屬性,指定需要輸出的屬性值,如果沒有指定該屬性,則默認輸出ValueStack棧頂的值。

舉例:
<s:property value="#user.id"/>
<s:property/>:輸出棧頂的值

4.3 debug標簽

struts的調試標簽:可以觀測值棧數據

<s:debug></s:debug>

4.4 iterator標簽

用于對集合進行迭代,這里的集合包含List、Set和數組。

<!-- list迭代 -->
<s:iterator var="user" value="#request.list" status="st">
    <s:property value="#user.id"/>
    <s:property value="#user.name"/>
</s:iterator>

<!-- map迭代 -->
<s:iterator var="en" value="#request.map" status="st
    <s:property value="#en.key"/>
    <s:property value="#en.value.name"/>
</s:iterator>

    <!-- Ognl表達式可以取值,也可以動態構建集合 -->
    <br/>一、.構建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
        <s:property value="#str"/>
    </s:iterator>
    
     <br/>一、.構建 map集合</br>
     <s:iterator var="en" value="#{'cn':'China','usa':'America'}">
        <s:property value="#en.key"/>
        <s:property value="#en.value"/>  <br/>
     </s:iterator>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容