型別安全路由
所需依賴項: io.ktor:ktor-server-resources
程式碼範例: resource-routing
Ktor 提供了 Resources 外掛程式,允許您實作型別安全的 路由。為此,您需要建立一個將作為型別化路由的類別,然後使用 @Resource
關鍵字註解此類別。請注意,@Resource
註解具有由 kotlinx.serialization 函式庫提供的 @Serializable
行為。
Ktor 客戶端提供了向伺服器發送型別化請求的能力。
新增依賴項
新增 kotlinx.serialization
鑑於資源類別應具有 @Serializable
行為,您需要依照 設定 章節所述新增 Kotlin 序列化外掛程式。
新增 Resources 依賴項
若要使用 Resources
,您需要在建置腳本中包含 ktor-server-resources
構件:
安裝 Resources
要安裝 Resources
外掛程式到應用程式, 請將其傳遞給指定
install
函式。 下面的程式碼片段展示了如何安裝 Resources
... - ... 在
embeddedServer
函式呼叫內。 - ... 在明確定義的
module
內,它是Application
類別的擴充函式。
建立資源類別
每個資源類別都應具有 @Resource
註解。 下面,我們將探討幾個資源類別的範例——定義單一路徑區段、查詢參數和路徑參數等等。
資源 URL
下面的範例展示了如何定義 Articles
類別,該類別指定一個響應 /articles
路徑的資源。
import io.ktor.resources.*
@Resource("/articles")
class Articles()
帶有查詢參數的資源
下面的 Articles
類別具有 sort
字串屬性,該屬性充當查詢參數,並允許您定義一個響應以下路徑並帶有 sort
查詢參數的資源:/articles?sort=new
。
@Resource("/articles")
class Articles(val sort: String? = "new")
帶有巢狀類別的資源
您可以巢狀類別以建立包含多個路徑區段的資源。請注意,在這種情況下,巢狀類別應具有外部類別型別的屬性。 下面的範例展示了一個響應 /articles/new
路徑的資源。
@Resource("/articles")
class Articles() {
@Resource("new")
class New(val parent: Articles = Articles())
}
帶有路徑參數的資源
下面的範例演示了如何新增巢狀 {id}
整數路徑參數,該參數比對路徑區段並將其擷取為名為 id
的參數。
@Resource("/articles")
class Articles() {
@Resource("{id}")
class Id(val parent: Articles = Articles(), val id: Long)
}
例如,此資源可用於響應 /articles/12
。
範例:用於 CRUD 操作的資源
讓我們總結一下上述範例,並為 CRUD 操作建立 Articles
資源。
@Resource("/articles")
class Articles(val sort: String? = "new") {
@Resource("new")
class New(val parent: Articles = Articles())
@Resource("{id}")
class Id(val parent: Articles = Articles(), val id: Long) {
@Resource("edit")
class Edit(val parent: Id)
}
}
此資源可用於列出所有文章、發布新文章、編輯它等等。我們將在下一章中了解如何為此資源定義路由處理器。
您可以在此處找到完整範例:resource-routing。
定義路由處理器
若要為型別化資源定義路由處理器,您需要將資源類別傳遞給動詞函式 (get
、post
、put
等)。 例如,下面的路由處理器響應 /articles
路徑。
@Resource("/articles")
class Articles()
fun Application.module() {
install(Resources)
routing {
get<Articles> { articles ->
// Get all articles ...
call.respondText("List of articles: $articles")
}
}
}
下面的範例展示了如何為在範例:用於 CRUD 操作的資源中建立的 Articles
資源定義路由處理器。請注意,在路由處理器內部,您可以將 Article
作為參數存取並獲取其屬性值。
fun Application.module() {
install(Resources)
routing {
get<Articles> { article ->
// Get all articles ...
call.respondText("List of articles sorted starting from ${article.sort}")
}
get<Articles.New> {
// Show a page with fields for creating a new article ...
call.respondText("Create a new article")
}
post<Articles> {
// Save an article ...
call.respondText("An article is saved", status = HttpStatusCode.Created)
}
get<Articles.Id> { article ->
// Show an article with id ${article.id} ...
call.respondText("An article with id ${article.id}", status = HttpStatusCode.OK)
}
get<Articles.Id.Edit> { article ->
// Show a page with fields for editing an article ...
call.respondText("Edit an article with id ${article.parent.id}", status = HttpStatusCode.OK)
}
put<Articles.Id> { article ->
// Update an article ...
call.respondText("An article with id ${article.id} updated", status = HttpStatusCode.OK)
}
delete<Articles.Id> { article ->
// Delete an article ...
call.respondText("An article with id ${article.id} deleted", status = HttpStatusCode.OK)
}
}
}
以下是處理每個端點請求的幾個提示:
get<Articles>
此路由處理器應根據
sort
查詢參數返回所有文章。 例如,這可能是包含所有文章的 HTML 頁面 或 JSON 物件。get<Articles.New>
此端點響應一個包含用於建立新文章欄位的網頁表單。
post<Articles>
post<Articles>
端點應接收使用網頁表單發送的參數。 Ktor 也允許您使用ContentNegotiation
外掛程式接收作為物件的 JSON 資料。get<Articles.Id>
get<Articles.Id.Edit>
此端點響應一個包含用於編輯現有文章欄位的網頁表單。
put<Articles.Id>
與
post<Articles>
端點類似,put
處理器接收使用網頁表單發送的表單參數。delete<Articles.Id>
此路由處理器刪除具有指定識別碼的文章。
您可以在此處找到完整範例:resource-routing。
從資源建構連結
除了使用資源定義進行路由外,它們還可用於建構連結。 這有時被稱為「反向路由」。 從資源建構連結在您需要將這些連結添加到使用 HTML DSL 建立的 HTML 文件中,或者需要產生重新導向回應時可能會有所幫助。
Resources
外掛程式透過多載的 href 方法擴展 Application
,該方法允許您從 Resource
產生連結。例如,下面的程式碼片段為上面定義的 Edit
資源建立了一個連結:
val link: String = href(Articles.Id.Edit(Articles.Id(id = 123)))
由於祖級 Articles
資源定義了帶有預設值 new
的 sort
查詢參數,因此 link
變數包含:
/articles/123/edit?sort=new
若要產生指定主機和協定的 URL,您可以向 href
方法提供 URLBuilder
。 還可以使用 URLBuilder
指定其他查詢參數,如下例所示:
val urlBuilder = URLBuilder(URLProtocol.HTTPS, "ktor.io", parameters = parametersOf("token", "123"))
href(Articles(sort = null), urlBuilder)
val link: String = urlBuilder.buildString()
link
變數隨後包含:
https://ktor.io/articles?token=123
範例
下面的範例展示了如何將從資源建構的連結添加到 HTML 響應中:
get {
call.respondHtml {
body {
this@module.apply {
p {
val link: String = href(Articles())
a(link) { +"Get all articles" }
}
p {
val link: String = href(Articles.New())
a(link) { +"Create a new article" }
}
p {
val link: String = href(Articles.Id.Edit(Articles.Id(id = 123)))
a(link) { +"Edit an exising article" }
}
p {
val urlBuilder = URLBuilder(URLProtocol.HTTPS, "ktor.io", parameters = parametersOf("token", "123"))
href(Articles(sort = null), urlBuilder)
val link: String = urlBuilder.buildString()
i { a(link) { +link } }
}
}
}
}
}
您可以在此處找到完整範例:resource-routing。