我维护一个Web应用程序,其中包含一个带有JSF标记<f:event
的页面。我在服务类中重写了一个方法,以便抛出一个业务异常。但是,当抛出业务异常时,它不会被托管bean捕获,并且页面上会显示异常。似乎我的代码try/catch
不起作用。
在XHTML中:
<f:event listener="#{resourceBean.init(enrollment)}" type="preRenderView" />
Managed Bean中的监听器方法:
private boolean canCreateResource;
public void init(Enrollment enrollment) {
(...)
try {
canCreateResource = resourceService.canCreateResource(enrollment);
} catch (BusinessException e) {
canCreateResource = false;
}
}
服务类中的方法:
public boolean canCreateResource(Enrollment enrollment) {
if (...) {
if (mandateService.isCoordinator(user, course)) {
return true;
} else {
throw new BusinessException("Undefined business rule.");
}
}
return false;
}
从我在其他网站上看到的内容,我想我必须实现一些JSF的处理程序类。但是哪个以及如何?
EDITED
OBS 1:BusinessException
类扩展RuntimeException
类。
OBS 2:创建了属性canCreateResource
来控制按钮的渲染。
答案 0 :(得分:10)
这是因为你从EJB中抛出了RuntimeException
。
当RuntimeException
没有注释@ApplicationException
时,EJB容器会将其包装在javax.ejb.EJBException
中并重新抛出它。这样做是因为运行时异常通常仅用于指示代码逻辑中的错误,即程序员的错误而不是最终用户的错误。您知道,NullPointerException
,IllegalArgumentException
,IndexOutOfBoundsException
,NumberFormatException
和朋友。这允许EJB客户端为此类运行时异常提供一个全能点,例如catch (EJBException e) { There's a bug in the service layer or in the way how we are using it! }
如果你曾尝试catch (Exception e)
并检查了实际的异常,那么你已经注意到了。
相应地修复你的BusinessException
类以添加该注释,然后它将被识别为真正的应用程序异常,而不是包含在EJBException
中:
@ApplicationException(rollback=true)
public class BusinessException extends RuntimeException {
// ...
}
请注意,如果您抛出非RuntimeException
,那么您仍然需要使用rollback=true
显式地保留注释,因为默认情况下它不会执行回滚,与没有注释的RuntimeException
相反。
@ApplicationException(rollback=true)
public class BusinessException extends Exception {
// ...
}
总结:
RuntimeException
将执行完全回滚,但异常将包含在EJBException
中。RuntimeException
的@ApplicationException
只会在显式设置rollback=true
时执行完全回滚。Exception
将不执行完全回滚。Exception
的@ApplicationException
只会在显式设置rollback=true
时执行完全回滚。请注意,@ApplicationException
是在自定义异常的所有子类上继承的,因此您无需在所有子类上重复它。最好将它作为一个抽象类。另见下面链接的相关问题中的示例。
答案 1 :(得分:1)
如果isCoordinator
方法最终会抛出异常,则应在canCreateResource
方法中添加try catch块。您可以抛出自己的异常或传播原始异常。在这两种情况下,您都必须在方法签名中声明它。如果你抛出BusinessException
:
public void canCreateResource(Enrollment enrollment) throws BusinessException
不要返回任何值。或者返回一个布尔值但不抛出任何异常。
在init
方法内的catch块中添加Facelet消息异常:
...
} catch (BusinessException e) {
this.canCreateResource = false;
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
}
}
同样在您的网页中,您必须添加<h:messages>
代码。
答案 2 :(得分:0)
如果你想捕获一个你自己没有创建的异常(并且你无法使用@ApplicationException
进行批注),你可以捕获所有异常并查看其中一个原因是否属于你的类型想抓住。
您可以递归检查异常的原因:
public static <T extends Throwable> T getCauseOfType(final Throwable throwable,
final Class<T> type) {
if (throwable == null) {
return null;
}
return type.isInstance(throwable) ? (T) throwable : getCauseOfType(throwable.getCause(), type);
}
public static <T extends Throwable> boolean hasCauseOfType(final Throwable throwable,
final Class<T> type) {
return getCauseOfType(throwable, type) != null;
}
你可以使用它:
try {
...
}
catch (Exception e) {
if (hasCauseOfType(e, SomeException.class)) {
// Special handling
}
else {
throw e;
}
}