首页 > 代码库 > Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法

Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法

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