欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Struts2 拦截器(Interceptor )原理和配置

程序员文章站 2022-07-09 17:16:13
...

Struts2 拦截器

拦截器在概念上与servlet过滤器或JDK代理类相同。拦截器允许横切功能,把action以及框架分开实现。你可以使用拦截器实现以下操作:

  • 在调用action之前提供预处理逻辑。

  • 在调用action后提供后处理逻辑。

  • 捕获异常,以便可以执行备用处理。

Struts2框架中提供的许多功能都是使用拦截器实现的,包括异常处理,文件上传,生命周期回调和验证等。事实上,由于Struts2将其大部分功能基于拦截器,因此不太可能为每个action分配7个或8个拦截器。


Struts2拦截器原理
Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

比如:应用要求用户登陆,且必须为指定用户名才可以查看系统中某个视图资源;否则,系统直接转入登陆页面。对于上面的需求,可以在每个Action的执行实际处理逻辑之前,先执行权限检查逻辑,但这种做法不利于代码复用。因为大部分Action里的权限检查代码都大同小异,故将这些权限检查的逻辑放在拦截器中进行将会更加优雅。


PS:
1.
Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现.
2. 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。


Struts2框架拦截器

Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:

序号 拦截器和说明
1 alias

允许参数在请求之间使用不同的别名。

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

提供可访问各种基于servlet信息的action。

16 timer

以action执行时间的形式提供简单的分析信息。

17 token

检查action的有效性,以防止重复提交表单。

18 validation

提供action的验证支持。

你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。

如何使用拦截器?

让我们看看如何在我们的“Hello World”程序中使用一个已经存在的拦截器。我们将首先使用timer拦截器,目的是测量执行action方法所需的时间。同时我们使用params拦截器,目的是将请求参数发送给action。

修改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="cn.w3cschool.struts2.HelloWorldAction"
         method="execute">
         <interceptor-ref name="params"/>
         <interceptor-ref name="timer" />
         <result name="success">/HelloWorld.jsp</result>
      </action>
   </package>
</struts>

部署项目,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。结果如下图所示:

Struts2 拦截器(Interceptor )原理和配置

现在,在给定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你去查看生成的日志,会看到以下文本:

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拦截器生成的,是表示ation总共需要109ms来执行。


创建自定义拦截器

在你的应用程序中使用自定义拦截器是提供跨切割应用程序功能的简洁方式。创建自定义拦截器很容易,需要扩展的是以下Interceptor接口

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

正如name所指出的,init()方法提供了一种初始化拦截器的方法,而destroy()方法为拦截器清理提供了一个工具。与action不同,拦截器在请求之间重复使用,需要线程安全,特别是intercept()方法。
ActionInvocation对象可访问运行时的环境。它允许访问action本身以及方法来调用action,并确定action是否已被调用。
如果你不需要初始化或清理代码,可以扩展AbstractInterceptor类,以实现init()和destroy()的默认的无操作指令。


Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。该接口声明了3个方法,其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。


1:所有拦截器都使用接口Interceptor ,Action去实现这个接口;
    Init()方法:在服务器起动的时候加载一次,并且只加载一次;
    Destroy()方法:当拦截器销毁时执行的方法;
    Interceptor()方法:其中里边有一个参数invocation;

public String intercept(ActionInvocation invocation) throws xception {
    System.out.println("interceptor!!");
    String result=invocation.invoke();
    return result;
}
其中intercept方法是拦截器的核心方法,所有安装的拦截器都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timer、params等。如果在<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。

Invocation.invoke()是如果只有一个拦截器执行完这个方法后,会返回给视图,如果有多个拦截器,它顺序的执行完所有的拦截器,才返回给视图,也就是调用后面的action继续执行。


创建拦截器类

我们接下来在Java Resources>src文件夹中创建以下MyInterceptor.java文件:

package cn.w3cschool.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{

      String output = "Pre-Processing"; 
      System.out.println(output);

      String result = invocation.invoke();

      output = "Post-Processing"; 
      System.out.println(output);

      return result;
   }
}
你可以发现,实际中action将通过拦截器使用invocation.invoke()调用执行,所以你可以根据你的需求做一些预处理和一些后处理。
框架本身通过第一次调用ActionInvocation对象的invoke()来启动进程。每次调用invoke()时,ActionInvocation都会查询其状态,并执行下一个拦截器。当所有配置的拦截器都被调用时,invoke()将使得action本身被执行。以下图表通过请求流显示了所说的概念:

Struts2 拦截器(Interceptor )原理和配置

创建Action类

我们在Java Resources>src文件夹下创建一个java文件HelloWorldAction.java,其中包名为cn.w3cschool.struts2,内容如下:

package cn.w3cschool.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”属性标准的getters和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,用户可以单击它以命令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>标签直接放置在<package>标签下的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">

      <interceptors>
         <interceptor name="myinterceptor"
            class="cn.w3cschool.struts2.MyInterceptor" />
      </interceptors>

      <action name="hello" 
         class="cn.w3cschool.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>

然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下图片:

Struts2 拦截器(Interceptor )原理和配置

现在,在给的定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你查看生成的日志,会在底部看到以下文本:

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

拦截器堆栈

你可以想象,为每个action配置的多个拦截器将很快变得极其难以管理。为此,拦截器使用拦截器堆栈进行管理。这里是直接从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,可以如下所述在你的配置中使用,此配置节点放置在<package ... />节点下。<interceptor-ref ... />标签引用的是在当前拦截器堆栈之前配置的拦截器或拦截器堆栈。因此非常重要的是在配置初始拦截器和拦截器堆栈时,确保name在所有拦截器和拦截器堆栈配置中是唯一的。
我们已经学习了如何将拦截器应用到action中,而拦截器堆栈的应用也是类似的。事实上,使用的标签也是一样的:
 
<action name="hello" class="com.tutorialspoint.struts2.MyAction">
   <interceptor-ref name="basicStack"/>
   <result>view.jsp</result>
</action

上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。


摘抄:https://www.w3cschool.cn/struts_2/struts_interceptors.html