1. 程式人生 > >2.Play Framework HTTP routing Http路由

2.Play Framework HTTP routing Http路由

內建HTTP路由器

router是用來將請求的http request 轉到對應的Action處理的一個元件 一個http請求在mvc框架中被當做是一個事件,這個事件包含兩個組成部分: 1、請求的url+引數 2、請求的型別post還是get 路由的跳轉規則實在conf/routes檔案中配置

##依賴注入

Play的路由構造器會建立一個構造器類,這個類通過 @Inject 在構造器中接受一個controller的例項,這說明我們既可以通過依賴注入例項化,也可以通過建構函式手動的例項化 Play還有一個遺留的靜態路由生成器,他和被宣告的controller共同工作,不過這是不推薦的方式,這個方式不但打破了封裝,而且也不被一些新的Play的介面 如果你需要使用靜態路由生成器,你可以通過在build.sbt配置檔案新增以下配置來進行轉換

routesGenerator := StaticRoutesGenerator

Play預設的認為你使用的註解的方式建立controller 如果不想使用這個模式,你可以去使用靜態的路由生成器 ,或者通過用@符號預先宣告在呼叫controller的地方,或者將每個controller宣告為一個object(靜態物件)而不是一個class

路由配置檔案的配置方法

conf/routes是用於配置路由的檔案,這個檔案中羅列了所有在應用中被用到的路由。每一個路由由一個http請求方式和一個http請求的url構成,兩者通過宣告關聯到對應的Action生成器上

# Display a client.(可以用#來編輯註釋)

    GET   /clients/:id          controllers.Clients.show(id: Long)

你也可以使用->來將路由指定到其他的配置檔案

->      /api                        api.MyRouter

也可以在路由配置前用一個+開頭,這可以改變以確定的Play元件的行為,這面這就是使用“nocsrf”來修飾,來繞過 CSRF filter

+ nocsrf
POST  /api/new              controllers.Api.newThing

Http請求

Play可以支援所有的請求型別:(GET, PATCH, POST, PUT, DELETE, HEAD)

URI部分

URI部分指定了路由請求的路徑,而且可以動態的指定。而且支援正則表示式

靜態的指定:

GET   /clients/all          controllers.Clients.list()

動態的指定:

GET   /clients/:id          controllers.Clients.show(id: Long)

動態部分使用多“/” 如果在動態部分去捕獲多個urI路徑(通過斜槓分開),可以使用*id,也就是使用正則表示式的萬用字元模式

GET   /files/*name          controllers.Application.download(name)

在上面的配置中,訪問 /files/myproject/test.png ,在後面的controller裡接收到的引數也就是/myproject/test.png 但是動態的路由跨越多個“/”,既不是由路由解碼的也不是由反向路由編碼的,校驗所有使用者輸入的uri段是你的責任,反向路由只是做一些簡單的串聯工作,所以你要確保result的值是可靠的正確的,而不是像有多個前置的斜槓或者非assic字元 動態部分使用正則表示式

GET   /items/$id<[0-9]+>    controllers.Items.show(id: Long)

宣告Action生成器方法

在配置的最後一部分是一個宣告,這個部分必須定義一個返回 play.api.mvc.Action值的有效方法,這個方法通常是一個controller action 如果宣告的方法沒有定義任何引數,那隻需要給一個完整的方法名就可以了

GET   /                     controllers.Application.homePage()

如果你的action定義了一些引數,所有的引數都可以通過在請求url中抽出來去或者從查詢字串中獲取 從請求uri中獲取:

   # Extract the page parameter from the path.
    GET   /:page                controllers.Application.show(page)
    # Extract the page parameter from the query string.
    GET   /                     controllers.Application.show(page)

與之對應的show方法的定義

def show(page: String) = Action {
  loadContentFromDatabase(page).map { htmlContent =>
    Ok(htmlContent).as("text/html")
  }.getOrElse(NotFound)
}

如果引數是String的時候,引數的型別是可選的,如果你想去指定鍵入的引數為指定的Scala型別,你可以明確的在action宣告處指定引數的型別

GET   /clients/:id          controllers.Clients.show(id: Long)

可以在路由中設定預設的引數值

# Extract the page parameter from the path, or fix the value for /
GET   /                     controllers.Application.show(page = "home")
GET   /:page                controllers.Application.show(page)

但是上面的寫法比較麻煩,我們可以用一條記錄同時匹配有預設值和沒有預設值的情況,也就是如果沒有鍵入值的話就使用預設值,如果有鍵入值的話就使用鍵入值

# Pagination links, like /clients?page=3
GET   /clients              controllers.Clients.list(page: Int ?= 1)

我們也可以使用一個可選值的option去傳引數,對引數沒有限制

# The version parameter is optional. E.g. /api/list-all?version=3.0
GET   /api/list-all         controllers.Api.list(version: Option[String]

路由的優先順序

很多時候我們在同意請求的時候會匹配到多個路由,這個時候會預設根據宣告順序選擇第一個配置的路由

反向路由

路由生成器還可用於從Scala呼叫中生成URL。這樣就可以將所有URI模式集中在一個配置檔案中,這樣您在重構應用程式時就會更加自信。 對於路徑檔案中使用的每個控制器,路由器將在routes包中生成一個“反向控制器” ,具有相同的操作方法,具有相同的簽名,但返回一個 play.api.mvc.Call而不是a play.api.mvc.Action。 在play.api.mvc.Call定義了一個HTTP呼叫,並同時提供了HTTP方法和URI。 例如,如果您建立一個控制器,如:

package controllers

import javax.inject.Inject

import play.api._
import play.api.mvc._

class Application @Inject()(cc:ControllerComponents) extends AbstractController(cc)  {

  def hello(name: String) = Action {
    Ok("Hello " + name + "!")
  }

}

如果您將其對映到conf/routes檔案中:

# Hello action

    GET   /hello/:name          controllers.Application.hello(name)

然後,您可以hello使用controllers.routes.Application反向控制器將URL反轉到操作方法:

// Redirect to /hello/Bob
def helloBob = Action {
  Redirect(routes.Application.hello("Bob"))
}

注意:routes每個控制器包都有一個子包。因此,操作controllers.Application.hello可以通過反轉controllers.routes.Application.hello(只要在路徑檔案中沒有其他路徑發生匹配生成的路徑)。 反向操作方法非常簡單:它接受您的引數並將它們替換回路徑模式。在路徑段(:foo)的情況下,在替換完成之前對值進行編碼。對於正則表示式和萬用字元模式,字串將以原始形式替換,因為該值可能跨越多個段。確保在將它們傳遞到反向路徑時根據需要轉義這些元件,並避免傳遞未經驗證的使用者輸入。

相對路線

有些情況下返回相對路線而不是絕對路線可能是有用的。返回的路由play.mvc.Call始終是絕對的(它們帶有一個 /),當HTTP代理,負載平衡器和API閘道器重寫對Web應用程式的請求時,這可能會導致問題。使用相對路線有用的一些示例包括: 在Web閘道器後面託管應用程式,該應用程式在所有路徑前面新增除conf/routes檔案中配置的內容之外的其他內容,並將應用程式置於不期望的路徑上。 在動態呈現樣式表時,您需要資產連結是相對的,因為它們可能最終由CDN從不同的URL提供服務。 為了能夠生成相對路線,您需要知道相對於(起始路線)的目標路線是什麼。可以從當前檢索起始路線RequestHeader。因此,要生成相對路徑,您需要將當前RequestHeader路徑或起始路徑作為String引數傳遞。 例如,給定的控制器端點如:

package controllers

import javax.inject._
import play.api.mvc._

@Singleton
class Relative @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  def helloview() = Action { implicit request =>
    Ok(views.html.hello("Bob"))
  }

  def hello(name: String) = Action {
    Ok(s"Hello $name!")
  }
}

注意:當前請求通過宣告來隱式傳遞給檢視模板implicit request 如果您將其對映到conf/routes檔案中:

GET     /foo/bar/hello              controllers.Relative.helloview
GET     /hello/:name                controllers.Relative.hello(name)

然後,您可以像以前一樣使用反向路由器定義相對路由,幷包括對relative:

@(name: String)(implicit request: RequestHeader)

<h1>Hello @name</h1>

<a href="@routes.Relative.hello(name)">Absolute Link</a>
<a href="@routes.Relative.hello(name).relative">Relative Link</a>

注意:該Request從控制器傳遞被轉換為RequestHeader與被標記implicit在檢視引數。然後它會隱式傳遞給呼叫relative 請求/foo/bar/hello生成的HTML時,如下所示:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Bob</title>
    </head>
    <body>
      <a href="/hello/Bob">Absolute Link</a>
      <a href="../../hello/Bob">Relative Link</a>
    </body>
</html>

預設控制器

Play包括一個Default控制器,它提供了一些有用的動作。這些可以直接從routes檔案中呼叫:

# Redirects to https://www.playframework.com/ with 303 See Other
GET   /about      controllers.Default.redirect(to = "https://www.playframework.com/")

# Responds with 404 Not Found
GET   /orders     controllers.Default.notFound

# Responds with 500 Internal Server Error
GET   /clients    controllers.Default.error

# Responds with 501 Not Implemented
GET   /posts      controllers.Default.todo

在此示例中,GET /about重定向到外部網站,但也可以重定向到另一個操作(例如/posts在上面的示例中)。 自定義路由 Play提供了一個用於定義嵌入式路由器的DSL,稱為字串插入路由DSL,或簡稱為sird。此DSL有許多用途,包括嵌入輕量級Play伺服器,為常規Play應用程式提供自定義或更高階的路由功能,以及模擬REST服務以進行測試。 請參閱字串插值路由DSL