Thymeleaf
Thymeleaf is a modern server-side Java templating engine that emphasizes natural HTML templates that can be previewed in the browser with a double click, which is very useful when working on UI templates yourself (eg , designer) without the need for a running server. Thymeleaf offers an extensive feature set and is actively developed and maintained. More complete introductory information can be found on the project home page Thymeleaf.
Integration of Thymeleaf with Spring
WebFlux is managed by the Thymeleaf project. The configuration provides several bean declarations such as SpringResourceTemplateResolver
,
SpringWebFluxTemplateEngine
and ThymeleafReactiveViewResolver
. For more information, see
"Thymeleaf+Spring" and announcement integration with WebFlux.
FreeMarker
Apache FreeMarker is a template engine to generate any kind of text output from HTML to email and more. The Spring Framework has built-in integration for using Spring WebFlux with templates from FreeMarker.
View Configuration
The following example shows how you can configure FreeMarker as a presentation technology:
@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")
}
}
Your templates should be stored in the directory specified by FreeMarkerConfigurer
, as shown in
the previous example. Given the previous configuration, if the controller returns the view name welcome
,
the resolver looks for the template classpath:/templates/freemarker/welcome.ftl
.
FreeMarker Configuration
It is possible to pass the FreeMarker handler's "Settings" and "SharedVariable" directly into
the FreeMarker handler's Configuration
object (which is managed by Spring) by setting the appropriate
bean properties in FreeMarkerConfigurer
. The freemarkerSettings
property requires a java.util.Properties
object, and the freemarkerVariables
property requires a java.util.Map
object. The
following example shows how to use FreeMarkerConfigurer
:
@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()))
}
}
Details For settings and variables that apply to the Configuration
object, see the FreeMarker
documentation.
Form Handling
Spring provides a tag library for use in JSP that contains, among other
things, the <spring:bind/>
element. This element primarily allows forms to display values from
underlying form objects and display 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 the form input elements themselves.
Binding macros
The support for the standard set
of macros is in the file spring-webflux.jar
for FreeMarker, so they are always available to a suitably
configured application.
Some macros defined in Spring templating libraries are considered internal (private),
but there is no such restriction in macro definitions , which makes all macros visible to calling code and user
templates. The following sections cover only those macros that need to be called directly from templates. If you
need to view the macro code directly, the file is called spring.ftl
and is located in the package
org.springframework.web.reactive.result.view.freemarker
.
Form Macros
For detailed information about form macro support for FreeMarker templates in Spring, see the following sections of the Spring MVC documentation.
Input Macros
Input fields
Selection fields
HTML escaping
Scripting Views
Spring Framework has built-in integration for using Spring WebFlux with any templating library that can run on top of the specification scripting engine JSR-223 in Java. The following table shows the template libraries that we tested on various script execution engines:
Script library | Script execution engine |
---|---|
ScriptEngine
and Invocable
.
Requirements
You must provide a scripting engine in your classpath, the details of which depend on the scripting engine:
A JavaScript processing engine called Nashorn ships with Java 8+. It is strongly recommended that you use the latest available update release.
JRuby required add as a dependency to provide support for the Ruby language.
Jython must be added as a dependency to provide support for the Python language.
To provide support for Kotlin scripts, the dependency
org.jetbrains.kotlin:kotlin-script-util
must be added and a fileMETA-INF/services/javax.script.ScriptEngineFactory
containing the lineorg.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
. For more information, see this example.
You need to add a script template library. One way to do this in the case of JavaScript is WebJars.
Script templates
You can declare a
ScriptTemplateConfigurer
bean to specify which script engine to use, which script files to load, which
function to call to render templates, and so on. The following example uses Mustache templates and a JavaScript
engine called Nashorn:
@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"
}
}
The render
function is called with the following parameters:
String template
: Contents of the templateMap model
: View modelRenderingContext renderingContext
:RenderingContext
, which provides access to the application context, locale, template loader, and URL (since version 5.0).
Mustache.render()
is natively compatible with this signature, so you can call it directly.
If your templating technology requires some customization, you can pass in a script that implements a custom rendering function. For example, Handlerbars requires templates to be compiled before using them and requires polyfill to emulate some browser capabilities that are not available in the server-side scripting engine. The following example shows how to set a custom rendering function:
@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
}
}
sharedEngine
property to false
is
necessary when using thread-unsafe scripting engines with template libraries that are not designed for concurrency,
such as Handlebars or React running on Nashorn. In this case, Java SE 8 update 60 is required due to this bug, but it is generally
recommended to use the latest Java SE patch release anyway.
polyfill.js
only defines the window object that Handlebars needs to work properly, as shown in
the following snippet:
var window = {};
This is a basic implementation of render.js
compiles the template before using it. A
production-ready implementation must also store any reusable cached templates or precompiled templates. This can be
done on the script side, as well as with any settings you need (for example, managing the template engine
configuration). The following example shows how to compile the template:
function render(template, model) {
var compiledTemplate = Handlebars.compile(template);
return compiledTemplate(model);
}
Check out the Spring Framework unit tests, Java and resourcesto view more configuration examples.
JSON and XML
For content
consistency reasons, it is useful to be able to alternate between displaying a model with a template in HTML or
other formats (such as JSON or XML), in depending on the type of content requested by the client. To support this
feature, Spring WebFlux provides a HttpMessageWriterView
, which can be used to connect any of the
available codecs from Spring-web
, such as Jackson2JsonEncoder
,
Jackson2SmileEncoder
, or Jaxb2XmlEncoder
.
Unlike other presentation technologies,
HttpMessageWriterView
does not require ViewResolver
, but is configured as the default
view. You can configure one or more of these default views to wrap them around different
HttpMessageWriter
instances or Encoder
instances. At runtime, the one that matches the
requested content type is used.
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 that you
want to use for rendering. If the model contains only one attribute, then that one will be used.