§自定义路由
Play 提供了一种机制,可以从路径或查询字符串参数中绑定类型。
§PathBindable
PathBindable 允许从 URL 路径绑定业务对象;这意味着我们可以定义类似 /user/3
的路由来调用以下操作
控制器
def user(user: User) = Action {
Ok(user.name)
}
user
参数将使用从 URL 路径中提取的 id 自动检索,例如使用以下路由定义
/conf/routes
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
,它定义了抽象方法 bind
和 unbind
。
对于类定义
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
发现此文档中的错误?此页面的源代码可以在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。