我有一个
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";
}
我在使用这段代码时遇到了一些问题:
对于经过身份验证的用户,会显示
wait.jsp
页面,但不会重定向到 Welcome.jsp
。
对于未经身份验证的用户,我收到以下异常:
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)
execAndWait
导致操作在新线程中执行。ActionContext
是ThreadLocal
,新线程将不会获取父线程版本ActionContext
中存储的值。每个线程都有一个独特的 ActionContext
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);
}
}
NPE
是因为 execAndWait
拦截器的操作正在单独的线程中运行,并且您正在调用使用 getText
的 ActionContext
方法。 ActionContext
是线程本地的,这意味着存储在 ActionContext 中的值对于每个线程都是唯一的。
为了在流程结束后显示成功页面,您需要不时刷新页面。在示例中,它是通过
meta http-equiv="refresh"
完成的。
<meta http-equiv="refresh" content="5;url=<s:url includeParams="all" />"/>
在您的操作或应用程序提供的资源中找不到密钥
"error.login"
,或者您使用了错误的区域设置。这意味着您尚未配置 i18n
资源。要解决您的问题,您需要创建 LoginAction.properties
文件并将密钥放入其中
error.login = Error login
如果您使用的全局属性文件在您的帖子中没有看到,请在其中添加此键。