简单的Struts2的Interceptors(拦截器)机制介绍以及利用拦截器实现用户登陆时执行耗时操作并自动跳转的实例

    咳咳,标题有点长。话说也好久没有更文了。最近学校在学习Struts2,哎,感觉根本没上什么哇,教程都是用网上的。。。上周布置一作业说利用拦截器实现用户登陆时进行耗时操作并在完成之后进行页面跳转。看似很简单,但是对我这样的初学者来说还是有难度的。老师给的教程上的内容又太简单,百度也找不到我想要的答案,怎么办呢?最后还是要靠官方的文档,不了解Struts2拦截器的机制真的做起来很被动啊!最近也在准备CET6,就当是阅读练习吧,实际去看全英文文档的时候,发现其实也不难懂~下面的分析是基于自己的理解和Apache Struts2的官方文档,如果有不足之处还请指正。

  一、Struts2拦截器的概念

           有时候我们想在Action中做一些诸如输入验证、文件上传或者防止重复提交表单的操作,Struts2提供了一种策略,叫做拦截器,当你请求Action的时候,Struts2框架调用这个Action,但是在Action被执行之前或者Action执行之后,拦截器会起作用,这个要取决于配置。这样就能起到比较好的安全性,同时也能达到我们的目的。拦截器是一个很便携的插件,可以根据我们实际的逻辑需求进行增加或者删除,或者自己编程实现。

 二、Strtus2拦截器的运行机制

      首先我们先来看一下在Struts2里Action的生命周期

                                           

                                                                         (图片来自Apache Struts2官方)

        从图中不难看出,当用户发起请求时,由ServletDispatcher(Servlet调度器)实例化一个ActionProxy(Action代理)对象,要想执行这个Action,用户的请求必须突破重重的Interceptor(拦截器),就像在G20峰会时我们去杭州一样,安检重重呐!这样的目的一是为了可以进行一些耗时操作,二是为了安全。当这个Action执行完毕之后,Action会把结果传送出去。

   Struts2的拦截器是一个栈结构,所以说,拦截器的安放顺序非常重要,这个安放顺序将决定了你的Action是否能被顺利执行。

  在准备执行Action前或者执行后,拦截器(如果我们有明确定义的话),将会起到拦截请求的作用,此时,只有Action里的execute方法会被调用(这里指的是我们自定义拦截器栈的情况,并且没有引入官方的defaultStack拦截器栈。如果我们在拦截器栈中引入了官方的defaultStack的话,将会先执行validate方法,再执行execute方法),业务逻辑也要写在execute方法里,需要注意的是,一些特定的拦截器,比如 Execute and Wait Interceptor(执行并等待拦截器),一旦某个Action被设置了这个拦截器,则这个Action在工作时会独立于主线程,这样会导致我们无法像原来一样使用get方法获取到原来属性被设置的值,会抛出NullPointer Exception(空指针异常),这个需要根据实际情况对其他的拦截器进行设置。因此,Execute and Wait Interceptor必须位于拦截器栈的栈底。例如后面的实例。

 在Struts2里官方提供的拦截器有很多,每个拦截器或多或少都有自己的参数,要注意查文档,有些参数不能混用!

 三、实例(实现用户登陆时执行耗时操作并在任务完成后进行页面跳转)

  在这个例子中,我们将自定义拦截器的栈结构,并且不引入官方的defaultStack拦截器栈

  1、知识储备

        a、这里要用到三个Struts2的内置拦截器Parameters Interceptor(参数拦截器)、Validation Interceptor(验证拦截器)和 Execute and Wait Interceptor(执行且等待拦截器),根据官方文档,他们的功能如下

   Parameters Interceptor : Sets the request parameters onto the Action.

  解释:将用户的请求参数(一般是表单)设置进入Action里,也就是调用在某个Action中我们已经定义好的set方法。

  Validation Interceptor:This interceptor runs the action through the standard validation framework, which in turn checks the action against any validation rules.

  解释:这个验证拦截器会在验证框架启动时验证用户的输入数据,如果我们有定义action-validation.xml(eg.LoginAction-validation.xml),该拦截器将会调用它。需要注意的是,在这个验证拦截器中,默认放行在Action中的validate方法,并且提供excludeMethods和includeMethods属性。这两个属性的意思是:exclude,在英文中的解释是排他的,也就是说在拦截器运行时将忽略这个方法。include与之对应,将在拦截器运行时放行这个方法。

  Execute and Wait Interceptor:Executes the Action in the background and then sends the user off to an intermediate waiting page.

 解释:这个拦截器会在后台执行耗时操作,并且让用户看到等待界面。需要注意的是,这个拦截器在工作的时候,是独立与主线程的,所以要获取Session数据的时候需要使用到SessionAware方法,本例子没有用到,就不展开叙述。这个拦截器提供threadPriority、delay、delaySleepInterval属性。第一个threadPriority属性故名思意就是线程的优先级,默认值为Thread.NORM_PRIORITY。第二个delay,延迟,也就是说延迟几毫秒向用户展示等待界面,默认是没有设置延迟时间的。第三个delaySleepInterval,这个属性只能与delay属性一并使用,将设置一个毫秒数表示每隔多少毫秒,自动检测后台耗时操作是否完成。在这个拦截器中,如果被检测到后台耗时任务未完成,将返回结果wait。

  b、在这个实例中,还将用到ActionError与ActionMessage方法,这两个方法的作用是设置Action执行时的结果信息,他们继承自ActionSupport类。

2、项目的目录结构(由易百教程改编)

It based on this webside 

http://www.yiibai.com/struts_2/struts-2-actionerror-actionmessage-example.html

项目结构:

  

其中*.properties文件可以在新建文件时选则file或者在项目外创建完拖入

LoginAction.properties内容如下

#Welcome messages
welcome.hello = 你好
#error message
username.required = 用户名不可以为空
password.required = 密码不可以为空
global.properties内容如下

#Global messages
global.username = 用户名
global.password = 密码
global.submit = 提交
global.reset = 重置

LoginAction.java文件如下


package org.myweb.action;
import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport
{

   private String user;
   private String password;
   private boolean isValidate = false;
   
   public void setUser(String user) {
	this.user = user;
   }
   
   public void setPassword(String password) {
	this.password = password;
   }
   
   public String getUser() {
	return user;
   }
   
   public String getPassword() {
	return password;
   }
   
   public String execute()
   {
	   for(int i = 0 ; i < 1000000 ; i++)
	   {
		   System.out.println(i);
	   }
	   validate();
	   if(this.isValidate)
	   {
		   return "success";
	   }
	   else
	   {
		   return "input";
	   }
   }
   
   public void validate()
   {
	   if(getUser().equals("abc") && getPassword().equals("abc"))
	   {
		   addActionMessage("OK");
		   this.isValidate = true;
	   }
	   else
	   {
	      addActionError("FAILED");
	   }
   }
}

 在这个登陆的Action中,设置了execute方法,执行100万次循环,模拟耗时操作,同时,设置了validate方法,用于验证,如果验证成功isValidate属性将变为true,在execute的耗时操作执行完毕之后,将根据这个属性的值返回不同的结果。

 struts.xml文件如下

  

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
   <constant name="struts.custom.i18n.resources" value="global" />
    <package name="user" namespace="/user" extends="struts-default">
     <action name="login">
	 <result>/pages/login.jsp</result>
     </action>
     <action name="loginAction" class="org.myweb.action.LoginAction">
     <interceptor-ref name="params"/>
       <interceptor-ref name="validation">
           <param name="includeMethods">getUser,getPassword</param>
      </interceptor-ref>
	   <interceptor-ref name="execAndWait">
		        <param name="delay">1000</param>
		        <param name="delaySleepInterval">500</param>
		</interceptor-ref>
	    <result name="wait">/pages/wait.jsp</result>
	    <result name="success">/pages/welcome.jsp</result>
	    <result name="input">/pages/login.jsp</result>

     </action>
   </package>
</struts>    
  我定义了以上提及的三个拦截器,第一层是参数拦截器prams,用于给Action设置用户提交过来的用户名和密码,第二层是验证拦截器validation,并且放行了getUser和getPassword方法,用于用户验证,第三层是执行且等待拦截器,设置为延迟1秒向用户展示等待界面,每隔500毫秒检测耗时操作是否完毕。这就是一个简单的拦截器的Stack结构,真正运行时,将依照这个结构执行。

  执行的机制是,先设置参数,再放行validate、getUser、getPassword方法,最后调用execute方法,所有被放行的方法都要通过走execute方法才能被调用!

  login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Struts2 ActionError & ActionMessage 示例</title>
<style type="text/css">
.errors {
    background-color:#FFCCCC;
    border:1px solid #CC0000;
    width:400px;
    margin-bottom:8px;
}
.errors li{ 
    list-style: none; 
}
</style>
</head>
<body>
<h1>Struts2 Delay Login</h1>
<s:if test="hasActionErrors()">
   <div class="errors">
      <s:actionerror/>
   </div>
</s:if>
<s:form action="loginAction" method="post">
    <s:textfield key="global.user" name="user"/>
    <s:password key="global.password" name="password"/>
    <s:submit key="global.submit" name="submit"/>
</s:form>
</body>
</html>
 wait.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
   <meta http-equiv="refresh" content="5;url=<s:url />"/>
    <title>My JSP 'wait.jsp' starting page</title>
    
  </head>
  
  <body>
    <h2>Please wait until the 1 million loops complete!</h2>
  </body>
</html>

welcome.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Struts2 Delay Login</title>
<style type="text/css">
.welcome {
    background-color: #DDFFDD;
    border: 1px solid #009900;
    width: 200px;
}
.welcome li {
    list-style: none;
}
</style>
</head>
<body>
    <h1>Struts 2 ActionError & ActionMessage示例</h1>
    <s:if test="hasActionMessages()">
        <div class="welcome">
            <s:actionmessage />
        </div>
    </s:if>
    <h4>
        <s:property value="getText('welcome.hello')" />
        <s:property value="username" />
    </h4>
</body>
</html>

运行效果如下:





MyEclipse后台


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值