验证逻辑(以及我的第一篇帖子!)

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

大家好!

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

那么我第一篇帖子的主题是什么(除了自我介绍)?验证逻辑。 这不是如何在 Spring 框架中执行验证的演练,而是讨论我特别讨厌的事情:)

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

最常见的例子是当您添加新实体时,例如 User。 通常,validator 将执行许多“简单”检查(字段不能为空,文本字段的长度超过 25 个字符等)。 然后,控制器(例如)将调用中间层 (userService.add(user)) 并捕获 DuplicateKeyException(或强类型的 DuplicateUserException)异常。 如果抛出此异常,则控制器将填充 errors 对象,然后重新显示表单。

那么这张图有什么问题呢? 简单的事实是,某些验证现在隐式地通过引发 DuplicateKeyException 来完成,表明验证失败! 在插入数据之前,数据库(在本例中)正在验证数据以确保其唯一,如果不是,则抛出异常。

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

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

注意:有一种论点是您正在重复您的验证逻辑; 数据库知道什么是唯一的,什么不是唯一的,那么为什么在控制器中重复该逻辑? 好吧,关键是您正在重复该逻辑,您正在使用引发 DuplicateXXXException 来指示验证失败,因此这并不是一个有效的论点。

还有另一种论点是,这不能 100% 保证捕获所有(在本例中)重复的键。 这是真的。 在调用验证之后但在中间层调用之前,有一个很小的机会窗口,另一个进程可能会偷偷地创建唯一的行,但这只是一个非常非常小的窗口(通常是毫秒),并且无论如何都可能会抛出 OptimisticLockingException。 还要考虑数据的性质。 两个不同的线程同时创建一个唯一的实体是不太可能的。 如果确实发生了,那也没关系。 让异常传递到容器,因为它现在确实是异常情况。

咆哮结束。

附言。我的其余博客文章可能同样冗长:)

获取 Spring 新闻邮件

通过 Spring 新闻邮件保持联系

订阅

取得领先

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

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部