Struts2 拦截器详解(一)

来源:互联网 发布:如何用矩阵算应用题 编辑:程序博客网 时间:2024/05/02 06:43
 

Struts2 拦截器详解(一)

分类: struts 278人阅读 评论(0) 收藏 举报
strutsinterceptoractionstringexceptionclass

拦截器是Struts2的一个重要特性。Struts2框架的大多数核心功能都是通过拦截器来实现的,像避免表单重复提交、类型转换、对象组装、验证、文件上传等,都是在拦截器的帮助下实现的。

拦截器的一个重要特征是:它可以在Action之前调用。

拦截器,在AOP(Aspect Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截。然后再之前或之后加入某些操作。拦截器是AOP的一种实现策略。

Struts2的拦截原理:

当请求到达Struts2的ServletDispatcher时,Struts2会查找相对应的配置信息,并实例化拦截器对象。串成一个列表(list),最后一个一个地调用列表中的拦截器。

1.配置拦截器

引入拦截器机制,可以实现对Action通用操作的可插拔式管理,这种可插拨是基于Struts.xml文件实现的。

1)配置拦截器

在struts.xml文件中定义拦截器只需为拦截器指定一个拦截器名称即可。使用<interceptor.../>元素来定义拦截器,最简单的格式如下。

[html] view plaincopy
  1. <interceptor name="拦截器名" class="拦截器类"></interceptor>  

有时,按照上面的配置便可以完成一个简单的拦截器,但是,如果还需要配置拦截器时传入拦截器参数,则需要在<interceptor.../>元素中使用<param.../>子元素。下面是在配置拦截器时,同时传入拦截器参数的配置形式。

[html] view plaincopy
  1. <interceptor name="拦截器名" class="拦截器类">  
  2.    <!-- 下面元素可以出现0次,也可以出现无数次,其中name属性指定需要设置的参数名 -->  
  3.       <param name="参数名">参数值</param>  
  4.    </interceptor>  


2)配置拦截器栈

struts2还支持把多个拦截器连在一起组成一个拦截器栈,比如:需要在Action执行前同时进行安全检查,身份验证,数据校验等等操作,可以将这些动作链接成一个拦截器栈。

拦截器栈的定义形式:

[html] view plaincopy
  1. <interceptor-stack name="拦截器栈名">  
  2.       <interceptor-ref name="拦截器一"></interceptor-ref>  
  3.       <interceptor-ref name="拦截器二"></interceptor-ref>  
  4.    </interceptor-stack>  


拦截器和拦截器栈的功能是一样的,只不过拦截器栈定义了一组拦截器。

当然我们也可以在拦截器中定义拦截器栈,这样都是可以的,主要是实现了代码的复用。比如:

[html] view plaincopy
  1. <interceptor name="a1" class="com.zhuxuli.SInterceptor">  
  2.    </interceptor>  
  3.    <interceptor name="a2" class="com.zhuxuli.DInterceptor">  
  4.    </interceptor>  
  5.    <interceptor name="a3" class="com.zhuxuli.WInterceptor"></interceptor>  
  6.      
  7.    <interceptor-stack name="a4">  
  8.       <interceptor-ref name="a1">  
  9.          <param name="st">gsa</param>  
  10.       </interceptor-ref>  
  11.       <interceptor-ref name="a2">  
  12.       </interceptor-ref>  
  13.    </interceptor-stack>  


2.使用拦截器

拦截器在<package>目录下声明好了以后,下一步就是在Action中使用拦截器了

示例代码如下:

[html] view plaincopy
  1. <action name="user" class="com.zhuxuli.action.UserAction">  
  2.           <result name="user">/user.jsp</result>  
  3.           <result name="add_user">/add_input.jsp</result>  
  4.           <span style="color:#ff0000;"><interceptor-ref name="myfilter">  
  5. </span>              <param name="name">拦截器</param>  
  6.               <!-- 指定execute方法不需要被拦截 -->  
  7.               <param name="excludeMethods">execute</param>  
  8.           </interceptor-ref>  
  9.        </action>  

通过<interceptor标签直接引用拦截器。

如果是使用拦截器栈,那示例代码如下:

[html] view plaincopy
  1. <action name="ge">  
  2.        <result name="success">/success.jsp</result>  
  3.        <interceptor-ref name="a1"></interceptor-ref>  
  4.        <!-- 定义使用的拦截器栈,和使用拦截器没有什么区别,都是通过interceptor-ref标签完成 -->  
  5.        <interceptor-ref name="a4"></interceptor-ref>  
  6.   </action>  

3.拦截器剖析

拦截器的配置已经说的很明白了,但是我们还一点疑问是,那个拦截器的实现类怎么办?

对于Struts2拦截器的实现有两种形式

第一种方式:自定义拦截器类

第二种方式:Struts2自带的拦截器

首先我们说明下第一种方式:

上述代码

[html] view plaincopy
  1. <interceptor name="拦截器名" class="拦截器类">  
  2.    <!-- 下面元素可以出现0次,也可以出现无数次,其中name属性指定需要设置的参数名 -->  
  3.       <param name="参数名">参数值</param>  
  4.    </interceptor>  


我们可以看到,自定义拦截器只有name=“拦截器名”是不可以的,我们还要有拦截器类,那拦截器类是怎么实现的?

1)实现自定义拦截器类

如果要开发自己的拦截器类,应该实现com.opensymphony.xwork2.interceptor.Interceptor接口,此接口的定义代码如下:

[java] view plaincopy
  1. import com.opensymphony.xwork2.ActionInvocation;  
  2.   
  3. public interface Interceptor {  
  4.     //撤销该拦截器之前的回调方法  
  5.     void destory();  
  6.     //初始化该拦截器的回调方法  
  7.     void init();  
  8.     //拦截器实现拦截的逻辑方法  
  9.     String intercept(ActionInvocation invocation) throws Exception;  
  10. }  


通过接口可以看出,该接口里有三种方法。

init():拦截器初始化之后,在该拦截器执行拦截之前,系统将回调该方法,对于每一个拦截器而言,该init()方法只执行一次。因此,该方法的方法体主要用户打开一些一次性资源,例如数据库资源等。

destory():该方法与init()方法对应。在拦截实例被销毁之前,系统将回调该拦截器的destory()方法,该方法用于销毁在init()方法里打开的资源。

interceptor(ActionInvocation invocation):该方法是用户需要实现的拦截动作。就像Action执行execute()方法一样,interceptor会返回一个字符串作为逻辑视图。如果该方法直接返回了一个字符串,系统将跳转到该逻辑视图队形的实际的视图资源,不会调用被拦截的Action类。该方法的ActionInvocation参数保护那了被拦截的Action的引用,可以通过调用该参数的invoke()方法,将控制权转给下一个拦截器,或者转给Action的execute方法。

除此之外,Struts2提供了一个AbstractInterceptor类,该类提供了空的init()和destory()方法的实现,也就是如果拦截器不需要申请资源,则可以无须实现这两个方法。

注意:

当实现了intercept(ActionInvocation invocation)方法时,可以获得ActionInvocation参赛,这个参数又可以获得被拦截的Action实例,一旦取得了Action实例,几乎得到了全部的控制权。

实例剖析:

 通过上面的了解,我们来做一个拦截器的实例

需求:客户端用户名密码登陆,拦截器对其进行拦截,如果用户名和密码满足条件,进入执行execute方法,如果不满足要求,返回index.jsp页面

建立相应的index.jsp页面

[html] view plaincopy
  1. <%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>  
  2. <%@ taglib prefix="s" uri="/struts-tags" %>  
  3. <%  
  4. String path = request.getContextPath();  
  5. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
  6. %>  
  7.   
  8. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  9. <html>  
  10.   <head>  
  11.     <base href="<%=basePath%>">  
  12.       
  13.     <title>My JSP 'index.jsp' starting page</title>  
  14.     <meta http-equiv="pragma" content="no-cache">  
  15.     <meta http-equiv="cache-control" content="no-cache">  
  16.     <meta http-equiv="expires" content="0">      
  17.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  18.     <meta http-equiv="description" content="This is my page">  
  19.     <!-- 
  20.     <link rel="stylesheet" type="text/css" href="styles.css"> 
  21.     -->  
  22.   </head>  
  23.     
  24.   <body>  
  25.      <s:form action="los" method="post">  
  26.         <s:textfield label="请输入用户名" name="username"></s:textfield>  
  27.         <s:password label="请输入密码" name="userpass"></s:password>  
  28.         <s:submit/>  
  29.      </s:form>  
  30.   </body>  
  31. </html>  

定义Action类

Action中定义了接受前台两个参数的属性


[java] view plaincopy
  1. import com.opensymphony.xwork2.ActionSupport;  
  2.   
  3. public class LoginAction extends ActionSupport {  
  4.     private String username;  
  5.     private String userpass;  
  6.     public String getUsername() {  
  7.         return username;  
  8.     }  
  9.     public void setUsername(String username) {  
  10.         this.username = username;  
  11.     }  
  12.     public String getUserpass() {  
  13.         return userpass;  
  14.     }  
  15.     public void setUserpass(String userpass) {  
  16.         this.userpass = userpass;  
  17.     }  
  18.     public String execute() throws Exception{  
  19.         return SUCCESS;  
  20.     }  
  21. }  


 

[java] view plaincopy
  1. import com.opensymphony.xwork2.ActionSupport;  
  2.   
  3. public class LoginAction extends ActionSupport {  
  4.     private String username;  
  5.     private String userpass;  
  6.     public String getUsername() {  
  7.         return username;  
  8.     }  
  9.     public void setUsername(String username) {  
  10.         this.username = username;  
  11.     }  
  12.     public String getUserpass() {  
  13.         return userpass;  
  14.     }  
  15.     public void setUserpass(String userpass) {  
  16.         this.userpass = userpass;  
  17.     }  
  18.     public String execute() throws Exception{  
  19.         return SUCCESS;  
  20.     }  
  21. }  


定义拦截器类

该拦截器类继承了AbstractInterceptor类,可以不写init()和destory()方法,但是必须实现intercept(ActionInvocation invocation)方法

当拦截到内容后,系统首先打印出"拦截器开始工作......"

由于invocation中已经存在Action对象,所以按照我们说的得Action者得天下原则,为Action中的两个属性username ,userpass赋值。这里存在一个很重要的问题:如果不为Action的两个元素赋值,那Action类不像我们以前没有拦截器认识的一样,Action中的username和userpass将不会在自动取得前台index.jsp页面传送过来的值,即使满足条件,如果Action类中还需要对username和userpass两个属性做进一步处理的话,username和userpass将会是空值。

怎么解决呢?

首先必须明白的是在提交后,Struts2将会自动调用LoginAction动作类中的setUsername方法,并将username文本框中的值通过setUserame方法的参数传入。实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由于params已经在defaultStack中定义,因此,在未引用拦截器的< action>中是会自动引用params的。

但是,如果引用了自定义拦截器,那我们就要现实的在Action中引用params拦截器

如果满足用户名和密码是user 和123,则调用invocation.invoke()方法,该方法的作用是调用下一个拦截器或Action(如果是最后一个拦截器了,则调用Action);

 

[java] view plaincopy
  1. import javax.servlet.http.HttpServletRequest;  
  2.   
  3. import org.apache.struts2.ServletActionContext;  
  4.   
  5. import com.opensymphony.xwork2.ActionInvocation;  
  6. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;  
  7. import com.zhuxuli.action.LoginAction;  
  8.   
  9. public class LoInterceptor extends AbstractInterceptor{  
  10.     public String intercept(ActionInvocation invocation) throws Exception{  
  11.         System.out.println("拦截器开始工作.....");  
  12.         HttpServletRequest request=ServletActionContext.getRequest();  
  13.         LoginAction action=(LoginAction)invocation.getAction();  
  14.         action.setUsername(request.getParameter("username"));  
  15.         action.setUserpass(request.getParameter("userpass"));  
  16.         if(action.getUsername().equals("user")&&action.getUserpass().equals("123")){  
  17.             String result=invocation.invoke();  
  18.             System.out.println("result="+result);  
  19.             return result;  
  20.         }else{  
  21.             return "input";  
  22.         }  
  23.     }  
  24. }  


然后配置struts.xml文件

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE struts PUBLIC  
  3.     "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"  
  4.     "http://struts.apache.org/dtds/struts-2.1.7.dtd">  
  5. <struts>  
  6.    <constant name="struts.i18n.encoding" value="gbk" />  
  7.     <constant name="struts.devMode" value="true" />  
  8.    <package name="zxl" extends="struts-default">  
  9.        <interceptors>  
  10.           <interceptor name="a1" class="com.zhuxuli.Iterceptors.LoInterceptor">  
  11.           </interceptor>  
  12.        </interceptors>  
  13.        <action name="los" class="com.zhuxuli.action.LoginAction">  
  14.           <result name="input">/index.jsp</result>  
  15.           <result name="success">/success.jsp</result>  
  16.           <interceptor-ref name="a1"></interceptor-ref>  
  17.        </action>  
  18.    </package>  
  19. </struts>  

实例运行后,如果用户名和密码不是user和123,页面返回index.jsp页面继续输入,满足条件,则返回为success.jsp页面。

必须注意的是:

在执行返回success.jsp页面的时候,你会看到控制台打印出了相应的语句,也就是下面的代码执行了

                       Stringresult=invocation.invoke();

                      

                       //代码执行了

                       System.out.println("result="+result);

                       returnresult;

也就是说,通过invocation调用invoke()方法执行Action后,Action执行完毕后,又返回到String result=invocation.invoke()代码下面继续执行,直到执行结束,也就说明了拦截器的拦截过程为:如下图,

说明:搜先调用拦截器1,满足要求,则通过Invocation.invoke()方法调用下一个拦截器或Action,因为这里有下一个拦截器,所以直接调用拦截器2,如果还是满足条件,则继续向下调用,知道返回结果,返回结果后,注意的是,还会继续回到拦截器2执行未完成的代码,执行完后,继续执行拦截器1未完成的代码,直到最后返回结果。

0 0
原创粉丝点击