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