2018-01-30 10:28:48 +08:00
|
|
|
[[webflux-view]]
|
|
|
|
= View Technologies
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view.adoc[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
The use of view technologies in Spring WebFlux is pluggable. Whether you decide to
|
2018-10-25 21:15:58 +08:00
|
|
|
use Thymeleaf, FreeMarker, or some other view technology is primarily a matter of a
|
|
|
|
configuration change. This chapter covers the view technologies integrated with Spring
|
2023-04-19 23:26:17 +08:00
|
|
|
WebFlux. We assume you are already familiar with xref:web/webflux/dispatcher-handler.adoc#webflux-viewresolution[View Resolution].
|
2018-10-25 21:15:58 +08:00
|
|
|
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-view-thymeleaf]]
|
|
|
|
== Thymeleaf
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-thymeleaf.adoc[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML
|
2018-01-30 10:28:48 +08:00
|
|
|
templates that can be previewed in a browser by double-clicking, which is very
|
2018-09-17 22:36:43 +08:00
|
|
|
helpful for independent work on UI templates (for example, by a designer) without the need for a
|
|
|
|
running server. Thymeleaf offers an extensive set of features, and it is actively developed
|
|
|
|
and maintained. For a more complete introduction, see the
|
2019-03-21 06:48:14 +08:00
|
|
|
https://www.thymeleaf.org/[Thymeleaf] project home page.
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
The Thymeleaf integration with Spring WebFlux is managed by the Thymeleaf project. The
|
2018-09-17 22:36:43 +08:00
|
|
|
configuration involves a few bean declarations, such as
|
2018-01-30 10:28:48 +08:00
|
|
|
`SpringResourceTemplateResolver`, `SpringWebFluxTemplateEngine`, and
|
2018-09-17 22:36:43 +08:00
|
|
|
`ThymeleafReactiveViewResolver`. For more details, see
|
2019-03-21 06:48:14 +08:00
|
|
|
https://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] and the WebFlux integration
|
2022-07-26 21:45:12 +08:00
|
|
|
https://web.archive.org/web/20210623051330/http%3A//forum.thymeleaf.org/Thymeleaf-3-0-8-JUST-PUBLISHED-td4030687.html[announcement].
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 21:15:58 +08:00
|
|
|
|
2018-01-30 10:28:48 +08:00
|
|
|
[[webflux-view-freemarker]]
|
|
|
|
== FreeMarker
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-freemarker.adoc[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-03-21 06:48:14 +08:00
|
|
|
https://freemarker.apache.org/[Apache FreeMarker] is a template engine for generating any
|
2019-06-13 22:37:48 +08:00
|
|
|
kind of text output from HTML to email and others. The Spring Framework has built-in
|
2018-01-30 10:28:48 +08:00
|
|
|
integration for using Spring WebFlux with FreeMarker templates.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-view-freemarker-contextconfig]]
|
2018-09-17 22:36:43 +08:00
|
|
|
=== View Configuration
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-freemarker.adoc#mvc-view-freemarker-contextconfig[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
The following example shows how to configure FreeMarker as a view technology:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
|
|
|
.Java
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
@Configuration
|
|
|
|
@EnableWebFlux
|
|
|
|
public class WebConfig implements WebFluxConfigurer {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void configureViewResolvers(ViewResolverRegistry registry) {
|
2019-08-28 17:18:26 +08:00
|
|
|
registry.freeMarker();
|
2018-01-30 10:28:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Configure FreeMarker...
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
public FreeMarkerConfigurer freeMarkerConfigurer() {
|
|
|
|
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
2019-06-13 22:37:48 +08:00
|
|
|
configurer.setTemplateLoaderPath("classpath:/templates/freemarker");
|
2018-01-30 10:28:48 +08:00
|
|
|
return configurer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
|
|
|
.Kotlin
|
|
|
|
----
|
|
|
|
@Configuration
|
|
|
|
@EnableWebFlux
|
|
|
|
class WebConfig : WebFluxConfigurer {
|
|
|
|
|
|
|
|
override fun configureViewResolvers(registry: ViewResolverRegistry) {
|
|
|
|
registry.freeMarker()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure FreeMarker...
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
|
|
|
|
setTemplateLoaderPath("classpath:/templates/freemarker")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`,
|
2019-06-13 22:37:48 +08:00
|
|
|
shown in the preceding example. Given the preceding configuration, if your controller
|
|
|
|
returns the view name, `welcome`, the resolver looks for the
|
2018-01-30 10:28:48 +08:00
|
|
|
`classpath:/templates/freemarker/welcome.ftl` template.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-views-freemarker]]
|
2018-09-17 22:36:43 +08:00
|
|
|
=== FreeMarker Configuration
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-freemarker.adoc#mvc-views-freemarker[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
You can pass FreeMarker 'Settings' and 'SharedVariables' directly to the FreeMarker
|
2019-06-13 22:37:48 +08:00
|
|
|
`Configuration` object (which is managed by Spring) by setting the appropriate bean
|
|
|
|
properties on the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires
|
|
|
|
a `java.util.Properties` object, and the `freemarkerVariables` property requires a
|
2018-09-17 22:36:43 +08:00
|
|
|
`java.util.Map`. The following example shows how to use a `FreeMarkerConfigurer`:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
|
|
|
.Java
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
@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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
|
|
|
.Kotlin
|
|
|
|
----
|
|
|
|
@Configuration
|
|
|
|
@EnableWebFlux
|
|
|
|
class WebConfig : WebFluxConfigurer {
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
|
|
|
|
setTemplateLoaderPath("classpath:/templates")
|
|
|
|
setFreemarkerVariables(mapOf("xml_escape" to XmlEscape()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
See the FreeMarker documentation for details of settings and variables as they apply to
|
|
|
|
the `Configuration` object.
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-06-13 22:37:48 +08:00
|
|
|
[[webflux-view-freemarker-forms]]
|
|
|
|
=== Form Handling
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-freemarker.adoc#mvc-view-freemarker-forms[See equivalent in the Servlet stack]#
|
2019-06-13 22:37:48 +08:00
|
|
|
|
|
|
|
Spring provides a tag library for use in JSPs that contains, among others, a
|
|
|
|
`<spring:bind/>` element. This element primarily lets forms display values from
|
|
|
|
form-backing objects and show the results of failed validations from a `Validator` in the
|
|
|
|
web or business tier. Spring also has support for the same functionality in FreeMarker,
|
|
|
|
with additional convenience macros for generating form input elements themselves.
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-view-bind-macros]]
|
|
|
|
==== The Bind Macros
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-freemarker.adoc#mvc-view-bind-macros[See equivalent in the Servlet stack]#
|
2019-06-13 22:37:48 +08:00
|
|
|
|
|
|
|
A standard set of macros are maintained within the `spring-webflux.jar` file for
|
|
|
|
FreeMarker, so they are always available to a suitably configured application.
|
|
|
|
|
|
|
|
Some of the macros defined in the Spring templating libraries are considered internal
|
|
|
|
(private), but no such scoping exists in the macro definitions, making all macros visible
|
|
|
|
to calling code and user templates. The following sections concentrate only on the macros
|
|
|
|
you need to directly call from within your templates. If you wish to view the macro code
|
|
|
|
directly, the file is called `spring.ftl` and is in the
|
|
|
|
`org.springframework.web.reactive.result.view.freemarker` package.
|
|
|
|
|
2023-04-19 23:26:17 +08:00
|
|
|
For additional details on binding support, see xref:web/webmvc-view/mvc-freemarker.adoc#mvc-view-simple-binding[Simple Binding]
|
|
|
|
for Spring MVC.
|
2019-06-13 22:37:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
[[webflux-views-form-macros]]
|
|
|
|
==== Form Macros
|
|
|
|
|
|
|
|
For details on Spring's form macro support for FreeMarker templates, consult the following
|
|
|
|
sections of the Spring MVC documentation.
|
|
|
|
|
2023-04-19 23:26:17 +08:00
|
|
|
* xref:web/webmvc-view/mvc-freemarker.adoc#mvc-views-form-macros[Input Macros]
|
|
|
|
* xref:web/webmvc-view/mvc-freemarker.adoc#mvc-views-form-macros-input[Input Fields]
|
|
|
|
* xref:web/webmvc-view/mvc-freemarker.adoc#mvc-views-form-macros-select[Selection Fields]
|
|
|
|
* xref:web/webmvc-view/mvc-freemarker.adoc#mvc-views-form-macros-html-escaping[HTML Escaping]
|
2019-06-13 22:37:48 +08:00
|
|
|
|
|
|
|
|
2018-10-25 21:15:58 +08:00
|
|
|
|
2018-01-30 10:28:48 +08:00
|
|
|
[[webflux-view-script]]
|
|
|
|
== Script Views
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-script.adoc[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
The Spring Framework has a built-in integration for using Spring WebFlux with any
|
|
|
|
templating library that can run on top of the
|
2018-09-17 22:36:43 +08:00
|
|
|
https://www.jcp.org/en/jsr/detail?id=223[JSR-223] Java scripting engine.
|
|
|
|
The following table shows the templating libraries that we have tested on different script engines:
|
|
|
|
|
|
|
|
[%header]
|
|
|
|
|===
|
|
|
|
|Scripting Library |Scripting Engine
|
2019-03-21 06:48:14 +08:00
|
|
|
|https://handlebarsjs.com/[Handlebars] |https://openjdk.java.net/projects/nashorn/[Nashorn]
|
|
|
|
|https://mustache.github.io/[Mustache] |https://openjdk.java.net/projects/nashorn/[Nashorn]
|
|
|
|
|https://facebook.github.io/react/[React] |https://openjdk.java.net/projects/nashorn/[Nashorn]
|
|
|
|
|https://www.embeddedjs.com/[EJS] |https://openjdk.java.net/projects/nashorn/[Nashorn]
|
|
|
|
|https://www.stuartellis.name/articles/erb/[ERB] |https://www.jruby.org[JRuby]
|
|
|
|
|https://docs.python.org/2/library/string.html#template-strings[String templates] |https://www.jython.org/[Jython]
|
|
|
|
|https://github.com/sdeleuze/kotlin-script-templating[Kotlin Script templating] |https://kotlinlang.org/[Kotlin]
|
2018-09-17 22:36:43 +08:00
|
|
|
|===
|
|
|
|
|
|
|
|
TIP: The basic rule for integrating any other script engine is that it must implement the
|
2018-01-30 10:28:48 +08:00
|
|
|
`ScriptEngine` and `Invocable` interfaces.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-view-script-dependencies]]
|
|
|
|
=== Requirements
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-script.adoc#mvc-view-script-dependencies[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
You need to have the script engine on your classpath, the details of which vary by script engine:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-03-21 06:48:14 +08:00
|
|
|
* The https://openjdk.java.net/projects/nashorn/[Nashorn] JavaScript engine is provided with
|
2018-01-30 10:28:48 +08:00
|
|
|
Java 8+. Using the latest update release available is highly recommended.
|
2019-03-21 06:48:14 +08:00
|
|
|
* https://www.jruby.org[JRuby] should be added as a dependency for Ruby support.
|
|
|
|
* https://www.jython.org[Jython] should be added as a dependency for Python support.
|
2018-02-01 00:24:35 +08:00
|
|
|
* `org.jetbrains.kotlin:kotlin-script-util` dependency and a `META-INF/services/javax.script.ScriptEngineFactory`
|
|
|
|
file containing a `org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory`
|
2018-09-17 22:36:43 +08:00
|
|
|
line should be added for Kotlin script support. See
|
|
|
|
https://github.com/sdeleuze/kotlin-script-templating[this example] for more detail.
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2021-09-10 21:38:42 +08:00
|
|
|
You need to have the script templating library. One way to do that for JavaScript is
|
2019-03-21 06:48:14 +08:00
|
|
|
through https://www.webjars.org/[WebJars].
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[webflux-view-script-integrate]]
|
2018-09-17 22:36:43 +08:00
|
|
|
=== Script Templates
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-script.adoc#mvc-view-script-integrate[See equivalent in the Servlet stack]#
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
You can declare a `ScriptTemplateConfigurer` bean to specify the script engine to use,
|
2018-01-30 10:28:48 +08:00
|
|
|
the script files to load, what function to call to render templates, and so on.
|
2018-09-17 22:36:43 +08:00
|
|
|
The following example uses Mustache templates and the Nashorn JavaScript engine:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
|
|
|
.Java
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
@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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
|
|
|
.Kotlin
|
|
|
|
----
|
|
|
|
@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"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
The `render` function is called with the following parameters:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
* `String template`: The template content
|
|
|
|
* `Map model`: The view model
|
|
|
|
* `RenderingContext renderingContext`: The
|
|
|
|
{api-spring-framework}/web/servlet/view/script/RenderingContext.html[`RenderingContext`]
|
|
|
|
that gives access to the application context, the locale, the template loader, and the
|
|
|
|
URL (since 5.0)
|
2018-01-30 10:28:48 +08:00
|
|
|
|
|
|
|
`Mustache.render()` is natively compatible with this signature, so you can call it directly.
|
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
If your templating technology requires some customization, you can provide a script that
|
2019-03-21 06:48:14 +08:00
|
|
|
implements a custom render function. For example, https://handlebarsjs.com[Handlerbars]
|
2018-09-17 22:36:43 +08:00
|
|
|
needs to compile templates before using them and requires a
|
2019-03-21 06:48:14 +08:00
|
|
|
https://en.wikipedia.org/wiki/Polyfill[polyfill] in order to emulate some
|
2018-01-30 10:28:48 +08:00
|
|
|
browser facilities not available in the server-side script engine.
|
2018-09-17 22:36:43 +08:00
|
|
|
The following example shows how to set a custom render function:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
|
|
|
.Java
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
@Configuration
|
2019-08-28 17:18:26 +08:00
|
|
|
@EnableWebFlux
|
2018-01-30 10:28:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
|
|
|
.Kotlin
|
|
|
|
----
|
|
|
|
@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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
2018-09-17 22:36:43 +08:00
|
|
|
|
|
|
|
NOTE: Setting the `sharedEngine` property to `false` is required when using non-thread-safe
|
|
|
|
script engines with templating libraries not designed for concurrency, such as Handlebars or
|
2019-09-05 20:04:43 +08:00
|
|
|
React running on Nashorn. In that case, Java SE 8 update 60 is required, due to
|
|
|
|
https://bugs.openjdk.java.net/browse/JDK-8076099[this bug], but it is generally
|
|
|
|
recommended to use a recent Java SE patch release in any case.
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
`polyfill.js` defines only the `window` object needed by Handlebars to run properly,
|
|
|
|
as the following snippet shows:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,javascript,indent=0,subs="verbatim,quotes"]
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
var window = {};
|
|
|
|
----
|
|
|
|
|
|
|
|
This basic `render.js` implementation compiles the template before using it. A production
|
2018-09-17 22:36:43 +08:00
|
|
|
ready implementation should also store and reused cached templates or pre-compiled templates.
|
2018-01-30 10:28:48 +08:00
|
|
|
This can be done on the script side, as well as any customization you need (managing
|
|
|
|
template engine configuration for example).
|
2018-09-17 22:36:43 +08:00
|
|
|
The following example shows how compile a template:
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-08-28 17:18:26 +08:00
|
|
|
[source,javascript,indent=0,subs="verbatim,quotes"]
|
2018-01-30 10:28:48 +08:00
|
|
|
----
|
|
|
|
function render(template, model) {
|
|
|
|
var compiledTemplate = Handlebars.compile(template);
|
|
|
|
return compiledTemplate(model);
|
|
|
|
}
|
|
|
|
----
|
|
|
|
|
|
|
|
Check out the Spring Framework unit tests,
|
2021-04-27 13:18:23 +08:00
|
|
|
{spring-framework-main-code}/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[Java], and
|
|
|
|
{spring-framework-main-code}/spring-webflux/src/test/resources/org/springframework/web/reactive/result/view/script[resources],
|
2018-01-30 10:28:48 +08:00
|
|
|
for more configuration examples.
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 21:15:58 +08:00
|
|
|
|
2018-01-30 10:28:48 +08:00
|
|
|
[[webflux-view-httpmessagewriter]]
|
2018-09-17 22:36:43 +08:00
|
|
|
== JSON and XML
|
2023-04-19 23:26:17 +08:00
|
|
|
[.small]#xref:web/webmvc-view/mvc-jackson.adoc[See equivalent in the Servlet stack]#
|
2018-09-17 22:36:43 +08:00
|
|
|
|
2023-04-19 23:26:17 +08:00
|
|
|
For xref:web/webflux/dispatcher-handler.adoc#webflux-multiple-representations[Content Negotiation] purposes, it is useful to be able to alternate
|
2018-09-17 22:36:43 +08:00
|
|
|
between rendering a model with an HTML template or as other formats (such as JSON or XML),
|
|
|
|
depending on the content type requested by the client. To support doing so, Spring WebFlux
|
|
|
|
provides the `HttpMessageWriterView`, which you can use to plug in any of the available
|
2023-04-19 23:26:17 +08:00
|
|
|
xref:web/webflux/reactive-spring.adoc#webflux-codecs[Codecs] from `spring-web`, such as `Jackson2JsonEncoder`, `Jackson2SmileEncoder`,
|
2019-03-05 20:08:34 +08:00
|
|
|
or `Jaxb2XmlEncoder`.
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2018-09-17 22:36:43 +08:00
|
|
|
Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`
|
2023-04-19 23:26:17 +08:00
|
|
|
but is instead xref:web/webflux/config.adoc#webflux-config-view-resolvers[configured] as a default view. You can
|
2019-03-05 20:08:34 +08:00
|
|
|
configure one or more such default views, wrapping different `HttpMessageWriter` instances
|
|
|
|
or `Encoder` instances. The one that matches the requested content type is used at runtime.
|
2018-01-30 10:28:48 +08:00
|
|
|
|
2019-03-05 20:08:34 +08:00
|
|
|
In most cases, a model contains multiple attributes. To determine which one to serialize,
|
|
|
|
you can configure `HttpMessageWriterView` with the name of the model attribute to use for
|
|
|
|
rendering. If the model contains only one attribute, that one is used.
|