• Category Archives: Struts2

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

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

解决struts2中首页默认调用index的问题

在struts 2中,通过在web-xml中配置welcome-file欢迎页面来调用action是无效的。

以前是直接在index.jsp中加上这个标签 <s:action name=”index” namespace=”/”/>, 但是这样做的话, 对应index的action中result处理就不起作用了。

经过资料整理后, 最终得出我们可以在struts-xml中的action配置中加入来实现你预期的效果。

我们可以在默认的package中加上<default-action-ref name=”action名称”/>, 如:

<package name="default" namespace="/" extends="struts-default">
    <default-action-ref name="index"/>
    <action name="index" class="web.action.IndexAction" method="index">
        <result name="success">index.jsp</result>
    </action>
</package>

还有一点不要漏掉,记得清空web.xml中的welcome-file,不然默认是会被调用index.jsp的,对于某些人来说可能会造成错误:

<welcome-file-list>
    <welcome-file></welcome-file>
</welcome-file-list>

这样即可解决这个问题。

struts2自定义404错误页面

最近服务器后台出现一些异常,问题是客户访问一个该网站下不存在的action,为了给客户一个友好的界面提示以及减小服务器端日志文件的内容。就在struts2下进行了如下配置:
在struts.xml里的package下添加:

<default-action-ref name="pagenotfound"></default-action-ref>  
<action name="pagenotfound">  
    <result>/404.jsp</result>  
</action>

 

当然struts2只会处理用户访问不存在的action,当用户访问jsp或者html时,是不会处理的。
这样还要在项目的web.xml下添加:

<package name="404" extends="struts-default">
	<default-action-ref name="notFound" />
	<action name="notFound">
		<result>/404.jsp</result>
	</action>
</package>

 

close