Struts2 - 拦截器( Interceptors)
拦截器在概念上与servlet过滤器或JDKs Proxy类相同。 拦截器允许横切功能与动作和框架分开实现。 您可以使用拦截器实现以下目标 -
在调用操作之前提供预处理逻辑。
在调用操作后提供后处理逻辑。
捕获异常以便可以执行备用处理。
Struts2框架中提供的许多功能都是使用拦截器实现的;
Examples包括异常处理,文件上传,生命周期回调等。事实上,由于Struts2在拦截器上强调其大部分功能,因此每个动作不可能分配7或8个拦截器。
Struts2框架拦截器
Struts 2框架提供了一个很好的开箱即用拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了很少的重要拦截器 -
Sr.No | 拦截器和描述 |
---|---|
1 | alias 允许参数在请求中具有不同的名称别名。 |
2 | checkbox 通过为未选中的复选框添加参数值false,帮助管理复选框。 |
3 | conversionError 将字符串转换为参数类型的错误信息放入操作的字段错误中。 |
4 | createSession 如果尚不存在,则自动创建HTTP会话。 |
5 | debugging 为开发人员提供几种不同的调试屏幕。 |
6 | execAndWait 当操作在后台执行时,将用户发送到中间等待页面。 |
7 | exception 将从操作引发的异常映射到结果,允许通过重定向进行自动异常处理。 |
8 | fileUpload 便于文件上传。 |
9 | i18n 在用户会话期间跟踪所选区域设置。 |
10 | logger 通过输出正在执行的操作的名称来提供简单的日志记录。 |
11 | params 设置操作的请求参数。 |
12 | prepare 这通常用于执行预处理工作,例如设置数据库连接。 |
13 | profile 允许记录操作的简单性能分析信息。 |
14 | scope 在会话或应用程序范围中存储和检索操作的状态。 |
15 | ServletConfig 提供对各种基于servlet的信息的访问权限的操作。 |
16 | timer 以动作执行所需的时间的形式提供简单的分析信息。 |
17 | token 检查有效令牌的操作以防止重复的表单提交。 |
18 | validation 为操作提供验证支持 |
有关上述拦截器的完整详细信息,请查看Struts 2文档。 但是我将向您展示如何在Struts应用程序中使用拦截器。
如何使用拦截器?
让我们看看如何使用现有的拦截器来实现我们的“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.iowiki.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文件。 然后在Tomcat的webapps目录中部署此WAR。 最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp 。 这将产生以下屏幕 -
现在在给定的文本框中输入任何单词,然后单击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拦截器正在生成底线,因此告知动作总共需要执行109ms。
创建自定义拦截器
在应用程序中使用自定义拦截器是提供横切应用程序功能的一种优雅方式。 创建自定义拦截器很容易; 需要扩展的接口是以下Interceptor接口 -
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
顾名思义,init()方法提供了一种初始化拦截器的方法,而destroy()方法为拦截器清理提供了一种工具。 与动作不同,拦截器可以跨请求重用,并且需要线程安全,尤其是intercept()方法。
ActionInvocation对象提供对运行时环境的访问。 它允许访问操作本身和方法来调用操作并确定是否已经调用了操作。
如果您不需要初始化或清理代码,则可以扩展AbstractInterceptor类。 这提供了init()和destroy()方法的默认nooperation实现。
创建拦截器类
让我们在Java Resources 》 src文件夹中创建以下MyInterceptor.java -
package com.iowiki.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()方法将导致执行操作本身。
下图通过请求流程显示了相同的概念 -
创建Action类 (Create Action Class)
让我们在Java Resources 》 src下创建一个java文件HelloWorldAction.java,其包名为com.iowiki.struts2 ,其内容如下所示。
package com.iowiki.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方法。
创建一个视图 (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>
创建主页面
我们还需要在WebContent文件夹中创建index.jsp 。 此文件将用作初始操作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操作将使用struts.xml文件映射到HelloWorldAction类及其execute方法。
配置文件 (Configuration Files)
现在,我们需要注册我们的拦截器,然后调用它,因为我们在前面的例子中调用了默认拦截器。 要注册新定义的拦截器,
<?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.iowiki.struts2.MyInterceptor" />
</interceptors>
<action name = "hello"
class = "com.iowiki.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文件。 然后在Tomcat的webapps目录中部署此WAR。 最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp 。 这将产生以下屏幕 -
现在在给定的文本框中输入任何单词,然后单击Say Hello按钮以执行定义的操作。 现在,如果您要检查生成的日志,您会在底部找到以下文本 -
Pre-Processing
Inside action....
Post-Processing
堆叠多个拦截器
可以想象,必须为每个动作配置多个拦截器很快就会变得非常难以管理。 因此,拦截器使用拦截器堆栈进行管理。 这是一个直接来自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.iowiki.struts2.MyAction">
<interceptor-ref name = "basicStack"/>
<result>view.jsp</result>
</action
上述“basicStack”注册将通过hello动作注册所有六个拦截器的完整股份。 应该注意,拦截器按照已配置的顺序执行。 例如,在上面的例子中,将首先执行异常,第二个将是servlet-config,依此类推。