问题
I have a login screen where some user input validation will happen, the user will be authenticated and finally redirected to the welcome screen.
Below is the interceptor definition for the 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>
Below is the execute method of LoginAction
:
if (isUserAuthenticated) {
// Some background processing for logging purpose
return "success";
} else {
addActionError(getText("error.login"));
return "error";
}
I am having a couple of problems with this code:
1) For an authenticated user, the wait.jsp
page is getting displayed but the redirection to Welcome.jsp
is not happening.
2) for an unAuthenticated user, I am getting the below exception:
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)
回答1:
execAndWait
causes the action to be executed in a new thread.- Since
ActionContext
isThreadLocal
, the new thread will not get the values stored in the parent thread version ofActionContext
. Every thread has a unique version ofActionContext
getText()
will throw a NPE when it tries to execute in the new thread because it depends onActionContext
To fix this, you need to copy the parent threads ActionContext
into the execAndWait
thread. You can do this by extending the BackgroundProcess
class, implementing the beforeInvocation()
and afterInvocation()
methods, and extending ExecuteAndWaitInterceptor
, implementing the getNewBackgroundProcess()
method.
EXAMPLE
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);
}
}
回答2:
NPE
is happening because the action with execAndWait
interceptor is running in a separate thread and you are calling getText
method which uses ActionContext
. ActionContext
is thread local which means that values stored in the ActionContext are unique per thread.
In order to show success page after process is over you need to refresh page time to time. In examples it is done with meta http-equiv="refresh"
.
<meta http-equiv="refresh" content="5;url=<s:url includeParams="all" />"/>
回答3:
The key "error.login"
is not found in the resources supplied with your action or application or you have used wrong locale. That means that you have not i18n
resources configured. To resolve your issue you need to create LoginAction.properties
file and put the key inside it
error.login = Error login
If you are using global properties file that is not seen from your post, then add this key there.
来源:https://stackoverflow.com/questions/16692658/execandwait-interceptor-not-redirecting-to-success-page-after-waiting