类型安全的路由
所需依赖项: io.ktor:ktor-server-resources
代码示例: resource-routing
Ktor 提供了 Resources 插件,允许您实现类型安全的路由。为此,您需要创建一个类作为类型化路由,然后使用 @Resource 关键字注解此 class。请注意,@Resource 注解具有由 kotlinx.serialization 库提供的 @Serializable 行为。
Ktor 客户端提供了向服务器发出类型化请求的功能。
添加依赖项
添加 kotlinx.serialization
鉴于资源类应具有 @Serializable 行为,您需要按照 Setup 部分的描述添加 Kotlin serialization 插件。
添加 Resources 依赖项
要使用 Resources,您需要在构建脚本中包含 ktor-server-resources artifact:
安装 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)
}
}
}以下是处理每个 endpoint 请求的一些提示:
get<Articles>此路由处理程序旨在根据
sort查询形参返回所有文章。 例如,这可能是一个包含所有文章的 HTML 页面或 JSON 对象。get<Articles.New>此 endpoint 响应一个网页表单,其中包含用于创建新文章的字段。
post<Articles>post<Articles>endpoint 旨在接收使用网页表单发送的形参。 Ktor 还允许您使用ContentNegotiation插件以对象形式接收 JSON 数据。get<Articles.Id>此路由处理程序旨在返回具有指定标识符的文章。 这可能是一个显示文章的 HTML 页面或一个包含文章数据的 JSON 对象。
get<Articles.Id.Edit>此 endpoint 响应一个网页表单,其中包含用于编辑现有文章的字段。
put<Articles.Id>与
post<Articles>endpoint 类似,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。
