Struts 2 简明教程
Struts 2 - Interceptors
从本质上讲,拦截器与 servlet 过滤器或 JDK 的 Proxy 类相同。拦截器允许跨模块功能与操作和框架分开发挥作用。您可以使用拦截器实现以下内容 −
-
在调用操作之前提供预处理逻辑。
-
在调用操作之后提供后处理逻辑。
-
捕获异常,以便执行备用处理。
Struts2 框架中提供的许多功能都是使用拦截器实现的;
Examples 包括异常处理、文件上传、生命周期回调等。实际上,由于 Struts2 将其大部分功能强调在拦截器上,因此不太可能为每个操作分配 7 到 8 个拦截器。
Struts2 Framework Interceptors
Struts2 框架提供了一个即用型开箱拦截器列表,这些拦截器已经过预配置并准备使用。下面列出了一些重要的拦截器 −
Sr.No |
Interceptor & Description |
1 |
alias 允许参数在不同请求之间有不同的名称别名。 |
2 |
checkbox 通过为未选中的复选框添加 false 参数值,帮助管理复选框。 |
3 |
conversionError 将字符串转换为参数类型时的错误信息放置在操作的字段错误中。 |
4 |
createSession 如果尚未存在,则自动创建一个 HTTP 会话。 |
5 |
debugging 向开发者提供几个不同的调试屏幕。 |
6 |
execAndWait 在操作在后台执行时,将用户发送到中间等待页面。 |
7 |
exception 将操作中引发的异常映射到结果,允许通过重定向自动处理异常。 |
8 |
fileUpload Facilitates easy file uploading. |
9 |
i18n 在用户的会话期间跟踪所选的区域设置。 |
10 |
logger 提供简单的日志记录,输出正在执行的操作的名称。 |
11 |
params 在操作中设置请求参数。 |
12 |
prepare 这通常用于执行预处理工作,例如设置数据库连接。 |
13 |
profile 可以将简单的状况信息记录到操作。 |
14 |
scope 在会话或应用程序范围内存储和检索操作的状态。 |
15 |
ServletConfig 为操作提供访问基于 Servlet 的各种信息的权限。 |
16 |
timer 提供操作执行所需时间的形式的简单状况信息。 |
17 |
token 检查操作是否具有有效令牌来防止重复提交表单。 |
18 |
validation 为操作提供验证支持。 |
请在 Struts 2 文档中查找以上所述拦截器的完备详细信息。但我会向你展示如何在 Struts 应用程序中通常使用拦截器。
How to Use Interceptors?
让我们了解如何在“Hello World”程序中使用已存在的拦截器。我们将使用 timer 拦截器,其目的是衡量执行操作方法所需的时间。同时,我正在使用 params 拦截器,其目的是将请求参数发送到操作。你可以尝试不使用此拦截器来验证你的示例,你会发现 name 属性没有被设置,这是因为参数无法到达操作。
我们将保留 HelloWorldAction.java、web.xml、HelloWorld.jsp 和 index.jsp 文件,因为它们已在 Examples 章节中创建,但让我们修改 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>
右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后再将此 WAR 部署到 Tomcat 的 Web 应用目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将产生以下屏幕:
现在在给定的文本框中输入任意单词并单击马上问候按钮来执行已定义的操作。现在,如果你将检查生成的日志,你会发现以下文本:
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 拦截器生成的,其表明操作总共花费了 109 毫秒才得以执行。
Create Custom Interceptors
在应用程序中使用自定义拦截器是提供跨切割应用程序功能的优雅方式。创建自定义拦截器很容易;需要扩展的接口是以下 Interceptor 接口:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
顾名思义,init() 方法提供一种方法来初始化拦截器,而 destroy() 方法则提供一种拦截器清理功能。与操作不同,拦截器将在所有请求中重复使用,且需要线程安全,尤其是 intercept() 方法。
ActionInvocation 对象提供对运行时环境的访问。它允许访问操作本身以及用于调用操作并确定是否已调用操作的方法。
如果你不需要初始化或清理代码,则可以扩展 AbstractInterceptor 类。它提供了 init() 和 destroy() 方法的默认无效操作实现。
Create Interceptor Class
让我们在 Java Resources > 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;
}
}
如你所见,实际操作将通过调用 invocation.invoke() 由拦截器执行。因此,你可以根据你的要求进行某些预处理和后处理。
框架本身通过对 ActionInvocation 对象的 invoke() 进行首次调用来启动该进程。每次调用 invoke() 时,ActionInvocation 都会咨询其状态并执行随之而来的任何一个拦截器。当调用所有配置的拦截器后,invoke() 方法将导致执行操作本身。
下图通过请求流程显示了相同概念 -
Create Action Class
让我们在 Java Resources > src 中使用包名 com.tutorialspoint.struts2 创建一个 java 文件 HelloWorldAction.java ,内容如下。
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;
}
}
这是一个我们在之前的示例中见过的类。我们为“名称”属性有标准的 getter 和 setter 方法,还有一个返回字符串“成功”的执行方法。
Create a View
让我们在 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>
Create Main Page
我们还需要在 WebContent 文件夹中创建 index.jsp 。这个文件将作为初始操作 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 将使用 struts.xml 文件映射到 HelloWorldAction 类及其执行方法。
Configuration Files
现在,我们需要注册我们的拦截器,然后调用它,就像我们在前一个示例中调用缺省拦截器一样。要注册一个新定义的拦截器,需要将 <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> 标签内调用多个拦截器。你可以使用不同的操作调用同一个拦截器。
需要在 WebContent 下面的 WEB-INF 文件夹下创建 web.xml 文件,如下所示 -
<?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>
右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后再将此 WAR 部署到 Tomcat 的 Web 应用目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将产生以下屏幕:
现在,在给定文本框中输入任意单词,然后单击“Say Hello”按钮以执行定义的操作。现在,如果你检查生成的日志,你将会在底部找到以下文本 -
Pre-Processing
Inside action....
Post-Processing
Stacking Multiple Interceptors
如你所想象的,必须为每个操作配置多个拦截器会很快变得极度难以管理。因此,拦截器使用拦截器栈进行管理。以下就是一个直接来自 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 name = "hello" class = "com.tutorialspoint.struts2.MyAction">
<interceptor-ref name = "basicStack"/>
<result>view.jsp</result>
</action
对“basicStack”的上述注册将完全登记在 hello 操作中六个拦截器的全部赌注。需要注意的是,拦截器按照其配置的顺序执行。例如,在上述情况下,exception 将首先执行,其次是 servlet-config,依此类推。