文档

§自定义路由

Play 提供了一种机制,可以从路径或查询字符串参数中绑定类型。

§PathBindable

PathBindable 允许从 URL 路径绑定业务对象;这意味着我们可以定义类似 /user/3 的路由来调用以下操作

def user(user: User) = Action {
  Ok(user.name)
}

user 参数将使用从 URL 路径中提取的 id 自动检索,例如使用以下路由定义

GET     /user/:user            controllers.BinderApplication.user(user: scalaguide.binder.models.User)

您可以为任何想要直接从请求路径绑定的类型 A 提供 PathBindable[A] 的实现。它定义了抽象方法 bind(从路径构建值)和 unbind(从值构建路径片段)。

对于类定义

case class User(id: Int, name: String) {}

绑定 :id 路径参数的绑定器使用示例

implicit def pathBinder(implicit intBinder: PathBindable[Int]): PathBindable[User] = new PathBindable[User] {
  override def bind(key: String, value: String): Either[String, User] = {
    for {
      id   <- intBinder.bind(key, value)
      user <- User.findById(id).toRight("User not found")
    } yield user
  }
  override def unbind(key: String, user: User): String = {
    user.id.toString
  }
}

在此示例中,调用 findById 方法来检索 User 实例;请注意,在现实世界中,这种方法应该很轻量级,并且不涉及例如数据库访问,因为代码是在服务器 IO 线程上调用的,并且必须完全非阻塞。

因此,例如,您可以使用简单对象标识符作为路径绑定器,并使用操作组合检索实际值。

§QueryStringBindable

查询字符串参数使用类似的机制;可以定义类似 /age 的路由来调用以下操作

def age(age: AgeRange) = Action {
  Ok(age.from.toString)
}

age 参数将使用从查询字符串中提取的参数自动检索,例如 /age?from=1&to=10

您可以为任何类型 A 提供 QueryStringBindable[A] 的实现,以便您可以直接从请求查询字符串中绑定该类型。类似于 PathBindable,它定义了抽象方法 bindunbind

对于类定义

case class AgeRange(from: Int, to: Int) {}

绑定 :from:to 查询字符串参数的绑定器使用示例

implicit def queryStringBindable(implicit intBinder: QueryStringBindable[Int]): QueryStringBindable[AgeRange] =
  new QueryStringBindable[AgeRange] {
    override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, AgeRange]] = {
      for {
        from <- intBinder.bind("from", params)
        to   <- intBinder.bind("to", params)
      } yield {
        (from, to) match {
          case (Right(from), Right(to)) => Right(AgeRange(from, to))
          case _                        => Left("Unable to bind an AgeRange")
        }
      }
    }
    override def unbind(key: String, ageRange: AgeRange): String = {
      intBinder.unbind("from", ageRange.from) + "&" + intBinder.unbind("to", ageRange.to)
    }
  }

Play 提供的所有绑定器在其 unbind 方法中自动应用表单 URL 编码,因此所有特殊字符都将安全地进行 URL 编码。但是,在实现自定义绑定器时,这不会自动发生,因此在必要时确保对键/值部分进行编码

override def unbind(key: String, cartItem: CartItem): String = {
  // If we don't use Play's QueryStringBindable[String].unbind() for some reason, we need to construct the result string manually.
  // The key is constant and does not contain any special character, but
  // value may contain special characters => need form URL encoding for cartItem.identifier:
  "identifier=" + URLEncoder.encode(cartItem.identifier, "utf-8")
}

下一步: 扩展 Play


发现此文档中的错误?此页面的源代码可以在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。