【问题标题】:Handling service layer exception in Java EE frontend method在 Java EE 前端方法中处理服务层异常
【发布时间】:2015-09-29 20:26:21
【问题描述】:

我维护一个 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 的处理程序类。但是哪个以及如何?


已编辑

OBS 1:BusinessException 类扩展了 RuntimeException 类。

OBS 2:创建属性canCreateResource 是为了控制按钮的呈现。

【问题讨论】:

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


    【解决方案1】:

    这是因为您从 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 {
        // ...
    }
    

    总结:

    1. 事务性 EJB 方法抛出的 RuntimeException 将执行完全回滚,但异常将包装在 EJBException 中。
    2. 来自事务性 EJB 方法的 RuntimeException@ApplicationException 只会在显式设置 rollback=true 时执行完全回滚。
    3. 来自事务性 EJB 方法的Exception 不会执行完全回滚。
    4. 来自事务性 EJB 方法的 Exception@ApplicationException 只会在显式设置 rollback=true 时执行完全回滚。

    请注意,@ApplicationException 继承自自定义异常的所有子类,因此您无需对所有子类重复。最好将它作为一个抽象类。另请参阅下面链接的相关问题中的示例。

    另见:

    【讨论】:

    • 你的答案是正确的,但我决定改变,现在 BusinessException 扩展了异常(检查异常)。谢谢大佬。
    • 您仍然需要添加注释。因为,默认情况下它不会对此执行回滚。
    【解决方案2】:

    如果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(), ""));
    }
    }
    

    您还必须在您的页面中添加&lt;h:messages&gt; 标签。

    【讨论】:

    • 也许我的问题还不清楚。我编辑了 canCreateResource 方法的代码,并添加了 cmets 以改进解释。当isCoordinatortrue 时不会引发异常。该代码有效。我想了解为什么 try/catch 块不拦截抛出的异常,即当 isCoordinatorfalse 时。
    【解决方案3】:

    如果您想捕获不是您自己创建的异常(并且您无法使用 @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;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-06
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-21
      相关资源
      最近更新 更多