1

我正在使用 Play 2.1.0。我正在尝试创建一个接受 POST 请求并要求请求正文中需要布尔值的操作。现在发生的情况是,即使我不提供参数,Action 也会得到一个错误的值。测试代码:

// /post/boolean/single routes to this method
def postTestBooleanSingle = Action { implicit request =>
    val form = Form("flag" -> boolean)
    form.bindFromRequest.fold(
        formWithErrors =>
            BadRequest(formWithErrors.errors map (fe => fe.key + ": " + fe.message) mkString ", "),
        flag => Ok(f"got $flag%b")
    )
}

// /post/num/single routes to this method
def postTestNumSingle = Action { implicit request =>
    val form = Form("num" -> number)
    form.bindFromRequest.fold(
        formWithErrors => 
            BadRequest(formWithErrors.errors map (fe => fe.key + ": " + fe.message) mkString ", "),
        num => Ok(f"got $num%d")
    )
}

$ curl -XPOST -d "num=42" http://localhost:9000/post/num/single
got 42
$ curl -XPOST http://localhost:9000/post/num/single
num: error.required // didn't provide num so i get an error
$ curl -XPOST -d "flag=true" http://localhost:9000/post/boolean/single
got true
$ curl -XPOST http://localhost:9000/post/boolean/single
got false // ???

我如何需要一个布尔参数?

4

1 回答 1

4

我不知道为什么,但是在没有任何参数的情况下,布尔类型的表单映射似乎默认为 false。

这是播放源中 Format.scala 负责的片段:

/**
 * Default formatter for the `Boolean` type.
 */
implicit def booleanFormat: Formatter[Boolean] = new Formatter[Boolean] {

  override val format = Some(("format.boolean", Nil))

  def bind(key: String, data: Map[String, String]) = {
    Right(data.get(key).getOrElse("false")).right.flatMap {
      case "true" => Right(true)
      case "false" => Right(false)
      case _ => Left(Seq(FormError(key, "error.boolean", Nil)))
    }
  }

  def unbind(key: String, value: Boolean) = Map(key -> value.toString)
}

这里的重要部分是data.get(key).getOrElse("false"). 在没有任何输入的情况下,它将布尔值默认为 false。您需要创建一个自定义格式化程序并使用它为布尔值定义一个自定义绑定。

我会留给你把这些放在你的代码库中的好地方,但是你的拼图应该看起来像这样:

// This is the custom formatter to support your custom mapping.
import play.api.data.format.Formatter
implicit def requiredBooleanFormatter: Formatter[Boolean] = new Formatter[Boolean] {

  override val format = Some(("format.boolean", Nil))

  def bind(key: String, data: Map[String, String]) = {
    Right(data.get(key).getOrElse("")).right.flatMap {
      case "true" => Right(true)
      case "false" => Right(false)
      case _ => Left(Seq(FormError(key, "error.boolean", Nil)))
    }
  }

  def unbind(key: String, value: Boolean) = Map(key -> value.toString)
}

// This is your custom mapping to be used in the form
import play.api.data.Forms
val requiredBoolean: Mapping[Boolean] = Forms.of[Boolean](requiredBooleanFormatter)

注意从.getOrElse("false")到的变化.getOrElse("")。代码几乎相同,但我们现在将空值推送到错误捕获器,而不是让它们false取值。(注意:为了清楚起见,我requiredBooleanFormatter在此示例中明确指定,但由于requiredBooleanFormatter是隐式且在范围内,您不必这样做。)

现在您可以在表单中使用requiredBoolean而不是boolean要求在请求中明确设置参数。

于 2013-05-09T21:56:36.917 回答