文件

§自訂路由

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

您可以提供 QueryStringBindable[A] 的實作,以取得任何您想要能夠直接從要求查詢字串繫結的類型 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


在此文件檔中發現錯誤?此頁面的原始程式碼可在此處找到 here。在閱讀 文件檔指南 後,請隨時提交拉取要求。有問題或建議要分享嗎?請前往 我們的社群論壇,與社群展開對話。