首页 > 编程笔记 > Java笔记

Struts2 Interceptor接口:拦截器

拦截器(Interceptor)是 Struts2 框架中一个非常重要的核心对象,它可以动态增强 Action 对象的功能。在 Struts2 框架中,很多重要的功能都是通过拦截器实现的。比如,在使用 Struts2 框架中,我们发现 Struts2 与 Servlet API 进行解耦,Action 对请求的处理不依赖于 Servlet API,但 Struts2 的 Action 却具有更加强大的请求处理功能,那么,这个功能的实现就是拦截器对 Action 的增强,可见拦截器的重要性。此外,Struts2 框架中的表单重负提交、对象类型转换、文件上传以及前面所学习的 ModelDriven 的操作,都离不开拦截器幕后的操作,Struts2 的拦截器的处理机制是 Struts2 框架的核心。

拦截器动态地作用于 Action 与 Result 之间,它可以动态地在 Action 与 Result 中加入新功能。

语法:

在 Struts2 API 中,存在一个名为 com.opensymphony.xwork2.interceptor 的包,此包中的对象是 Struts2 内置的一些拦截器对象,它们具有不同的功能。在这些对象中,Interceptor 接口是 Struts2 框架中定义的拦截器对象,其他的拦截器都直接或间接地实现于此接口。

说明:Interceptor 是 Struts2 框架中定义的拦截器对象,它是一个接口,无论是 Struts2 内置的拦截器对象,还是自定义的拦截器都需要直接或间接地实现于此接口。

Struts2 API 中定义该接口的源代码如下:
public interface Interceptor extends Serializable{
  void destroy();
  void init();
  String intercept(ActionInvocation invocation)throws Exception;
}
参数说明:
说明:只有调用了intercept()方法中的invocation参数的invoke()方法,才可以执行Action对象中的请求处理方法。

虽然 Struts2 提供了拦截器对象 Interceptor,但此对象是一个接口,如果通过此接口创建拦截器对象,就需要实现 Interceptor 提供的三个方法,而在实际的开发中,主要用到的方法只有 intercept() 方法,如果没有用到 init() 方法与 destroy() 方法也需要对其进行空实现,这种创建拦截器的方式似乎有些不太方便。

为了简化程序的开发,创建拦截器对象也可以通过 Struts2 API 中的 AbstractInterceptor 对象进行创建,它与 Interceptor 的关系如图所示。


 
AbstractInterceptor 对象是一个抽象类,它对 Interceptory 接口进行了实现,在创建拦截器时可以通过继承 AbstractInterceptor 对象进行创建,在继承 AbstractInterceptor 对象后,创建拦截器的方式就更加简单,除重写必需的 intercept() 方法外,如果没有用到 init() 方法与 destroy() 方法,就不需要再对这两个方法进行实现。

说明:AbstractInterceptor 对象已经对 Interceptory 接口的 init() 方法与 destroy() 方法进行了实现,所以,通过继承 AbstractInterceptor 对象创建拦截器,就不需要实现 init() 方法与 destroy() 方法,如果需要可以对其进行重写。

示例

本示例为 Action 对象配置输出执行时间的拦截器,查看执行 Action 所需要的时间。

创建动态的 Java Web 项目,将 Struts2 的相关类包添加到项目的 classpath,并在 web.xml 文件中注册 Struts2 提供的 StrutsPrepareAndExecuteFilter 过滤器,从而搭建 Struts2 的开发环境。

创建名为 TestAction 的类,此类继承于 ActionSupport 对象,关键代码如下:
public class TestAction extends ActionSupport{
  private static final long serialVersionUID = 1L;
  public String execute()throws Exception{  //线程睡眠1秒
    Thread.sleep(1000);
    return SUCCESS;
  }
}
说明:由于需要配置输出 Action 执行时间的拦截器,为了方便查看执行时间,在 execute() 方法中,通过 Thread 类的 sleep() 方法使当前线程睡眠 1 秒钟。

在 struts.xml 配置文件中,配置 TestAction 对象,并将输出 Action 执行时间的拦截器 "timer" 应用到 TestAction 中,关键代码如下:
<struts>
  <!--声明常量(开发模式)-->
  <constant name="struts.devMode"value="true"/>
  <!--声明常量(在Struts2的配置文件修改后,自动加载)-->
  <constant name="struts.configuration.xml.reload"value="true"/>
  <!--声明包-->
  <package name="myPackge"extends="struts-default">
    <!--配置Action-->
    <action name="testAction"class="com.lyq.action.TestAction">
      <!--配置拦截器-->
      <interceptor-ref name="timer"/>
      <!--配置返回页面-->
      <result>success.jsp</result>
    </action>
  </package>
</struts>
在 TestAction 对象的配置之中为其配置一个拦截器对象 "timer",其作用是输出 TestAction 执行的时间。

技巧:如果需要查看一个 Action 对象执行所需要的时间,可以为这个 Action 对象配置 "timer" 拦截器,"timer" 拦截器是 Struts2 的内置拦截器,不需要对其进行创建及编写,直接配置即可。

创建程序的首页 index.jsp 及 TestAction 返回页面 success.jsp,由于本示例测试 "timer" 拦截器的使用,故没有过多的设置。

在代码编写完成之后,部署项目并访问 TestAction 对象,在访问之后可以查看到 TestAction 执行所占用的时间。

典型应用

本示例创建验证用户是否登录的拦截器对象,对用户请求操作进行拦截处理,如果用户没有登录,将不能进入到管理页面。

创建名为 Struts2_34 的 Java Web 项目,将 Struts2 的相关类包添加到项目的 classpath,并在 web.xml 文件中注册 Struts2 提供的 StrutsPrepareAndExecuteFilter 过滤器,从而搭建 Struts2 的开发环境。
 
创建名为 LoginInterceptor 的类,此类继承于 MethodFilterInterceptor 类,是验证用户是否登录的拦截器对象,关键代码如下:
/**
*验证用户登录的拦截器
*@authorZX
*/
public class LoginInterceptor extends MethodFilterInterceptor{
  private static final long serialVersionUID = 1L;
  @Override
    protected String doIntercept(ActionInvocation invocation)throws Exception{  //获取ActionContext
    ActionContext context = invocation.getInvocationContext();//获取Map类型的session
    Map<String,Object>session=context.getSession();  //判断用户是否登录
    if(session.get("user")!=null){  //调用执行方法
      return invocation.invoke();
    }  //返回登录
    return Action.LOGIN;
  }
}

在 LoginInterceptor 的拦截处理方法 doIntercpt() 中,首先获取 Action 的上下文对象 ActionContext,在获取 ActionContext 后,就可以获取 Map 类型的 session 对象,然后通过 session 获取 user 变量,以判断用户是否已经登录。如果用户已经登录,将调用执行方法向下执行,否则返回登录页面。

注意:在doIntercept()方法中,如果处理后需要向下执行,必须调用ActionInvocation的invoke()方法。

创建用户 Action 对象 UserAction 类,用于对用户相关的请求进行处理,主要包含用户登录请求、用户退出请求、管理等,关键代码如下:
/**
*用户Action
*@author ZX
*/
public class UserAction extends ActionSupport{
  private static final long serialVersionUID = 1L;  //用户名
  private String username;  //密码
  private String password;  //获取Map类型的session变量
  Map<String,Object>session = ActionContext.getContext().getSession();//登录方法
  public String login()throws Exception{  //验证用户名
    if("admin".equalsIgnoreCase(username)&&"admin".equalsIgnoreCase(password)){  //登录成功,将用户名放置到sesseion之中
      session.put("user",username);  //返回管理页面
      return"main";
    }  //返回登录页面
    return LOGIN;
  }  //注销用户
  public String logoff()throws Exception{  //逐出session中的变量
    session.remove("user");  //返回登录页面
    return LOGIN;
  }  //进入管理页面
  public String main()throws Exception{
    return SUCCESS;
  }
  public String getUsername(){
    return username;
  }
  public void setUsername(String username){
    this.username=username;
  }
  public String getPassword(){
    return password;
  }
  public void setPassword(String password){
    this.password=password;
  }
}

UserAction 类中包含 3 个成员变量,分别为 username、password 及 Map 类型的 session,这 3 个对象都是在请求中需要用到的对象,其中 username 与 password 为用户名及密码,而 session 在用户登录与用户退出操作时需要用到。

UserAction 类的 login() 方法用于对登录请求进行处理,在用户登录成功后,将用户名保存到 session 中;logoff() 方法用于对用户退出请求操作进行处理,在用户注销后,移除 session 中的所有变量;main() 方法为进入管理页面的请求处理方法。

说明:本示例主要讲解拦截器的应用,用户的登录操作并没有涉及数据库操作,只判断用户名及密码是否为字符串 "admin"。

对 Struts2 的配置文件 struts.xml 进行配置,主要配置 LoginInterceptor 拦截器以及 UserAction 对象,关键代码如下:
<struts>
  <!--声明常量(开发模式)-->
  <constant name="struts.devMode"value="true"/>
  <!--声明常量(在Struts2的配置文件修改后,自动加载)-->
  <constant name="struts.configuration.xml.reload"value="true"/>
  <!--声明包-->
  <package name="myPackge"extends="struts-default">
    <!--配置拦截器-->
    <interceptors>
      <!--验证用户登录的拦截器-->
      <interceptor name="loginInterceptor"class="com.lyq.action.LoginInterceptor"/>
    </interceptors>
    <!--配置UserAction-->
    <action name="userAction"class="com.lyq.action.UserAction">
      <!--配置返回页面-->
      <result>/main.jsp</result>
      <result name="login">/login.jsp</result>
      <result name="main"type="redirectAction">userAction!main</result>
      <!--添加验证用户登录的拦截器-->
      <interceptor-ref name="loginInterceptor">
        <param name="excludeMethods">login,logoff</param>
      <param name="includeMethods">main</param>
    </interceptor-ref>
  <!--添加默认拦截器栈-->
  <interceptor-ref name="defaultStack"/>
  </action>
</package>
</struts>

在配置文件 struts.xml 中,首先定义名为 loginInterceptor 的拦截器,然后将这个拦截器应用到 userAction 中,由于 LoginInterceptor 继承了 MethodFilterInterceptor,所以可以为 loginInterceptor 设置拦截参数。本示例中将拦截的方法设置为 "main",也就是对 main() 方法进行拦截。

注意:如果在 Action 对象的配置中应用自定义的拦截器,那么这个 Action 对象所继承的拦截器就不会被应用,所以,在设置了自定义的拦截器后,还需要添加默认的拦截器栈 "defaultStack"。

在 UserAction 的配置中,配置了 3 个返回页面,其中处理成功的返回页面为 main.jsp,用户登录的返回页面为 login.jsp,而用户登录成功后,会发出进入管理页面的请求,其地址配置为 userAction!main,也就是请求 UserAction 类的 main() 方法。

技巧:如果返回页面仍然需要交给一个 Action 对象进行处理,可以将返回结果配置成一个 Action 对象的请求地址,其请求类型配置为 "redirectAction"

创建用户登录页面 login.jsp,在此页面中放置用户登录的表单,表单的提交地址设置为 "userAction",关键代码如下:
<body>
  <s:form action="userAction" method="post">
    <s:textfield name="username" label="用户名"></s:textfield>
    <s:password name="password" label="密码"></s:password>
    <s:submit value="登录" method="login"></s:submit>
  </s:form>
  <s:a href="index.jsp">返回首页</s:a>
</body>

在 login.jsp 页面中,表单的编写使用了 Struts2 提供的表单标签进行编写,由于 UserAction 对象中处理登录请求的方法是 login() 方法,所以,本示例中将“登录”按钮的 method 属性设置值为 "login"。

技巧:如果一个 Action 对象中包含多个请求处理方法,那么在表单中的“提交”按钮上可以通过 "mthod" 属性来指定调用方法的名称。

创建名为 main.jsp 的 JSP 页面,此页面是用户登录成功后进入的管理页面,关键代码如下:
<body>
  <h1>
    管理页面
  </h1>
  <s:a action="userAction" method="logoff">退出</s:a>
  <s:a href="index.jsp">返回首页</s:a>
</body>

说明:由于本示例主要演示拦截器的定义与使用,所以在管理页面中只是象征性地设置了一些文字,代表这个页面是一个管理页面。

编写程序的首页 index.jsp,在此页面中编写两个超级链接,分别为“进入管理页面”与“登录”,关键代码如下:
<body>
  <s:a action="userAction" method="main">进入管理页面</s:a>
  <s:a href="login.jsp">登录</s:a>
</body>

在首页可以看到两个超级链接地址,分别为“进入管理页面”与“登录”。如果用户没有登录,单击“进入管理页面”超级链接,请求将被 "LoginInterceptor" 拦截器所拦截,其请求跳转到登录页面。

注意:在浏览器地址栏中可以看到地址仍然为 "userAction!main",原因是拦截器拦截了没有登录的请求,并对其进行了处理。

如果用户登录后再请求管理页面,则会成功进入管理页面,原因是拦截器对请求进行判断,会发现这是已登录的一个请求,所以,请求会继续向下执行。

所有教程

优秀文章