验证逻辑(以及我的第一篇博文!)

工程 | Colin Yates | 2006年8月25日 | ...

大家好!

这是我上个月加入 Interface21 后的第一篇博文。我之前的博客现在正式弃用,我不会再更新它了。

那么,我的第一篇博文主题是什么(除了自我介绍)?验证逻辑。它不会逐步介绍如何在 Spring 框架中执行验证,而是会讨论我个人特别讨厌的一个问题 :)

特别是,我想讨论一下验证逻辑中应该包含什么。这似乎是一个显而易见的问题;“验证指定数据的逻辑”。好的,这显而易见的,但请继续阅读:)。如您所知,Spring 框架通过ErrorsValidator接口为您提供了验证的良好抽象层。特别是 Validator 是您将特定于业务的验证规则应用于已填充的域对象的地方。Spring 优秀的绑定支持负责根据某些输入更新您的域模型,Validator 负责确保已填充的域模型在语义上是正确的。那么我的烦恼是什么呢?我一次又一次地遇到允许验证逻辑从验证器泄漏到控制器(对于 Web 应用程序)甚至更糟糕地泄漏到中间层的应用程序。在人们开始提出异议之前;我并不是说验证不属于中间层,而是说 Validator 是放置验证逻辑的地方!

最常见的示例是添加新实体(例如用户)。通常,验证器会执行一些“简单”检查(字段不为空、文本字段长度超过 25 个字符等)。然后,控制器(例如)将调用中间层 (userService.add(user)) 并捕获 DuplicateKeyException(或强类型 DuplicateUserException)异常。如果引发此异常,则控制器将填充错误对象,然后重新显示表单。

那么这张图有什么问题呢?简而言之,某些验证现在隐式地通过引发 DuplicateKeyException 来指示验证失败!。数据库(在此示例中)会在插入数据之前验证数据以确保其唯一性,如果数据不唯一,则会引发异常。

我的观点(我承认我在表达时非常冗长;))是,这都是属于 Validator 的验证逻辑。将此唯一性检查移到 Validator 中它应该在的地方(!)可以带来许多好处

  • 这是一个更简洁、更直观的实现;您在哪里查找验证逻辑?在 Validator 中。
  • Validator 实现现在真正地可重用。以前,Validator 实际上只验证了一些数据。
  • 唯一用户的单元测试在验证单元测试中完成。这比单元测试控制器要容易得多,单元测试控制器需要模拟 Errors、HttpServletRequest、HttpServletResponse(实际上这很容易,但仍然……)等。需要模拟以测试 Validator 的对象数量是 Errors 对象、DAO 和您的域模型。
  • 控制器中的 onSubmit 方法现在遵守 SimpleFormController 指定的约定(该约定指出仅在验证成功时才调用它),因此代码更简洁。
这并不是什么火箭科学,但很多人就是“不明白”。我认为这可能是因为他们将 Validator 视为验证请求参数是否正确的地方。当然,您可以在域模型本身执行此操作,但那仍然是他们的思维方式。事实并非如此。它完全是关于应用所有您的业务验证规则。

注意:有人认为您正在重复验证逻辑;数据库知道什么内容是唯一的,什么内容不是唯一的,所以为什么要在控制器中重复该逻辑呢?好吧,关键是您确实在重复该逻辑,您正在使用引发 DuplicateXXXException 来指示验证失败,因此这实际上不是一个有效的论点。

还有一个论点认为这不能保证捕获所有(在这种情况下)重复键。这是真的。在调用验证后但在进行中间层调用之前,存在一个小窗口,在此窗口中,另一个进程可能会偷偷溜进来并创建唯一的行,但这是一个非常非常小的窗口(通常为毫秒),并且可能仍会引发 OptimisticLockingException。还要考虑数据的性质。两个不同的线程同时创建单个唯一实体的可能性极低。如果确实发生了,没关系。让异常传递到容器,因为它现在确实是一个异常情况。

抱怨结束。

附注:我的其他博文可能也同样冗长 :)

获取 Spring 时事通讯

通过 Spring 时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部