如何在Web应用程序中处理业务错误?

时间:2009-05-15 22:03:45

标签: web-applications error-handling spring-mvc

假设我有一个可以将人员存储在数据库中的Web应用程序。每个人必须拥有唯一的电子邮件地址(或用户名或其他)。如果用户尝试添加具有已存在的电子邮件地址的Person,则应返回表单并显示错误消息(就像在典型的验证失败期间一样)。

这种错误最常见的是从服务层到控制器然后再到视图?服务方法是否应该为控制器捕获异常,或者返回值或某种结果对象?

如果我最终想要使用我的服务层来生成Web服务,这是否会改变我的工作方式?

任何有关最佳做法/样本申请的建议或链接都​​将受到赞赏。

6 个答案:

答案 0 :(得分:3)

基本上有两种方法:异常并返回业务规则验证的结果。每种方式都有其优点和缺点,但基本上是:

例外:

  • 您当时只能返回一个失败的结果
  • 异常易于实现,不会使您的业务逻辑复杂化 - 只需检查条件并抛出业务异常
  • 例外仅适用于阻止规则
  • 打开的交易可以轻松回滚

业务规则验证:

  • 您可以检查多个业务规则并将损坏的列表返回给用户
  • 多个规则会使逻辑流程变得复杂,因为它们会使方法
  • 中的返回类型变得混乱
  • 它们允许处理更多场景,例如非阻塞信息规则

我认为这在很大程度上取决于应用哪种方法更适合,所以没有简单的答案。很长一段时间我成功地使用了业务规则的例外,现在我倾向于利用第二种方法。

答案 1 :(得分:1)

处理此问题的一种方法是为具有状态代码的addPerson操作创建响应对象。例如:

class AddPersonResponse {
    private Person person;
    private AddPersonStatus status;
    private AddPersonFailureReason failureReason;
}

enum AddPersonStatus {
    SUCCESS, FAILURE
}

enum AddPersonFailureReason {
    DUPLICATE_EMAIL_ADDRESS,
    DUPLICATE_USER_NAME
}

您发送给用户的视图可以绑定到服务返回的响应对象,并提供适当的反馈。

答案 2 :(得分:1)

我想我会选择抛出异常。您可以创建从Exception类派生的自定义异常。这样,您就可以使用类中的“消息”字段作为最终用户友好消息,同时仍然可以从基础的“innerException”字段中记录实际的异常详细信息。通过这种方式,您可以选择隐藏有关您的方法失败的原因的丑陋细节,同时仍保持基础异常描述的详细程度。

答案 3 :(得分:1)

这个讨论很古老,你会发现不同的阵营。我对此的看法是,如果您的后端系统具有明确的独立功能,则应首先使用API​​和所有内容进行开发,然后在视图层中使用该API。在这种情况下,保证分层。一个例子是您正在为已经开发的自定义软件编写Web前端。

然而,在大多数Web应用程序中,使用单个配置源更加容易和直接。 Django,RoR,JBoss Seam等都采用这种方法。它们使用以一组域类为中心的概念,其中放置了所有验证逻辑和约束。模型异常(例如NoSuchObject)直接映射到视图异常(404 Not Found),全部由框架处理。使用这种方法,没有层,主要的想法是避免分层,直到它真正需要。 Django文档是关于这个主题的真正良好信息来源,而Seam文档更具技术性,但也更详细。

将某些逻辑公开为Web服务的决定不会自动保证构建完整的分层解决方案的决定,我很容易重构,YAGNI和DRY规则。

分层确实增加了来回传播信息的另一个问题,我会说,除非它很好地适应你的问题,否则不要使用它。

答案 4 :(得分:1)

我必须说,我不是“验证错误是例外”模式的忠实粉丝。

我的模型Save()方法只是创建并返回一个破坏规则列表(或一个空列表。)然后我的ControllerBase(或服务层)的工作就是处理那些他们认为合适的破坏规则。

对于我的ControllerBase,我通过AddModelError将它们逐个添加到MVC验证处理程序。在服务层中,它最终就像在我的JSON结果中添加“isValid”标志一样。

答案 5 :(得分:0)

我在Spring MVC中使用的方法是在我的Validator类中执行所有验证。因此,在我的验证方法中,我会调用服务上的方法来检查电子邮件地址是否已被使用。如果它是重复的,我会为绑定到Errors对象添加一个错误,以便在表单上显示。如果Person对象有效,那么在将它添加到服务时不应该担心被抛出的任务。