是的,Play框架中的验证是同步设计的。我认为这是因为大多数情况下表单验证中没有I/O操作:只需检查字段值的大小、长度、是否与正则表达式匹配等。
验证是建立在
play.api.data.validation.Constraint
上的,该对象存储从已验证的值到
ValidationResult
(
Valid
或
Invalid
)的函数,这里没有放置
Future
的地方。
case class Constraint[-T](name: Option[String], args: Seq[Any])(f: (T => ValidationResult)) {
def apply(t: T): ValidationResult = f(t)
}
验证
只是使用用户定义的函数增加了另一个约束条件。
因此,我认为在Play中的数据绑定不适合在验证期间进行I/O操作。将其异步化会使其更加复杂和难以使用,因此保持简单。让框架中的每个代码片段都在包装在Future
中的数据上工作是过度的。
如果您需要使用ReactiveMongo进行验证,则可以使用Await.result
。ReactiveMongo在任何地方都返回Futures,并且您可以阻塞直到这些Futures完成以在验证
函数内获取结果。是的,在运行MongoDB查询时会浪费一个线程。
object Application extends Controller {
def checkUser(e:String, p:String):Boolean = {
val result = cursor.toList().map( _.length != 0)
Await.result(result, 5 seconds)
}
val loginForm = Form(
tuple(
"email" -> email,
"password" -> text
) verifying("Invalid user name or password", fields => fields match {
case (e, p) => checkUser(e, p)
})
)
def index = Action { implicit request =>
if (loginForm.bindFromRequest.hasErrors)
Ok("Invalid user name")
else
Ok("Login ok")
}
}
也许可以通过使用
continuations来避免浪费线程,但我没有尝试过。
我认为在Play邮件列表中讨论这个问题是很好的,也许很多人想在Play数据绑定中进行异步I/O(例如,检查值是否与数据库相符),所以未来版本的Play可能会有人实现它。