§自訂路由
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
您可以提供 QueryStringBindable[A]
的實作,以取得任何您想要能夠直接從要求查詢字串繫結的類型 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
在此文件檔中發現錯誤?此頁面的原始程式碼可在此處找到 here。在閱讀 文件檔指南 後,請隨時提交拉取要求。有問題或建議要分享嗎?請前往 我們的社群論壇,與社群展開對話。