使用 Struts2 编写页面,遇到一个要长时间运行的接口,因此增加了一个execAndWait ,结果在 Action 中调用 getContext()的时候报告异常
1 ActionContext context = ActionContext.getContext();
2 ServletContext servletContext = (ServletContext) context.get(ServletActionContext.SERVLET_CONTEXT); //抛空指针异常
3 String rootPath = servletContext.getRealPath("/");
查询了很多评论,最终找到原因跟解决方案,具体解释在 http://stackoverflow.com/questions/16692658/execandwait-interceptor-not-redirecting-to-success-page-after-waiting。大致意思为:execAndWait 会导致执行的Action 在另外一个线程中被执行,而getText 依赖 ActionContext ,他从 ActionContext 中获得当前的Locale 从而根据语言的不同加载不同的文字,可是,由于ActionContext 是ThreadLocal 的,而execAndWait 新开线程的时候并没有把父线程的ActionContext 传递给子线程 结果导致在新开的子线程中的ActionContext中的数据都是null ,因此出现异常信息就不足为怪了。
解决方法如下:需要重载两个类,来解决这个问题
ActionInvocationEx.java
package byrs.rms.interceptors;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionEventListener;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.interceptor.PreResultListener;
import com.opensymphony.xwork2.util.ValueStack;
public class ActionInvocationEx implements ActionInvocation {
/**
*
*/
private static final long serialVersionUID = 2434502343414625665L;
private final ActionInvocation mActionInvocation;
private final ActionContext context;
public ActionInvocationEx(ActionInvocation aActionInvocation,ActionContext aContext)
{
mActionInvocation = aActionInvocation;
context = aContext;
}
public Object getAction() {
return mActionInvocation.getAction();
}
public boolean isExecuted() {
return mActionInvocation.isExecuted();
}
public ActionContext getInvocationContext() {
return mActionInvocation.getInvocationContext();
}
public ActionProxy getProxy() {
return mActionInvocation.getProxy();
}
public Result getResult() throws Exception {
return mActionInvocation.getResult();
}
public String getResultCode() {
return mActionInvocation.getResultCode();
}
public void setResultCode(String resultCode) {
mActionInvocation.setResultCode(resultCode);
}
public ValueStack getStack() {
return mActionInvocation.getStack();
}
public void addPreResultListener(PreResultListener listener) {
mActionInvocation.addPreResultListener(listener);
}
public String invoke() throws Exception {
return mActionInvocation.invoke();
}
public String invokeActionOnly() throws Exception {
return mActionInvocation.invokeActionOnly();
}
public void setActionEventListener(ActionEventListener listener) {
mActionInvocation.setActionEventListener(listener);
}
public void init(ActionProxy proxy) {
mActionInvocation.init(proxy);
}
public ActionInvocation serialize() {
return mActionInvocation.serialize();
}
public ActionInvocation deserialize(ActionContext actionContext) {
return mActionInvocation.deserialize(actionContext);
}
/**
* @return the context
*/
public ActionContext getContext() {
return context;
}
}
ExecAndWaitInterceptorEx.java
package byrs.rms.interceptors;
import org.apache.struts2.interceptor.BackgroundProcess;
import org.apache.struts2.interceptor.ExecuteAndWaitInterceptor;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
public class ExecAndWaitInterceptorEx extends ExecuteAndWaitInterceptor {
/**
*
*/
private static final long serialVersionUID = 8829373762598564300L;
/**
* {@inheritDoc}
*/
@Override
protected BackgroundProcess getNewBackgroundProcess(String arg0, ActionInvocation arg1, int arg2) {
ActionInvocationEx aActionInvocationEx = new ActionInvocationEx(arg1,ActionContext.getContext());
return new BackgroundProcessEx(arg0, aActionInvocationEx, arg2);
}
private class BackgroundProcessEx extends BackgroundProcess {
public BackgroundProcessEx(String threadName,
ActionInvocation invocation, int threadPriority) {
super(threadName, invocation, threadPriority);
}
private static final long serialVersionUID = -9069896828432838638L;
/**
* {@inheritDoc}
* @throws InterruptedException
*/
@Override
protected void beforeInvocation() throws InterruptedException {
ActionInvocationEx aActionInvocationEx = (ActionInvocationEx)this.invocation;
ActionContext context = aActionInvocationEx.getContext();
ActionContext.setContext(context);
}
/**
* {@inheritDoc}
*/
@Override
protected void afterInvocation() {
ActionContext.setContext(null);
}
}
}
然后在struts.xml中覆盖默认拦截器即可
<interceptors >
<interceptor name="execAndWait" class="byrs.rms.interceptors.ExecAndWaitInterceptorEx"/>
</interceptors >
参考自:http://www.mobibrw.com/?p=1046