Struts 2 - 攔截器



從概念上講,攔截器與Servlet過濾器或JDK的Proxy類相同。攔截器允許實現與Action和框架分離的橫切功能。您可以使用攔截器實現以下功能:

  • 在呼叫Action之前提供預處理邏輯。

  • 在呼叫Action之後提供後處理邏輯。

  • 捕獲異常,以便可以執行替代處理。

Struts2框架提供的許多功能都是使用攔截器實現的;

例如包括異常處理、檔案上傳、生命週期回撥等。事實上,由於Struts2的大部分功能都依賴於攔截器,因此每個Action不太可能分配7個或8個攔截器。

Struts2框架攔截器

Struts 2框架提供了一個很好的現成攔截器列表,這些攔截器已預先配置並可以使用。下面列出了一些重要的攔截器:

序號 攔截器及描述
1

別名

允許引數在不同請求中具有不同的名稱別名。

2

checkbox

透過為未選中的複選框新增false引數值來協助管理複選框。

3

conversionError

將字串轉換為引數型別時出現的錯誤資訊放入Action的欄位錯誤中。

4

createSession

如果HTTP會話尚不存在,則自動建立一個。

5

debugging

為開發者提供幾個不同的除錯螢幕。

6

execAndWait

在Action在後臺執行時,將使用者傳送到一箇中間等待頁面。

7

exception

將Action丟擲的異常對映到結果,允許透過重定向進行自動異常處理。

8

fileUpload

方便檔案上傳。

9

i18n

在使用者的會話期間跟蹤所選語言環境。

10

logger

透過輸出正在執行的Action的名稱來提供簡單的日誌記錄。

11

params

在Action上設定請求引數。

12

prepare

這通常用於執行預處理工作,例如設定資料庫連線。

13

profile

允許為Action記錄簡單的效能分析資訊。

14

scope

在會話或應用程式範圍內儲存和檢索Action的狀態。

15

ServletConfig

為Action提供對各種基於Servlet的資訊的訪問。

16

timer

以Action執行所需時間長度的形式提供簡單的效能分析資訊。

17

token

檢查Action是否有有效的令牌,以防止重複提交表單。

18

validation

為Action提供驗證支援。

請檢視Struts 2文件以瞭解上述攔截器的完整詳細資訊。但我將向您展示如何在Struts應用程式中一般使用攔截器。

如何使用攔截器?

讓我們看看如何將現有的攔截器用於我們的“Hello World”程式。我們將使用timer攔截器,其目的是衡量執行Action方法所需的時間。同時,我使用params攔截器,其目的是將請求引數傳送到Action。您可以嘗試在不使用此攔截器的例子,您會發現name屬性沒有被設定,因為引數無法到達Action。

我們將保留HelloWorldAction.java、web.xml、HelloWorld.jsp和index.jsp檔案,因為它們是在例子章節中建立的,但是讓我們修改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.struts2.HelloWorldAction"
         method = "execute">
         <interceptor-ref name = "params"/>
         <interceptor-ref name = "timer" />
         <result name = "success">/HelloWorld.jsp</result>
      </action>
   </package>
</struts>

右鍵單擊專案名稱,然後單擊匯出>WAR檔案以建立WAR檔案。然後將此WAR部署到Tomcat的webapps目錄中。最後,啟動Tomcat伺服器並嘗試訪問URL https://:8080/HelloWorldStruts2/index.jsp。這將生成以下螢幕:

Hello World Struts 4

現在在給定的文字框中輸入任何單詞,然後單擊“Say Hello”按鈕以執行定義的操作。現在,如果您檢查生成的日誌,您將找到以下文字:

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攔截器生成的,它表明Action執行總共耗時109毫秒。

建立自定義攔截器

在您的應用程式中使用自定義攔截器是提供橫切應用程式功能的一種優雅方法。建立自定義攔截器很容易;需要擴充套件的介面是以下Interceptor介面:

public interface Interceptor extends Serializable {
   void destroy();
   void init();
   String intercept(ActionInvocation invocation)
   throws Exception;
}

顧名思義,init()方法提供了一種初始化攔截器的方法,而destroy()方法提供了一種攔截器清理的工具。與Action不同,攔截器在請求之間被重用,並且需要是執行緒安全的,特別是intercept()方法。

ActionInvocation物件提供了對執行時環境的訪問。它允許訪問Action本身以及呼叫Action和確定Action是否已被呼叫的方法。

如果您不需要初始化或清理程式碼,則可以擴充套件AbstractInterceptor類。這提供了init()和destroy()方法的預設空操作實現。

建立攔截器類

讓我們在Java 資源 > src資料夾中建立以下MyInterceptor.java檔案:

package com.tutorialspoint.struts2;

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;
   }
}

正如您所注意到的,實際的Action將透過invocation.invoke()呼叫由攔截器執行。因此,您可以根據您的需求進行一些預處理和一些後處理。

框架本身首先透過對ActionInvocation物件的invoke()進行第一次呼叫來啟動此過程。每次呼叫invoke()時,ActionInvocation都會查詢其狀態並執行下一個攔截器。當所有已配置的攔截器都已呼叫時,invoke()方法將導致Action本身被執行。

下圖透過請求流程顯示了相同的概念:

ActionInvocation

建立Action類

讓我們在Java 資源 > src下建立一個名為HelloWorldAction.java的java檔案,包名為com.tutorialspoint.struts2,內容如下。

package com.tutorialspoint.struts2;

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;
   }
}

這是我們在之前的例子中看到的同一個類。我們為“name”屬性提供了標準的getter和setter方法,以及一個返回字串“success”的execute方法。

建立檢視

讓我們在Eclipse專案的WebContent資料夾中建立以下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資料夾中建立index.jsp。此檔案將用作初始Action URL,使用者可以單擊該URL來告訴Struts 2框架呼叫HelloWorldAction類的已定義方法並呈現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 Struts2</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 Action將使用struts.xml檔案對映到HelloWorldAction類及其execute方法。

配置檔案

現在,我們需要註冊我們的攔截器,然後像我們在之前的例子中呼叫預設攔截器一樣呼叫它。要註冊新定義的攔截器,將<interceptors>...</interceptors>標籤直接放在struts.xml檔案中的<package>標籤下。對於預設攔截器,您可以跳過此步驟,就像我們在之前的示例中所做的那樣。但在這裡,讓我們註冊並使用它,如下所示:

<?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.struts2.MyInterceptor" />
      </interceptors>

      <action name = "hello" 
         class = "com.tutorialspoint.struts2.HelloWorldAction" 
         method = "execute">
         <interceptor-ref name = "params"/>
         <interceptor-ref name = "myinterceptor" />
         <result name = "success">/HelloWorld.jsp</result>
      </action>

   </package>
</struts>

需要注意的是,您可以在<package>標籤內註冊多個攔截器,同時您可以在<action>標籤內呼叫多個攔截器。您可以使用不同的Action呼叫相同的攔截器。

web.xml檔案需要在WebContent下的WEB-INF資料夾下建立,如下所示:

<?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>struts2</filter-name>
      <filter-class>
         org.apache.struts2.dispatcher.FilterDispatcher
      </filter-class>
   </filter>

   <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
   </filter-mapping>
</web-app>

右鍵單擊專案名稱,然後單擊匯出>WAR檔案以建立WAR檔案。然後將此WAR部署到Tomcat的webapps目錄中。最後,啟動Tomcat伺服器並嘗試訪問URL https://:8080/HelloWorldStruts2/index.jsp。這將生成以下螢幕:

Hello World Struts 4

現在在給定的文字框中輸入任何單詞,然後單擊“Say Hello”按鈕以執行定義的操作。現在,如果您檢查生成的日誌,您將在底部找到以下文字:

Pre-Processing
Inside action....
Post-Processing

堆疊多個攔截器

您可以想象,必須為每個Action配置多個攔截器很快就會變得難以管理。為此,攔截器使用攔截器棧進行管理。這是一個例子,直接來自strutsdefault.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,可以在您的配置中使用,如下所示。此配置節點位於<package .../>節點下。每個<interceptor-ref .../>標籤引用在當前攔截器棧之前配置的攔截器或攔截器棧。因此,在配置初始攔截器和攔截器棧時,確保名稱在所有攔截器和攔截器棧配置中都是唯一的非常重要。

我們已經看到了如何將攔截器應用於Action,應用攔截器棧沒有什麼不同。事實上,我們使用完全相同的標籤:

<action name = "hello" class = "com.tutorialspoint.struts2.MyAction">
   <interceptor-ref name = "basicStack"/>
   <result>view.jsp</result>
</action

上述“basicStack”的註冊將向hello Action註冊所有六個攔截器的完整棧。需要注意的是,攔截器的執行順序與其配置順序相同。例如,在上述情況下,exception將首先執行,第二個將是servlet-config,依此類推。

廣告