2

There's an issue I've experienced this day. I have an interceptor that begins and commits a Hibernate transaction and it may throw an exception on commit (org.hibernate.StaleObjectStateException for instance). That is, it can throw an exception but exception doesn't get to the handler. I thought there's an issue in my code. But then I wrote a simple test and here it is

Package definition in 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, console output :

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

BUT if an exception is thrown by BusinnesLogic, we can uncomment code:

BusinessLogic.java:

package test;

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

and comment out code in 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;
        }

output will be:

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

And we will see the error page.

So, can anybody give a good explanation of this behavior? What's the point of putting the exception interceptor at the top of the default struts stack if it can't handle exceptions that was thrown by other interceptors? and why?? I would really appreciate for a good answer.

EDIT: There is a code I have a problem with:

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;
}

What should be done if I want handle exceptions thrown on commit() ?

4

2 回答 2

3

在动作调用和结果呈现TestInterceptor 之后抛出异常。

写作拦截器页面上的注释:

请记住,调用将在调用结果后返回(例如,在呈现 JSP 之后),使其非常适合诸如 open-session-in-view 模式之类的事情。如果你想在结果被调用之前做一些事情,你应该实现一个 PreResultListener。

于 2012-07-05T01:20:28.023 回答
1

ExceptionMappingInterceptor 的核心功能

这个拦截器构成了异常处理特性的核心功能。异常处理允许您将异常映射到结果代码,就像操作返回结果代码而不是抛出意外异常一样。当遇到异常时,它会被一个 ExceptionHolder 包装并压入堆栈,从而可以从结果中轻松访问异常。注意:虽然您可以随时在配置文件中配置异常映射,但如果此拦截器不在您的操作的拦截器堆栈中,则配置不会产生任何影响。建议您将此拦截器设置为堆栈上的第一个拦截器,确保它具有捕获任何异常的完全访问权限,即使是由其他拦截器引起的异常。

示例代码:

   <xwork>
     <package name="default" extends="xwork-default">
         <global-results>
             <result name="error" type="freemarker">error.ftl</result>
         </global-results>

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

         <action name="test">
             <interceptor-ref name="exception"/>
             <interceptor-ref name="basicStack"/>
             <exception-mapping exception="com.acme.CustomException" result="custom_error"/>
             <result name="custom_error">custom_error.ftl</result>
             <result name="success" type="freemarker">test.ftl</result>
         </action>
     </package>
   </xwork>
于 2012-07-05T00:22:13.027 回答