假设我有一个可以将人员存储在数据库中的Web应用程序。每个人必须拥有唯一的电子邮件地址(或用户名或其他)。如果用户尝试添加具有已存在的电子邮件地址的Person,则应返回表单并显示错误消息(就像在典型的验证失败期间一样)。
这种错误最常见的是从服务层到控制器然后再到视图?服务方法是否应该为控制器捕获异常,或者返回值或某种结果对象?
如果我最终想要使用我的服务层来生成Web服务,这是否会改变我的工作方式?
任何有关最佳做法/样本申请的建议或链接都将受到赞赏。
答案 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对象有效,那么在将它添加到服务时不应该担心被抛出的任务。