攔截器在概念上和servlet過濾器或JDKs代理類一樣。攔截器允許橫切功能在動作和框架中單獨實現(xiàn)。你可以使用攔截器實現(xiàn)下面的內(nèi)容:
在動作被調(diào)用之前提供預(yù)處理邏輯。
在動作被調(diào)用之后提供預(yù)處理邏輯。
Struts 2 框架提供的許多功能都是使用攔截實現(xiàn)的;例如包括異常處理,文件上傳,生命周期回調(diào)和驗證等。事實上,由于 Struts 2 是許多攔截器功能的基礎(chǔ),所以每次動作不是不可能有 7 個或 8 個攔截器被分配。
Struts 2 框架提供了一列開箱即用的攔截器來預(yù)先設(shè)定和準備使用。下面列出了幾個重要的攔截器:
序號 | 攔截器及描述 |
---|---|
1 |
alias
允許參數(shù)有不同的跨請求的別名。 |
2 |
checkbox
通過為沒有被檢查的復選框添加一個參數(shù)值 false 來協(xié)助管理復選框。 |
3 |
conversionError
把從字符串轉(zhuǎn)化為參數(shù)類型的錯誤信息放置到動作的字段錯誤中。 |
4 |
createSession
如果不存在 HTTP 會話,則自動創(chuàng)建一個 HTTP 會話。 |
5 |
debugging
為開發(fā)人員提供幾種不同的調(diào)試屏幕。 |
6 |
execAndWait
當動作在后臺執(zhí)行的時侯,把用戶定向到一個中間的等待頁面。 |
7 |
exception
映射動作拋出的異常到一個結(jié)果中,通過重定向允許自動異常處理。 |
8 |
fileUpload
有利于簡單的文件上傳。 |
9 |
i18n
在用戶的會話期間,跟蹤選定的語言環(huán)境。 |
10 |
logger
通過輸出被執(zhí)行的動作的名稱提供簡單的日志。 |
11 |
params
設(shè)置動作的請求參數(shù)。 |
12 |
prepare
它通常是用來做預(yù)處理工作,如設(shè)置數(shù)據(jù)庫連接。 |
13 |
profile
|
14 |
scope
在會話或應(yīng)用程序的范圍中存儲和檢索動作的狀態(tài)。 |
15 |
ServletConfig
為行動提供了各種基于 servlet 信息的訪問。 |
16 |
timer
以動作需要多長時間執(zhí)行的形式提供了簡單的配置信息。 |
17 |
token
為有效的標記檢查動作用來防止重復地表單提交。 |
18 |
validation
為動作提供了驗證支持。 |
關(guān)于上面提到的攔截器的完整信息,請查看 Struts 2 的文檔。但是我會告訴你通常如何在你的 Struts 應(yīng)用程序中使用一個攔截器。
讓我們來看看如何在我們的 “Hello World” 程序中使用已存在的攔截器。我們將使用 timer 攔截器,它的目的是測量它多長時間執(zhí)行一個動作的方法。同時我使用 params 攔截器,它的目的是給動作發(fā)送請求參數(shù)。你可以嘗試在你的例子中不使用這個攔截器,你將會發(fā)現(xiàn) name 屬性沒有被設(shè)置,因為參數(shù)是無法達到動作中的。
我們將保留 HelloWorldAction.java,web.xml,HelloWorld.jsp 和index.jsp 文件,因為他們已經(jīng)在 Examples 章節(jié)被創(chuàng)建了,但是讓我們修改 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> <constant name="struts.devMode" value="true" /> <package name="helloworld" extends="struts-default"> <action name="hello" class="com.tutorialspoint.Struts 2.HelloWorldAction" method="execute"> <interceptor-ref name="params"/> <interceptor-ref name="timer" /> <result name="success">/HelloWorld.jsp</result> </action> </package> </struts>
右鍵單擊項目名稱,并且單擊 Export > WAR File 來創(chuàng)建一個 War 文件。然后在 Tomcat 的 webapps 目錄下部署這個 WAR。最后,啟動 Tomcat 服務(wù)器和嘗試訪問 URL http://localhost:8080/HelloWorldStruts 2/index.jsp
. 將會給出下面的畫面:
http://wiki.jikexueyuan.com/project/struts-2/images/helloworldstruts4.jpg" alt="" />
現(xiàn)在,在給定的文本框中輸入任何單詞,并且單擊 Say Hello 按鈕執(zhí)行已定義的動作。現(xiàn)在,如果你查看生成的日志,就會發(fā)現(xiàn)下面的文字:
INFO: Server startup in 3539 ms
27/08/2011 8:40:53 PM
com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
INFO: Executed action [//hello!execute] took 109 ms.
在這里最后一行是因為 timer 攔截器生成長的,它告訴動作被執(zhí)行的時間的 109ms。
在你的應(yīng)用程序中使用自定義的攔截器是一種提供橫切的應(yīng)用功能的簡潔的方式。創(chuàng)建一個自定義的攔截器是很容易的,需要擴展的接口是下面的 Interceptor 接口:
public interface Interceptor extends Serializable{
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
正如名稱所顯示的,init() 方法提供了一種初始化攔截器的方法,而destroy() 方法提供了一種清理攔截器的工具。與動作不同的是,攔截器在請求之間被重用,而且需要是線程安全的,尤其是 intercept() 方法。
ActionInvocation 對象提供運行時環(huán)境的訪問。它允許訪問動作本身和方法來調(diào)用該動作,并判定動作是否已經(jīng)被調(diào)用。
如果你不需要初始化或清理代碼,可以擴展 AbstractInterceptor 類。它提供了一個對 init() 和 destroy() 方法的默認的無操作實現(xiàn)。
讓我們在 Java Resources > src 文件夾中創(chuàng)建下面的MyInterceptor.java:
package com.tutorialspoint.Struts 2;
import java.util.*;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation)throws Exception{
/* let us do some pre-processing */
String output = "Pre-Processing";
System.out.println(output);
/* let us call action or next interceptor */
String result = invocation.invoke();
/* let us do some post-processing */
output = "Post-Processing";
System.out.println(output);
return result;
}
}
如你注意到的,實際的動作將通過使用攔截器調(diào)用 invocation.invoke() 來執(zhí)行。所以,你可以根據(jù)你的需求做一些預(yù)處理和一些后處理。
這個框架本身通過第一次調(diào)用 ActionInvocation 對象的 invoke() 來啟動過程。每次 invoke() 被調(diào)用,ActionInvocation 查詢它的狀態(tài),并且執(zhí)行接下來的攔截器。當所有已配置的攔截器已經(jīng)被配置時,invoke() 方法將引發(fā)這個動作本身被執(zhí)行。下面的圖通過請求流顯示了相同的概念:
http://wiki.jikexueyuan.com/project/struts-2/images/actioninvocation.jpg" alt="" />
讓我們在 Java Resources > src 中名為 com.tutorialspoint.Struts 2 的包下創(chuàng)建一個 java 文件HelloWorldAction.java,它的內(nèi)容在下面給出。
package com.tutorialspoint.Struts 2;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport{
private String name;
public String execute() throws Exception {
System.out.println("Inside action....");
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我們已經(jīng)在前面的例子中看到這個相同的類。我們對于 “name” 屬性有標準的 getters 和 setters 方法,還有返回字符串 “success” 的 execute 方法。
讓我們在 eclipse 項目的 WebContent 文件夾中創(chuàng)建下面的 jsp 文件 helloWorld.jsp。
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Hello World, <s:property value="name"/> </body> </html>
我們還需要在 WebContent 文件夾中創(chuàng)建 index.jsp。這個文件將作為初始動作 URL,用戶可以點擊它告訴 Struts 2 框架調(diào)用HelloWorldAction 類定義的方法,并且呈現(xiàn) HelloWorld.jsp 視圖。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Hello World</title> </head> <body> <h1>Hello World From Struts 2</h1> <form action="hello"> <label for="name">Please enter your name</label><br/> <input type="text" name="name"/> <input type="submit" value="Say Hello"/> </form> </body> </html>
上面的視圖文件中定義的 hello 動作將使用 struts.xml 文件映射到 HelloWorldAction 類和它的 execute 方法中。
現(xiàn)在,我們需要注冊我們的攔截器,然后調(diào)用它,就如我們已經(jīng)在前面的例子中調(diào)用了默認的攔截器一樣。為了注冊一個新定義的攔截器,可以把
<?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> <constant name="struts.devMode" value="true" /> <package name="helloworld" extends="struts-default"> <interceptors> <interceptor name="myinterceptor" class="com.tutorialspoint.Struts 2.MyInterceptor" /> </interceptors> <action name="hello" class="com.tutorialspoint.Struts 2.HelloWorldAction" method="execute"> <interceptor-ref name="params"/> <interceptor-ref name="myinterceptor" /> <result name="success">/HelloWorld.jsp</result> </action> </package> </struts>
應(yīng)該注意的是,你可以在
web.xml 文件需要在 WebContent 的 WEB-INF 文件夾下創(chuàng)建,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Struts 2</filter-name>
<filter-class>
org.apache.Struts 2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>Struts 2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
右鍵單擊項目名稱,并且單擊 Export > WAR File 來創(chuàng)建一個 War文件。然后在 Tomcat 的 webapps 目錄下部署這個 WAR。最后,啟動Tomcat 服務(wù)器和嘗試訪問 URL http://localhost:8080/HelloWorldStruts 2/index.jsp/
將會給出下面的畫面:
http://wiki.jikexueyuan.com/project/struts-2/images/helloworldstruts4.jpg" alt="" />
現(xiàn)在,在給定的文本框中輸入任何單詞,并且單擊 Say Hello 按鈕執(zhí)行已經(jīng)定義的動作?,F(xiàn)在,如果你查看生成的日志,就會在底部發(fā)現(xiàn)下面的文字:
Pre-Processing
Inside action....
Post-Processing
可想而知,為每個動作配置多個攔截器很快就會變得非常難以管理。為此,攔截器用攔截器棧進行管理。這兒有一個例子,直接來自 struts-default.xml 文件:
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
上面的棧被稱為 basicStack,它可以用在你的配置中,如下所示。這個配置節(jié)點被放置在
我們已經(jīng)看到了如何應(yīng)用攔截器到動作中,應(yīng)用攔截器棧是沒有什么不同的。實際上,我們完全使用相同的標簽:
<action name="hello" class="com.tutorialspoint.Struts 2.MyAction">
<interceptor-ref name="basicStack"/>
<result>view.jsp</result>
</action
上述注冊的 “basicStack” 將完整地注冊所有帶有 hello 動作的 6 個攔截器。應(yīng)該指出的是,攔截器按照已配置的順序執(zhí)行。例如,在上述情況下,將首先執(zhí)行異常,第二個執(zhí)行的是 servlet 配置等等。