鍍金池/ 教程/ Java/ 攔截器
注釋
主題/模板
驗證
有用的資源
Struts 2 注解類型
實例
攔截器
異常處理
表單標簽
結(jié)果類型
值棧/OGNL
Spring 集成
數(shù)據(jù)標簽
環(huán)境配置
配置
類型轉(zhuǎn)換
動作
Hibernate 集成
本地化
發(fā)送郵件
Ajax 標簽
數(shù)據(jù)庫訪問
體系結(jié)構(gòu)
文件上傳
Tiles 集成
概述
基本的 MVC 架構(gòu)
控制標簽

攔截器

攔截器在概念上和servlet過濾器或JDKs代理類一樣。攔截器允許橫切功能在動作和框架中單獨實現(xiàn)。你可以使用攔截器實現(xiàn)下面的內(nèi)容:

  • 在動作被調(diào)用之前提供預(yù)處理邏輯。

  • 在動作被調(diào)用之后提供預(yù)處理邏輯。

  • 捕獲異常,以便可以執(zhí)行交替處理。

Struts 2 框架提供的許多功能都是使用攔截實現(xiàn)的;例如包括異常處理,文件上傳,生命周期回調(diào)和驗證等。事實上,由于 Struts 2 是許多攔截器功能的基礎(chǔ),所以每次動作不是不可能有 7 個或 8 個攔截器被分配。

Struts 2 框架的攔截器

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。

創(chuàng)建自定義的攔截器

在你的應(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)。

創(chuàng)建攔截器類

讓我們在 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="" />

創(chuàng)建動作類

讓我們在 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 方法。

創(chuàng)建視圖

讓我們在 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>

創(chuàng)建主頁面

我們還需要在 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)用了默認的攔截器一樣。為了注冊一個新定義的攔截器,可以把 ... 標簽直接放置在 struts.xml 文件 標簽內(nèi)。對于默認的攔截器,你可以跳過這一步,就像我們在前面的例子中一樣。但在這里讓我們注冊和使用它,如下所示:

 
<?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)該注意的是,你可以在 標簽內(nèi)注冊多個攔截器,并且同時你可以在 標簽內(nèi)調(diào)用多個攔截器。你可以用不同的動作調(diào)用相同的攔截器。

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é)點被放置在 節(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 配置等等。

上一篇:概述下一篇:結(jié)果類型