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