使用 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