3

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

这种错误通常是如何从服务层冒泡到控制器然后到视图的?服务方法应该抛出异常让控制器捕获,还是返回一个值或某种结果对象?

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

任何建议或最佳实践/示例应用程序的链接将不胜感激。

4

6 回答 6

3

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

例外:

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

业务规则验证:

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

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

于 2009-05-15T22:39:04.460 回答
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
}

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

于 2009-05-15T22:10:47.693 回答
1

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

于 2009-05-15T22:17:09.443 回答
1

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

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

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

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

于 2009-05-15T22:17:44.200 回答
1

我必须说我不是“验证错误是异常”模式的忠实拥护者。

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

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

于 2009-05-15T22:28:09.820 回答
0

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

于 2009-05-15T23:02:54.700 回答