在Java EE前端方法中处理服务层异常

时间:2015-09-29 20:26:21

标签: jsf java-ee exception-handling ejb service-layer

我维护一个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来控制按钮的渲染。

3 个答案:

答案 0 :(得分:10)

这是因为你从EJB中抛出了RuntimeException

RuntimeException没有注释@ApplicationException时,EJB容器会将其包装在javax.ejb.EJBException中并重新抛出它。这样做是因为运行时异常通常仅用于指示代码逻辑中的错误,即程序员的错误而不是最终用户的错误。您知道,NullPointerExceptionIllegalArgumentExceptionIndexOutOfBoundsExceptionNumberFormatException和朋友。这允许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 {
    // ...
}

总结:

    从事务EJB方法抛出的
  1. RuntimeException将执行完全回滚,但异常将包含在EJBException中。
  2. 事务EJB方法中带有RuntimeException
  3. @ApplicationException只会在显式设置rollback=true时执行完全回滚。
  4. 来自事务EJB方法的
  5. Exception将不执行完全回滚。
  6. 事务EJB方法中带有Exception
  7. @ApplicationException只会在显式设置rollback=true时执行完全回滚。
  8. 请注意,@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;
  }
}