execAndWait Interceptor等待后不会重定向到成功页面

时间:2013-05-22 13:09:06

标签: struts2 struts-validation struts2-interceptors

我有一个登录界面,会进行一些用户输入验证,用户将被验证并最终重定向到欢迎屏幕。

以下是LoginAction的拦截器定义:

<package name="default" extends="struts-default" namespace="/">
    <interceptors>  
        <interceptor name="myInterceptor" 
            class="com.interceptor.MyInterceptor"></interceptor>

        <interceptor-stack name="newStack">
            <interceptor-ref name="myInterceptor"/>             
            <interceptor-ref name="defaultStack" />
            <interceptor-ref name="execAndWait">
                <param name="delay">100</param>
                <param name="delaySleepInterval">500</param>
            </interceptor-ref>              
         </interceptor-stack> 
    </interceptors>

    <action name="login"
        class="com.action.LoginAction"> 
        <interceptor-ref name="newStack"/>
        <result name="success">common/Welcome.jsp</result>
        <result name="wait">common/wait.jsp</result>
        <result name="error">Login.jsp</result>
        <result name="input">Login.jsp</result>
    </action>
</package>

以下是LoginAction的执行方法:

   if (isUserAuthenticated) {
        // Some background processing for logging purpose           
        return "success";
    } else {            
        addActionError(getText("error.login"));
        return "error";
    }

我在使用此代码时遇到了一些问题:

1)对于经过身份验证的用户,会显示wait.jsp页面,但未发生重定向到Welcome.jsp

2)对于unAuthenticated用户,我收到以下异常:

java.lang.NullPointerException
at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:361)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:208)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:123)
at com.opensymphony.xwork2.ActionSupport.getText(ActionSupport.java:103)
at com.infy.action.LoginAction.execute(LoginAction.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
at org.apache.struts2.interceptor.BackgroundProcess$1.run(BackgroundProcess.java:57)
at java.lang.Thread.run(Thread.java:662)

3 个答案:

答案 0 :(得分:4)

  1. execAndWait导致操作在新线程中执行。
  2. 由于ActionContextThreadLocal,新线程将无法获取存储在ActionContext的父线程版本中的值。每个帖子都有ActionContext
  3. 的唯一版本
  4. getText()在尝试在新线程中执行时会抛出NPE,因为它取决于ActionContext
  5. 要解决此问题,您需要将父线程ActionContext复制到execAndWait线程中。您可以通过扩展BackgroundProcess类,实施beforeInvocation()afterInvocation()方法,以及扩展ExecuteAndWaitInterceptor,实施getNewBackgroundProcess()方法来实现此目的。

    实施例

    public class YourExecAndWaitInterceptor extends ExecuteAndWaitInterceptor {
    
        private static final long serialVersionUID = 1L;
    
    
        /**
         * {@inheritDoc}
         */
        @Override
        protected BackgroundProcess getNewBackgroundProcess(String arg0, ActionInvocation arg1, int arg2) {
            return new YourBackgroundProcess(arg0, arg1, arg2, ActionContext.getContext());
        }
    
    }
    
    
    
    public class YourBackgroundProcess extends BackgroundProcess {
    
        private final ActionContext context;
    
        public YourBackgroundProcess(String threadName, ActionInvocation invocation, int threadPriority, ActionContext context) {
            super(threadName, invocation, threadPriority);
            this.context = context;
         }
    
        /**
         * {@inheritDoc}
         */
        @Override
        protected void beforeInvocation() {
            ActionContext.setContext(context);
        }
    
        /**
         * {@inheritDoc}
         */
       @Override
        protected void afterInvocation() {
            ActionContext.setContext(null);
        }
    
    }
    

答案 1 :(得分:3)

NPE正在发生,因为execAndWait拦截器的操作正在一个单独的线程中运行,而您正在调用使用getText的{​​{1}}方法。 ActionContext是本地线程,这意味着存储在ActionContext中的值对于每个线程都是唯一的。

为了在流程结束后显示成功页面,您需要不时刷新页面。在examples ActionContext完成了meta http-equiv="refresh"

<meta http-equiv="refresh" content="5;url=<s:url includeParams="all" />"/> 

答案 2 :(得分:1)

在您的操作或应用程序提供的资源中找不到密钥"error.login",或者您使用了错误的区域设置。这意味着您没有配置i18n个资源。要解决您的问题,您需要创建LoginAction.properties文件并将密钥放在其中

error.login = Error login

如果您使用的是从帖子中看不到的全局属性文件,请在此处添加此密钥。