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>