在 Struts 2 中使用 execAndWait 拦截器在 com.opensymphony.xwork2.util.LocalizedTextUtil.findText() 处出现 java.lang.NullPointerException

问题描述 投票:0回答:3

我有一个

login
屏幕,其中发生了一些用户的输入验证,用户将通过身份验证并最终重定向到
welcome
屏幕。

下面是

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. 对于未经身份验证的用户,我收到以下异常:

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)
struts2 struts-validation struts2-interceptors
3个回答
4
投票
  1. execAndWait
    导致操作在新线程中执行。
  2. 由于
    ActionContext
    ThreadLocal
    ,新线程将不会获取父线程版本
    ActionContext
    中存储的值。每个线程都有一个独特的
    ActionContext
  3. 版本
  4. getText()
    尝试在新线程中执行时会抛出NPE,因为它依赖于
    ActionContext

要解决此问题,您需要将父线程

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);
    }

}

3
投票
发生

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

为了在流程结束后显示成功页面,您需要不时刷新页面。在示例中,它是通过

meta http-equiv="refresh"
完成的。

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

1
投票

在您的操作或应用程序提供的资源中找不到密钥

"error.login"
,或者您使用了错误的区域设置。这意味着您尚未配置
i18n
资源。要解决您的问题,您需要创建
LoginAction.properties
文件并将密钥放入其中

error.login = Error login

如果您使用的全局属性文件在您的帖子中没有看到,请在其中添加此键。

© www.soinside.com 2019 - 2024. All rights reserved.