使用 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
1 package byrs.rms.interceptors; 2 3 import com.opensymphony.xwork2.ActionContext; 4 import com.opensymphony.xwork2.ActionEventListener; 5 import com.opensymphony.xwork2.ActionInvocation; 6 import com.opensymphony.xwork2.ActionProxy; 7 import com.opensymphony.xwork2.Result; 8 import com.opensymphony.xwork2.interceptor.PreResultListener; 9 import com.opensymphony.xwork2.util.ValueStack; 10 11 public class ActionInvocationEx implements ActionInvocation { 12 13 /** 14 * 15 */ 16 private static final long serialVersionUID = 2434502343414625665L; 17 18 private final ActionInvocation mActionInvocation; 19 20 private final ActionContext context; 21 22 public ActionInvocationEx(ActionInvocation aActionInvocation,ActionContext aContext) 23 { 24 mActionInvocation = aActionInvocation; 25 context = aContext; 26 } 27 28 public Object getAction() { 29 return mActionInvocation.getAction(); 30 } 31 32 public boolean isExecuted() { 33 return mActionInvocation.isExecuted(); 34 } 35 36 public ActionContext getInvocationContext() { 37 return mActionInvocation.getInvocationContext(); 38 } 39 40 public ActionProxy getProxy() { 41 return mActionInvocation.getProxy(); 42 } 43 44 public Result getResult() throws Exception { 45 return mActionInvocation.getResult(); 46 } 47 48 public String getResultCode() { 49 return mActionInvocation.getResultCode(); 50 } 51 52 public void setResultCode(String resultCode) { 53 mActionInvocation.setResultCode(resultCode); 54 } 55 56 public ValueStack getStack() { 57 return mActionInvocation.getStack(); 58 } 59 60 public void addPreResultListener(PreResultListener listener) { 61 mActionInvocation.addPreResultListener(listener); 62 } 63 64 public String invoke() throws Exception { 65 return mActionInvocation.invoke(); 66 } 67 68 public String invokeActionOnly() throws Exception { 69 return mActionInvocation.invokeActionOnly(); 70 } 71 72 public void setActionEventListener(ActionEventListener listener) { 73 mActionInvocation.setActionEventListener(listener); 74 } 75 76 public void init(ActionProxy proxy) { 77 mActionInvocation.init(proxy); 78 } 79 80 public ActionInvocation serialize() { 81 return mActionInvocation.serialize(); 82 } 83 84 public ActionInvocation deserialize(ActionContext actionContext) { 85 return mActionInvocation.deserialize(actionContext); 86 } 87 88 /** 89 * @return the context 90 */ 91 public ActionContext getContext() { 92 return context; 93 } 94 95 }
ExecAndWaitInterceptorEx.java
1 package byrs.rms.interceptors; 2 3 import org.apache.struts2.interceptor.BackgroundProcess; 4 import org.apache.struts2.interceptor.ExecuteAndWaitInterceptor; 5 6 import com.opensymphony.xwork2.ActionContext; 7 import com.opensymphony.xwork2.ActionInvocation; 8 9 public class ExecAndWaitInterceptorEx extends ExecuteAndWaitInterceptor { 10 11 /** 12 * 13 */ 14 private static final long serialVersionUID = 8829373762598564300L; 15 16 /** 17 * {@inheritDoc} 18 */ 19 @Override 20 protected BackgroundProcess getNewBackgroundProcess(String arg0, ActionInvocation arg1, int arg2) { 21 ActionInvocationEx aActionInvocationEx = new ActionInvocationEx(arg1,ActionContext.getContext()); 22 return new BackgroundProcessEx(arg0, aActionInvocationEx, arg2); 23 } 24 25 private class BackgroundProcessEx extends BackgroundProcess { 26 public BackgroundProcessEx(String threadName, 27 ActionInvocation invocation, int threadPriority) { 28 super(threadName, invocation, threadPriority); 29 } 30 31 private static final long serialVersionUID = -9069896828432838638L; 32 /** 33 * {@inheritDoc} 34 * @throws InterruptedException 35 */ 36 @Override 37 protected void beforeInvocation() throws InterruptedException { 38 ActionInvocationEx aActionInvocationEx = (ActionInvocationEx)this.invocation; 39 ActionContext context = aActionInvocationEx.getContext(); 40 ActionContext.setContext(context); 41 } 42 43 /** 44 * {@inheritDoc} 45 */ 46 @Override 47 protected void afterInvocation() { 48 ActionContext.setContext(null); 49 } 50 51 } 52 53 }
然后在struts.xml中覆盖默认拦截器即可
1 <interceptors > 2 <interceptor name="execAndWait" class="byrs.rms.interceptors.ExecAndWaitInterceptorEx"/> 3 </interceptors >
参考自:http://www.mobibrw.com/?p=1046