拦截器抛出的异常不会转到异常处理程序。

今天我遇到了一个问题。我有一个拦截器,它开始并提交Hibernate事务,它可能在提交时抛出异常(例如org.hibernate.StaleObjectStateException)。也就是说,它可以抛出异常,但异常不会到达处理程序。我以为我的代码有问题。但后来我写了一个简单的测试,结果是

struts.xml中的包定义:

<package name="basicstruts2" namespace="/" extends="struts-default">
    <interceptors>
        <interceptor name="dummy" class="test.TestInterceptor"/>

        <interceptor-stack name="myStack">
            <interceptor-ref name="defaultStack" />
            <interceptor-ref name="dummy" />
        </interceptor-stack>
    </interceptors>

    <default-interceptor-ref name="myStack"/>

    <global-results>
        <result name="exception" type="chain">exceptionHandler</result>
    </global-results>

    <global-exception-mappings>
        <exception-mapping exception="java.lang.Exception" result="exception" />
    </global-exception-mappings>

    <action name="test" class="test.TestAction">
        <result>result.jsp</result>
    </action>

    <action name="exceptionHandler" class="test.ExceptionHandler">
        <result>DebugErrorPage.jsp</result>
    </action>
</package>

TestAction.java

package test;

public class TestAction extends ActionSupport {

    private BusinessLogic logic = new BusinessLogic();

    public String execute() {
        logic.test();
        return SUCCESS;
    }
}

TestInterceptor.java

package test;

public class TestInterceptor implements Interceptor {

    @Override
    public String intercept(ActionInvocation arg0) throws Exception {
        String result = null;
        try {
            result = arg0.invoke();
            boolean flag = true;
            if (flag) throw new RuntimeException("qwerty");
        } catch (Exception e) {
            System.out.println("exception catched in interceptor, rethrowing " + e);
            throw e;
        }
        return result;
    }

}

ExceptionHandler.java

package test;

public class ExceptionHandler extends ActionSupport {

    private Exception exception;

    public void setException(Exception e) {
        exception = e;
        System.out.println("setting exception");
    }

    public String execute() {
        System.out.println("exeption in handler " + exception);
        return SUCCESS;
    }

}

BusinessLogic.java

package test;

public class BusinessLogic {
    public void test() {
        System.out.println("test logic");
//      boolean flag = true;
//      if (flag) throw new RuntimeException("qwerty");
    }
}

so,控制台输出:

test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty

但如果BusinessLogic抛出异常,我们可以取消对代码的注释:

BusinessLogic.java

package test;

public class BusinessLogic {
    public void test() {
        System.out.println("test logic");
        boolean flag = true;
        if (flag) throw new RuntimeException("qwerty");
    }
}

并注释掉拦截器中的代码:

@Override
        public String intercept(ActionInvocation arg0) throws Exception {
            String result = null;
            try {
            result = arg0.invoke();
        //  boolean flag = true;
        //  if (flag) throw new RuntimeException("qwerty");
            } catch (Exception e) {
                System.out.println("exception catched in interceptor, rethrowing " + e);
                throw e;
            }
            return result;
        }

输出将为:

test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
setting exception
exeption in handler java.lang.RuntimeException: qwerty

我们将看到错误页面。

那么,有没有人能很好地解释这种行为呢?如果异常拦截器不能处理其他拦截器抛出的异常,那么将异常拦截器放在默认Struts堆栈的顶部有什么意义?为什么?? 如果您能给我一个好的答复,我将不胜感激。

编辑: 有一个代码我有问题:

public String intercept(ActionInvocation arg0) throws Exception {
    String result = null;

    try {

        sf.getCurrentSession().beginTransaction();

        result = arg0.invoke();

        sf.getCurrentSession().getTransaction().commit();

    } catch (StaleObjectStateException staleEx) {
        if (sf.getCurrentSession().getTransaction().isActive()) {
            sf.getCurrentSession().getTransaction().rollback();
        }
        throw staleEx;

    } catch (Exception ex) {
        ex.printStackTrace();
        try {
            if (sf.getCurrentSession().getTransaction().isActive()) {
                sf.getCurrentSession().getTransaction().rollback();
            }
        } catch (Throwable rbEx) {
        }

        // Let others handle it... maybe another interceptor for exceptions?
        throw new ServletException(ex);
    }

    return result;
}

如果我希望处理commit()引发的异常,该怎么办?


解决方案

该异常由TestInterceptor在操作调用和结果呈现后引发。

来自Writing Interceptors page上的备注:

请记住,Invoke将在调用结果之后返回(例如。在呈现了您的JSP后),这使得它非常适合于打开视图中的会话模式之类的东西。如果要在调用结果之前执行某些操作,则应实现PreResultListener。

相关文章