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