HTML DSL
必要な依存関係: io.ktor:ktor-server-html-builder
コード例: html
HTML DSL は kotlinx.html ライブラリを Ktor に統合し、HTML ブロックを使用してクライアントにレスポンスを返すことを可能にします。HTML DSL を使用すると、Kotlin で純粋な HTML を記述したり、ビューに変数を挿入したり、テンプレートを使用して複雑な HTML レイアウトを構築したりできます。
依存関係の追加
HTML DSL はインストールの必要はありませんが、ktor-server-html-builder アーティファクトが必要です。以下のようにビルドスクリプトに含めることができます。
レスポンスで HTML を送信する
HTML レスポンスを送信するには、必要なルート内で respondHtml メソッドを呼び出します。 以下の例は、サンプルの HTML DSL と、クライアントに送信される対応する HTML を示しています。
import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.http.*
import io.ktor.server.routing.*
import kotlinx.html.*
fun Application.module() {
routing {
get("/") {
val name = "Ktor"
call.respondHtml(HttpStatusCode.OK) {
head {
title {
+name
}
}
body {
h1 {
+"Hello from $name!"
}
}
}
}
}
}<html>
<head>
<title>Ktor</title>
</head>
<body>
<h1>Hello from Ktor!</h1>
</body>
</html>次の例は、ユーザーから認証情報を収集するために使用される HTML フォームでレスポンスを返す方法を示しています。
get("/login") {
call.respondHtml {
body {
form(action = "/login", encType = FormEncType.applicationXWwwFormUrlEncoded, method = FormMethod.post) {
p {
+"Username:"
textInput(name = "username")
}
p {
+"Password:"
passwordInput(name = "password")
}
p {
submitInput() { value = "Login" }
}
}
}
}
}<html>
<body>
<form action="/login" enctype="application/x-www-form-urlencoded" method="post">
<p>Username:<input type="text" name="username"></p>
<p>Password:<input type="password" name="password"></p>
<p><input type="submit" value="Login"></p>
</form>
</body>
</html>完全な例については、auth-form-html-dsl を参照してください。
サーバー側でフォームパラメータを受け取る方法の詳細については、フォームパラメータを参照してください。
kotlinx.html を使用した HTML 生成の詳細については、kotlinx.html wiki を参照してください。
HTML 部分テンプレートの送信
完全な HTML ドキュメントの生成に加えて、.respondHtmlFragment() 関数を使用して HTML フラグメントでレスポンスを返すこともできます。
HTML フラグメントは、HTMX のようなライブラリで使用される動的な更新など、完全な <html> ドキュメントを必要としない部分的なマークアップを返す場合に便利です。
import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.http.*
import io.ktor.server.routing.*
import kotlinx.html.*
fun Application.module() {
routing {
get("/fragment") {
call.respondHtmlFragment(HttpStatusCode.Created) {
div("fragment") {
span { +"Created!" }
}
}
}
}
}<div class="fragment">
<span>
Created!
</span>
</div>この関数は .respondHtml() と同様に動作しますが、ルート HTML 要素を追加せずに、ビルダー内で定義したコンテンツのみをレンダリングします。
テンプレート
単純な HTML の生成に加えて、Ktor は複雑なレイアウトを構築するために使用できるテンプレートエンジンを提供します。HTML ページのさまざまな部分に対してテンプレートの階層を作成できます。たとえば、ページ全体のリミットテンプレート、ページヘッダーとフッターの子テンプレートなどです。Ktor はテンプレートを操作するための以下の API を提供しています。
- 指定されたテンプレートに基づいて構築された HTML でレスポンスを返すには、respondHtmlTemplate メソッドを呼び出します。
- テンプレートを作成するには、Template インターフェースを実装し、HTML を提供する
Template.applyメソッドをオーバーライドする必要があります。 - 作成されたテンプレートクラス内で、さまざまなコンテンツタイプのプレースホルダーを定義できます。
- Placeholder はコンテンツを挿入するために使用されます。PlaceholderList は、複数回表示されるコンテンツ(例:リストアイテム)を挿入するために使用できます。
- TemplatePlaceholder は、子テンプレートを挿入してネストされたレイアウトを作成するために使用できます。
例
テンプレートを使用して階層的なレイアウトを作成する方法の例を見てみましょう。次のような HTML があると仮定します。
<body>
<h1>Ktor</h1>
<article>
<h2>Hello from Ktor!</h2>
<p>Kotlin Framework for creating connected systems.</p>
<ul>
<li><b>One</b></li>
<li>Two</li>
</ul>
</article>
</body>このページのレイアウトを 2 つの部分に分けることができます。
- ページヘッダー用のルートレイアウトテンプレートと、記事用の子テンプレート。
- 記事コンテンツ用の子テンプレート。
これらのレイアウトをステップバイステップで実装してみましょう。
respondHtmlTemplateメソッドを呼び出し、パラメータとしてテンプレートクラスを渡します。この例では、Templateインターフェースを実装する必要があるLayoutTemplateクラスです。kotlinget("/") { call.respondHtmlTemplate(LayoutTemplate()) { // ... } }ブロック内では、テンプレートにアクセスしてそのプロパティ値を指定できます。これらの値は、テンプレートクラスで指定されたプレースホルダーを置き換えます。次のステップで
LayoutTemplateを作成し、そのプロパティを定義します。ルートレイアウトテンプレートは以下のようになります。
kotlinclass LayoutTemplate: Template<HTML> { val header = Placeholder<FlowContent>() val content = TemplatePlaceholder<ArticleTemplate>() override fun HTML.apply() { body { h1 { insert(header) } insert(ArticleTemplate(), content) } } }このクラスは 2 つのプロパティを公開しています。
headerプロパティは、h1タグ内に挿入されるコンテンツを指定します。contentプロパティは、記事コンテンツ用の子テンプレートを指定します。
子テンプレートは以下のようになります。
kotlinclass ArticleTemplate : Template<FlowContent> { val articleTitle = Placeholder<FlowContent>() val articleText = Placeholder<FlowContent>() val list = TemplatePlaceholder<ListTemplate>() override fun FlowContent.apply() { article { h2 { insert(articleTitle) } p { insert(articleText) } insert(ListTemplate(), list) } } }このテンプレートは
articleTitle、articleText、listプロパティを公開しており、それらの値はarticle内に挿入されます。テンプレートとして値のリストを提供するには、次の新しいクラスを作成します。
kotlinclass ListTemplate : Template<FlowContent> { val item = PlaceholderList<UL, FlowContent>() override fun FlowContent.apply() { if (!item.isEmpty()) { ul { each(item) { li { if (it.first) { b { insert(it) } } else { insert(it) } } } } } } }このテンプレートは、
PlaceholderListクラスを使用して、提供されたアイテムから順序なしリスト (UL) を生成します。また、強調のために最初のアイテムを<b>要素で囲みます。これで、指定されたプロパティ値を使用して構築された HTML を送信する準備が整いました。
kotlinget("/") { call.respondHtmlTemplate(LayoutTemplate()) { header { +"Ktor" } content { articleTitle { +"Hello from Ktor!" } articleText { +"Kotlin Framework for creating connected systems." } list { item { +"One" } item { +"Two" } } } } }
完全な例はこちらで見つけることができます: html-templates。
