今天我遇到了一个问题。我有一个拦截器,它开始并提交一个Hibernate事务,它可能会在commit(例如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");
}
}
所以,控制台输出:
test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
但如果BusinnesLogic抛出异常,我们可以取消注释代码:
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()
上抛出处理异常,该怎么办?
答案 0 :(得分:2)
在动作调用和结果呈现之后TestInterceptor
抛出异常。
来自Writing Interceptors page上的说明:
请记住,在调用结果之后(例如,在渲染JSP之后)将返回invoke,这使得它非常适合开放式会话视图模式。如果要在调用结果之前执行某些操作,则应实现PreResultListener。
答案 1 :(得分: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>