§字串內插路由 DSL
Play 提供一個用於定義內嵌路由的 DSL,稱為字串內插路由 DSL,簡稱 sird。此 DSL 有許多用途,包括內嵌一個輕量級 Play 伺服器、為一般 Play 應用程式提供自訂或更進階的路由功能,以及模擬 REST 服務以進行測試。
Sird 是基於字串內插萃取器物件。就像 Scala 支援將參數內插到字串中以建立字串(以及任何物件),例如 s"Hello $to"
,相同的機制也可以用於從字串中萃取參數,例如在 case 陳述式中。
DSL 存在於 play.api.routing.sird
套件中。通常,您會想要匯入此套件,以及其他幾個套件
import play.api.mvc._
import play.api.routing._
import play.api.routing.sird._
以下是一個簡單的使用範例
val router = Router.from {
case GET(p"/hello/$to") =>
Action {
Results.Ok(s"Hello $to")
}
}
在此情況下,插補路徑模式中的 $to
參數將萃取單一路徑區段,以用於動作中。GET
萃取器萃取使用 GET
方法的請求。它會取得 RequestHeader
,並萃取相同的 RequestHeader
參數,它只用作一個方便的篩選器。其他方法萃取器,包括 POST
、PUT
和 DELETE
也受支援。
與 Play 的編譯路由器一樣,sird 支援比對多個路徑區段參數,這是透過在參數後加上 *
來完成的
val router = Router.from {
case GET(p"/assets/$file*") =>
Assets.versioned(path = "/public", file = file)
}
正規表示式也受支援,方法是在參數後加上尖括號中的正規表示式
val router = Router.from {
case GET(p"/items/$id<[0-9]+>") =>
Action {
Results.Ok(s"Item $id")
}
}
查詢參數也可以萃取,使用 ?
算子對請求進行進一步萃取,並使用 q
萃取器
val router = Router.from {
case GET(p"/search" ? q"query=$query") =>
Action {
Results.Ok(s"Searching for $query")
}
}
雖然 q
會將必要的查詢參數萃取為 String
,但如果使用 Scala 2.10,q_?
或 q_o
會將選擇性的查詢參數萃取為 Option[String]
val router = Router.from {
case GET(p"/items" ? q_o"page=$page") =>
Action {
val thisPage = page.getOrElse("1")
Results.Ok(s"Showing page $thisPage")
}
}
同樣地,q_*
或 q_s
可用於萃取多值查詢參數的序列
val router = Router.from {
case GET(p"/items" ? q_s"tag=$tags") =>
Action {
val allTags = tags.mkString(", ")
Results.Ok(s"Showing items tagged: $allTags")
}
}
可以使用 &
算子萃取多個查詢參數
val router = Router.from {
case GET(
p"/items" ? q_o"page=$page"
& q_o"per_page=$perPage"
) =>
Action {
val thisPage = page.getOrElse("1")
val pageLength = perPage.getOrElse("10")
Results.Ok(s"Showing page $thisPage of length $pageLength")
}
}
由於 sird 僅是一個常規萃取器物件(由字串插補建構),因此它可以與任何其他萃取器物件結合,包括進一步萃取其子參數。Sird 提供了一些有用的萃取器,可立即萃取出一些最常見的類型,即 int
、long
、float
、double
和 bool
val router = Router.from {
case GET(p"/items/${int(id)}") =>
Action {
Results.Ok(s"Item $id")
}
}
在上面,id
的類型為 Int
。如果 int
提取器無法匹配,那麼當然整個模式都無法匹配。
類似地,相同的提取器可用於查詢字串參數,包括多值和可選查詢參數。對於可選或多值查詢參數,如果任何現有值無法繫結到類型,則匹配將會失敗,但沒有參數不會導致匹配失敗
val router = Router.from {
case GET(p"/items" ? q_o"page=${int(page)}") =>
Action {
val thePage = page.getOrElse(1)
Results.Ok(s"Items page $thePage")
}
}
為了進一步說明這些只是常規提取器物件,您可以在這裡看到您可以使用 case
敘述的所有其他功能,包括 @
語法和 if 敘述
val router = Router.from {
case rh @ GET(
p"/items/${idString @ int(id)}" ?
q"price=${int(price)}"
) if price > 200 =>
Action {
Results.Ok(s"Expensive item $id")
}
}
§繫結 sird 路由器
根據使用案例,可以使用多種方式將應用程式設定為使用 sird 路由器
§從路由檔案使用 SIRD 路由器
若要將路由 DSL 與使用 路由檔案 和 控制器 的常規 Play 專案結合使用,請延伸 SimpleRouter
package api
import javax.inject.Inject
import play.api.mvc._
import play.api.routing.sird._
import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
class ApiRouter @Inject() (controller: ApiController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/") => controller.index
}
}
將以下列新增至 conf/routes
-> /api api.ApiRouter
§組合 SIRD 路由器
您可以將多個路由器組合在一起,因為路由是部分函數。因此,您可以將路由分割成更小且更集中的路由器,然後在應用程式路由器中組合它們。例如,考慮上述 ApiRouter
和新的 SinglePageApplicationRouter
,如下所示
class SpaRouter @Inject() (controller: SinglePageApplicationController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/api") => controller.api
}
}
然後,您可以組合兩者以取得應用程式的完整路由器
class AppRouter @Inject() (spaRouter: SpaRouter, apiRouter: ApiRouter) extends SimpleRouter {
// Composes both routers with spaRouter having precedence.
override def routes: Routes = spaRouter.routes.orElse(apiRouter.routes)
}
§嵌入 play
可以在 嵌入 Play 區段中找到嵌入具有 sird 路由器的 play 伺服器的範例。
§提供 DI 路由器
路由器可以提供給應用程式,詳細資訊請參閱應用程式進入點和提供路由器
class SirdAppLoader extends ApplicationLoader {
def load(context: Context) = {
new SirdComponents(context).application
}
}
class SirdComponents(context: Context) extends BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
lazy val router = Router.from {
case GET(p"/hello/$to") =>
Action {
Ok(s"Hello $to")
}
}
}
§使用 Guice 提供 DI 路由器
可以在基於 Guice 的 Play 應用程式中提供 SIRD 路由器,方法是覆寫 GuiceApplicationLoader
和 Provider[Router]
class ScalaSimpleRouter @Inject() (val Action: DefaultActionBuilder) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/") =>
Action {
Results.Ok
}
}
}
@Singleton
class ScalaRoutesProvider @Inject() (playSimpleRouter: ScalaSimpleRouter, httpConfig: HttpConfiguration)
extends Provider[Router] {
lazy val get = playSimpleRouter.withPrefix(httpConfig.context)
}
class ScalaGuiceAppLoader extends GuiceApplicationLoader {
protected override def overrides(context: ApplicationLoader.Context): Seq[GuiceableModule] = {
super.overrides(context) :+ (bind[Router].toProvider[ScalaRoutesProvider]: GuiceableModule)
}
}
SIRD 路由器比路由檔案更強大,而且 IDE 可以更輕鬆地存取。
§覆寫繫結
也可以使用應用程式載入器中的 e.g. GuiceApplicationBuilder 提供路由器,以使用自訂路由器繫結或模組覆寫,詳細資訊請參閱繫結和模組
下一頁:Javascript 路由
在這個文件發現錯誤了嗎?此頁面的原始程式碼可以在這裡找到。在閱讀文件指南後,請隨時提交拉取請求。有問題或建議要分享嗎?前往我們的社群論壇與社群展開對話。