ビューテクノロジー
Spring WebFlux のビューのレンダリングはプラグ可能です。Thymeleaf、FreeMarker、その他のビューテクノロジを使用するかどうかは、主に構成の変更によって決まります。この章では、Spring WebFlux に統合されたビューテクノロジについて説明します。
ビューのレンダリングの詳細については、ビューリゾルバーを参照してください。
Spring WebFlux アプリケーションのビューは、アプリケーションの内部信頼境界内に存在します。ビューはアプリケーションコンテキスト内の Bean にアクセスできるため、セキュリティに影響する可能性があるため、テンプレートが外部ソースによって編集可能なアプリケーションでは Spring WebFlux テンプレートサポートを使用しないことをお勧めします。 |
Thymeleaf
Thymeleaf は、ダブルクリックでブラウザーでプレビューできる自然な HTML テンプレートを強調する最新のサーバー側 Java テンプレートエンジンです。これは、UI テンプレート(デザイナーなど)での独立した作業に必要なく、非常に役立ちます。実行中のサーバー。Thymeleaf は広範な機能セットを提供し、積極的に開発および保守されています。より完全な導入については、Thymeleaf (英語) プロジェクトのホームページを参照してください。
Thymeleaf と Spring の統合 WebFlux は、Thymeleaf プロジェクトによって管理されます。構成には、SpringResourceTemplateResolver
、SpringWebFluxTemplateEngine
、ThymeleafReactiveViewResolver
などのいくつかの Bean 宣言が含まれます。詳細については、Thymeleaf+Spring (英語) および WebFlux 統合の発表 (英語) を参照してください。
FreeMarker
Apache FreeMarker (英語) は、HTML からメールなどへのあらゆる種類のテキスト出力を生成するためのテンプレートエンジンです。Spring Framework には、Spring WebFlux と FreeMarker テンプレートを使用するための組み込みの統合機能があります。
構成を表示
次の例は、FreeMarker をビューテクノロジーとして設定する方法を示しています。
Java
Kotlin
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
}
// Configure FreeMarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:/templates/freemarker");
return configurer;
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
}
// Configure FreeMarker...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("classpath:/templates/freemarker")
}
}
テンプレートは、前の例に示されている FreeMarkerConfigurer
で指定されたディレクトリに保存する必要があります。上記の構成で、コントローラーがビュー名 welcome
を返す場合、リゾルバーは classpath:/templates/freemarker/welcome.ftl
テンプレートを探します。
FreeMarker の設定
FreeMarkerConfigurer
Bean で適切な Bean プロパティを設定することにより、FreeMarker の「設定」と "SharedVariables" を FreeMarker Configuration
オブジェクト(Spring によって管理される)に直接渡すことができます。freemarkerSettings
プロパティには java.util.Properties
オブジェクトが必要で、freemarkerVariables
プロパティには java.util.Map
が必要です。次の例は、FreeMarkerConfigurer
の使用方法を示しています。
Java
Kotlin
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
// ...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
Map<String, Object> variables = new HashMap<>();
variables.put("xml_escape", new XmlEscape());
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:/templates");
configurer.setFreemarkerVariables(variables);
return configurer;
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
// ...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("classpath:/templates")
setFreemarkerVariables(mapOf("xml_escape" to XmlEscape()))
}
}
Configuration
オブジェクトに適用される設定と変数の詳細については、FreeMarker のドキュメントを参照してください。
フォーム処理
Spring は、特に <spring:bind/>
要素を含む JSP で使用するタグライブラリを提供します。この要素により、フォームは主にフォームバッキングオブジェクトの値を表示し、Web またはビジネス層の Validator
からの検証の失敗の結果を表示できます。Spring は、FreeMarker と同じ機能をサポートしていますが、フォーム入力要素自体を生成するための追加の便利なマクロがあります。
バインドマクロ
マクロの標準セットは、FreeMarker の spring-webflux.jar
ファイル内で維持されるため、適切に構成されたアプリケーションで常に使用可能です。
Spring テンプレートライブラリで定義されているマクロの一部は内部(プライベート)と見なされますが、マクロ定義にはそのようなスコープは存在せず、呼び出し元のコードとユーザーテンプレートにすべてのマクロが表示されます。次のセクションでは、テンプレート内から直接呼び出す必要があるマクロのみに焦点を当てます。マクロコードを直接表示する場合、ファイルは spring.ftl
と呼ばれ、org.springframework.web.reactive.result.view.freemarker
パッケージに含まれています。
バインディングサポートの詳細については、Spring MVC の簡単なバインドを参照してください。
スクリプトビュー
Spring Framework には、JSR-223 (英語) Java スクリプトエンジン上で実行できるテンプレートライブラリで Spring WebFlux を使用するための組み込みの統合があります。次の表は、さまざまなスクリプトエンジンでテストしたテンプレートライブラリを示しています。
スクリプトライブラリ | スクリプトエンジン |
---|---|
他のスクリプトエンジンを統合するための基本的なルールは、ScriptEngine および Invocable インターフェースを実装する必要があるということです。 |
要件
クラスパスにスクリプトエンジンが必要です。詳細はスクリプトエンジンによって異なります。
Nashorn (英語) JavaScript エンジンには Java 8+ が付属しています。利用可能な最新の更新リリースを使用することを強くお勧めします。
JRuby (英語) は、Ruby サポートの依存関係として追加する必要があります。
Jython (英語) は、Python サポートの依存関係として追加する必要があります。
Kotlin スクリプトをサポートするには、
org.jetbrains.kotlin:kotlin-script-util
依存関係とorg.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
行を含むMETA-INF/services/javax.script.ScriptEngineFactory
ファイルを追加する必要があります。詳細については、この例 [GitHub] (英語) を参照してください。
スクリプトテンプレートライブラリが必要です。JavaScript でこれを行う 1 つの方法は、WebJars (英語) を使用することです。
スクリプトテンプレート
ScriptTemplateConfigurer
Bean を宣言して、使用するスクリプトエンジン、ロードするスクリプトファイル、テンプレートをレンダリングするために呼び出す関数などを指定できます。次の例では、Mustache テンプレートと Nashorn JavaScript エンジンを使用しています。
Java
Kotlin
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.scriptTemplate();
}
@Bean
public ScriptTemplateConfigurer configurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("nashorn");
configurer.setScripts("mustache.js");
configurer.setRenderObject("Mustache");
configurer.setRenderFunction("render");
return configurer;
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.scriptTemplate()
}
@Bean
fun configurer() = ScriptTemplateConfigurer().apply {
engineName = "nashorn"
setScripts("mustache.js")
renderObject = "Mustache"
renderFunction = "render"
}
}
render
関数は、次のパラメーターで呼び出されます。
String template
: テンプレートの内容Map model
: ビューモデルRenderingContext renderingContext
: アプリケーションコンテキスト、ロケール、テンプレートローダー、URL へのアクセスを提供するRenderingContext
(Javadoc) (5.0 以降)
Mustache.render()
はこの署名とネイティブに互換性があるため、直接呼び出すことができます。
テンプレートテクノロジでカスタマイズが必要な場合は、カスタムレンダリング機能を実装するスクリプトを提供できます。例: Handlerbars (英語) は、使用する前にテンプレートをコンパイルする必要があり、サーバーサイドスクリプトエンジンでは利用できないブラウザー機能をエミュレートするために、ポリフィル [Mozilla] が必要です。次の例は、カスタムレンダリング関数を設定する方法を示しています。
Java
Kotlin
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.scriptTemplate();
}
@Bean
public ScriptTemplateConfigurer configurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("nashorn");
configurer.setScripts("polyfill.js", "handlebars.js", "render.js");
configurer.setRenderFunction("render");
configurer.setSharedEngine(false);
return configurer;
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.scriptTemplate()
}
@Bean
fun configurer() = ScriptTemplateConfigurer().apply {
engineName = "nashorn"
setScripts("polyfill.js", "handlebars.js", "render.js")
renderFunction = "render"
isSharedEngine = false
}
}
Nashorn で実行されている Handlebars や React (参考: JavaScript フロントエンドフレームワークの比較 [Qiita] ) など、同時実行用に設計されていないテンプレートライブラリで非スレッドセーフスクリプトエンジンを使用する場合は、sharedEngine プロパティを false に設定する必要があります。その場合、このバグ (英語) のため、Java SE 8 update 60 が必要ですが、通常は最新の Java SE パッチリリースを使用することをお勧めします。 |
polyfill.js
は、次のスニペットが示すように、Handlebars が正しく実行するために必要な window
オブジェクトのみを定義します。
var window = {};
この基本的な render.js
実装は、テンプレートを使用する前にコンパイルします。また、本番対応の実装では、キャッシュされたテンプレートまたはプリコンパイルされたテンプレートを保存して再利用する必要があります。これは、必要なカスタマイズ(たとえば、テンプレートエンジンの構成の管理)だけでなく、スクリプト側でも実行できます。次の例は、テンプレートのコンパイル方法を示しています。
function render(template, model) {
var compiledTemplate = Handlebars.compile(template);
return compiledTemplate(model);
}
その他の構成例については、Spring Framework 単体テスト、Java [GitHub] (英語) 、リソース [GitHub] (英語) を参照してください。
HTML フラグメント
HTMX (英語) とホットワイヤーターボ (英語) は、クライアントがサーバーの更新を JSON ではなく HTML で受信する HTML over the wire アプローチを重視しています。これにより、JavaScript をほとんどまたはまったく記述しなくても、SPA (シングルページアプリ) の利点を活用できます。概要と詳細については、それぞれの Web サイトにアクセスしてください。
Spring WebFlux では、ビューのレンダリングには通常、1 つのビューと 1 つのモデルを指定することが含まれます。ただし、HTML-over-the-wire では、ブラウザーがページのさまざまな部分を更新するために使用できる複数の HTML フラグメントを送信することが一般的な機能です。このため、コントローラーメソッドは Collection<Fragment>
を返すことができます。例:
Java
Kotlin
@GetMapping
List<Fragment> handle() {
return List.of(Fragment.create("posts"), Fragment.create("comments"));
}
@GetMapping
fun handle(): List<Fragment> {
return listOf(Fragment.create("posts"), Fragment.create("comments"))
}
専用の型 FragmentsRendering
を返すことでも同じことができます。
Java
Kotlin
@GetMapping
FragmentsRendering handle() {
return FragmentsRendering.with("posts").fragment("comments").build();
}
@GetMapping
fun handle(): FragmentsRendering {
return FragmentsRendering.with("posts").fragment("comments").build()
}
各フラグメントは独立したモデルを持つことができ、そのモデルはリクエストの共有モデルから属性を継承します。
HTMX と Hotwire Turbo は、SSE (サーバー送信イベント) 経由のストリーミング更新をサポートします。コントローラーは、Flux<Fragment>
を使用して FragmentsRendering
を作成したり、ReactiveAdapterRegistry
を介して Reactive Streams Publisher
に適応可能な他のリアクティブプロデューサーを使用して ReactiveAdapterRegistry
を作成したりできます。また、FragmentsRendering
ラッパーを使用せずに Flux<Fragment>
を直接返すこともできます。
JSON と XML
コンテンツネゴシエーションの目的では、クライアントからリクエストされたコンテンツ型に応じて、HTML テンプレートを使用したモデルのレンダリングと他の形式(JSON や XML など)としてのレンダリングを切り替えることができると便利です。そうすることをサポートするために、Spring WebFlux は HttpMessageWriterView
を提供します。これを使用して、Jackson2JsonEncoder
、Jackson2SmileEncoder
、Jaxb2XmlEncoder
などの spring-web
から利用可能なコーデックのいずれかをプラグインできます。
他のビューテクノロジとは異なり、HttpMessageWriterView
は ViewResolver
を必要としませんが、代わりにデフォルトのビューとして構成されます。さまざまな HttpMessageWriter
インスタンスまたは Encoder
インスタンスをラップして、このようなデフォルトビューを 1 つ以上構成できます。リクエストされたコンテンツ型に一致するものが実行時に使用されます。
ほとんどの場合、モデルには複数の属性が含まれます。どれを直列化するかを決定するために、レンダリングに使用するモデル属性の名前で HttpMessageWriterView
を構成できます。モデルに含まれる属性が 1 つだけの場合、その属性が使用されます。