[docs] View Technologies section in WebFlux

Issue: SPR-16393
This commit is contained in:
Rossen Stoyanchev 2018-01-29 21:28:48 -05:00
parent 49eec6248d
commit 5ff724968d
3 changed files with 330 additions and 37 deletions

View File

@ -0,0 +1,288 @@
[[webflux-view]]
= View Technologies
[.small]#<<web.adoc#mvc-view,Same in Spring MVC>>#
The use of view technologies in Spring WebFlux is pluggable, whether you decide to
use Thymeleaf, FreeMarker, or other, is primarily a matter of a configuration change.
This chapter covers view technologies integrated with Spring WebFlux. We assume you are
already familiar with <<webflux-viewresolution>>.
[[webflux-view-thymeleaf]]
== Thymeleaf
[.small]#<<web.adoc#mvc-view-thymeleaf,Same in Spring MVC>>#
Thymeleaf is modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very
helpful for independent work on UI templates, e.g. by 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
http://www.thymeleaf.org/[Thymeleaf] project home page.
The Thymeleaf integration with Spring WebFlux is managed by the Thymeleaf project. The
configuration involves a few bean declarations such as
`SpringResourceTemplateResolver`, `SpringWebFluxTemplateEngine`, and
`ThymeleafReactiveViewResolver`. For more details see
http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] and the WebFlux integration
http://forum.thymeleaf.org/Thymeleaf-3-0-8-JUST-PUBLISHED-td4030687.html[announcement].
[[webflux-view-freemarker]]
== FreeMarker
[.small]#<<web.adoc#mvc-view-freemarker,Same in Spring MVC>>#
http://www.freemarker.org[Apache FreeMarker] is a template engine for generating any
kind of text output from HTML to email, and others. The Spring Framework has a built-in
integration for using Spring WebFlux with FreeMarker templates.
[[webflux-view-freemarker-contextconfig]]
=== View config
[.small]#<<web.adoc#mvc-view-freemarker-contextconfig,Same in Spring MVC>>#
To configure FreeMarker as a view technology:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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");
return configurer;
}
}
----
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`
shown above. Given the above configuration if your controller returns the view name
"welcome" then the resolver will look for the
`classpath:/templates/freemarker/welcome.ftl` template.
[[webflux-views-freemarker]]
=== FreeMarker config
[.small]#<<web.adoc#mvc-views-freemarker,Same in Spring MVC>>#
FreeMarker 'Settings' and 'SharedVariables' can be passed directly to the FreeMarker
`Configuration` object 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
`java.util.Map`.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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;
}
}
----
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
[[webflux-view-script]]
== Script Views
[.small]#<<web.adoc#mvc-view-script,Same in Spring MVC>>#
The Spring Framework has a built-in integration for using Spring WebFlux with any
templating library that can run on top of the
https://www.jcp.org/en/jsr/detail?id=223[JSR-223] Java scripting engine. Below is a list
of templating libraries we've tested on different script engines:
[horizontal]
http://handlebarsjs.com/[Handlebars] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
https://mustache.github.io/[Mustache] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://facebook.github.io/react/[React] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.embeddedjs.com/[EJS] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.stuartellis.eu/articles/erb/[ERB] :: http://jruby.org[JRuby]
https://docs.python.org/2/library/string.html#template-strings[String templates] :: http://www.jython.org/[Jython]
[TIP]
====
The basic rule for integrating any other script engine is that it must implement the
`ScriptEngine` and `Invocable` interfaces.
====
[[webflux-view-script-dependencies]]
=== Requirements
[.small]#<<web.adoc#mvc-view-script-dependencies,Same in Spring MVC>>#
You need to have the script engine on your classpath:
* http://openjdk.java.net/projects/nashorn/[Nashorn] JavaScript engine is provided with
Java 8+. Using the latest update release available is highly recommended.
* http://jruby.org[JRuby] should be added as a dependency for Ruby support.
* http://www.jython.org[Jython] should be added as a dependency for Python support.
You need to have the script templating library. One way to do that for Javascript is
through http://www.webjars.org/[WebJars].
[[webflux-view-script-integrate]]
=== Script templates
[.small]#<<web.adoc#mvc-view-script-integrate,Same in Spring MVC>>#
Declare a `ScriptTemplateConfigurer` bean in order to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
Below is an example with Mustache templates and the Nashorn JavaScript engine:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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;
}
}
----
The render function is called with the following parameters:
* `String template`: the template content
* `Map model`: the view model
* `String url`: the template url (since 4.2.2)
`Mustache.render()` is natively compatible with this signature, so you can call it directly.
If your templating technology requires some customization, you may provide a script that
implements a custom render function. For example, http://handlebarsjs.com[Handlerbars]
needs to compile templates before using them, and requires a
http://en.wikipedia.org/wiki/Polyfill[polyfill] in order to emulate some
browser facilities not available in the server-side script engine.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
@EnableWebMvc
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;
}
}
----
[NOTE]
====
Setting the `sharedEngine` property to `false` is required when using non thread-safe
script engines with templating libraries not designed for concurrency, like Handlebars or
React running on Nashorn for example. In that case, Java 8u60 or greater is required due
to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
====
`polyfill.js` only defines the `window` object needed by Handlebars to run properly:
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
This basic `render.js` implementation compiles the template before using it. A production
ready implementation should also store and reused cached templates / pre-compiled templates.
This can be done on the script side, as well as any customization you need (managing
template engine configuration for example).
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
function render(template, model) {
var compiledTemplate = Handlebars.compile(template);
return compiledTemplate(model);
}
----
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[java], and
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/resources/org/springframework/web/reactive/result/view/script[resources],
for more configuration examples.
[[webflux-view-httpmessagewriter]]
== JSON, XML
[.small]#<<web.adoc#mvc-view-jackson,Same in Spring MVC>>#
For <<webflux-multiple-representations>> purposes it is useful to be able to alternate
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 this Spring WebFlux
provides the `HttpMessageWriterView` that can be used to plug in any of the available
<<webflux-codecs>> from `spring-web` such as `Jackson2JsonEncoder`,
`Jackson2SmileEncoder`, or `Jaxb2XmlEncoder`.
Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`,
but instead is <<webflux-config-view-resolvers,configured>> as a default view. You can
configure one more such default views, wrapping different ``HttpMessageWriter``'s or
``Encoder``'s. The one that matches the requested content type is used at runtime.
In most cases a model will contain multiple attributes. In order to determine which one
to serialize, `HttpMessageWriterView` can be configured with the name of the model
attribute to use render, of if the model contains only one attribute, it will be used.

View File

@ -729,6 +729,8 @@ To configure view resolution is as simple as adding a `ViewResolutionResultHandl
to your Spring configuration. <<webflux-config-view-resolvers,WebFlux Config>> provides a
dedicated configuration API for view resolution.
See <<webflux-view>> for more on the view technologies integrated with Spring WebFlux.
[[webflux-redirecting-redirect-prefix]]
==== Redirecting
@ -2197,6 +2199,11 @@ reference documentation including:
include::webflux-view.adoc[leveloffset=+1]
[[webflux-config]]
== WebFlux Config
[.small]#<<web.adoc#mvc-config,Same in Spring MVC>>#
@ -2494,6 +2501,8 @@ on the `HttpMessageWriterView` implementation which accepts any of the available
}
----
See <<webflux-view>> for more on the view technologies integrated with Spring WebFlux.

View File

@ -1,11 +1,6 @@
[[mvc-view]]
= View Technologies
[[mvc-view-introduction]]
== Introduction
[.small]#<<web-reactive.adoc#webflux-view,Same in Spring WebFlux>>#
The use of view technologies in Spring MVC is pluggable, whether you decide to
use Thymeleaf, Groovy Markup Templates, JSPs, or other, is primarily a matter of a
@ -17,6 +12,7 @@ We assume you are already familiar with <<mvc-viewresolver>>.
[[mvc-view-thymeleaf]]
== Thymeleaf
[.small]#<<web-reactive.adoc#webflux-view-thymeleaf,Same in Spring WebFlux>>#
Thymeleaf is modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very
@ -36,6 +32,7 @@ See http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] for more detai
[[mvc-view-freemarker]]
== FreeMarker
[.small]#<<web-reactive.adoc#webflux-view-freemarker,Same in Spring WebFlux>>#
http://www.freemarker.org[Apache FreeMarker] is a template engine for generating any
kind of text output from HTML to email, and others. The Spring Framework has a built-in
@ -44,7 +41,8 @@ integration for using Spring MVC with FreeMarker templates.
[[mvc-view-freemarker-contextconfig]]
=== Context configuration
=== View config
[.small]#<<web-reactive.adoc#webflux-view-freemarker-contextconfig,Same in Spring WebFlux>>#
To configure FreeMarker as a view technology:
@ -99,19 +97,14 @@ properties:
</bean>
----
[[mvc-view-freemarker-createtemplates]]
=== Creating templates
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`
shown above. If you use the view resolvers highlighted, then the logical view names
relate to the template file names. So if your controller returns the view name "welcome"
then the resolver will look for the `/WEB-INF/freemarker/welcome.ftl` template.
shown above. Given the above configuration if your controller returns the view name
"welcome" then the resolver will look for the `/WEB-INF/freemarker/welcome.ftl` template.
[[mvc-views-freemarker]]
=== Advanced config
=== FreeMarker config
[.small]#<<web-reactive.adoc#webflux-views-freemarker,Same in Spring WebFlux>>#
FreeMarker 'Settings' and 'SharedVariables' can be passed directly to the FreeMarker
`Configuration` object managed by Spring by setting the appropriate bean properties on
@ -544,29 +537,32 @@ syntax. Here is a sample template for an HTML page:
[[mvc-view-script]]
== Script Views
[.small]#<<web-reactive.adoc#webflux-view-script,Same in Spring WebFlux>>#
The Spring Framework has a built-in integration for using Spring MVC with any
templating library that can runs on top of the https://www.jcp
.org/en/jsr/detail?id=223[JSR-223] Java scripting engine. Below is a list of
templating libraries we've tested on different script engines:
templating library that can run on top of the
https://www.jcp.org/en/jsr/detail?id=223[JSR-223] Java scripting engine. Below is a list
of templating libraries we've tested on different script engines:
* http://handlebarsjs.com/[Handlebars] running on http://openjdk.java.net/projects/nashorn/[Nashorn]
* https://mustache.github.io/[Mustache] running on http://openjdk.java.net/projects/nashorn/[Nashorn]
* http://facebook.github.io/react/[React] running on http://openjdk.java.net/projects/nashorn/[Nashorn]
* http://www.embeddedjs.com/[EJS] running on http://openjdk.java.net/projects/nashorn/[Nashorn]
* http://www.stuartellis.eu/articles/erb/[ERB] running on http://jruby.org[JRuby]
* https://docs.python.org/2/library/string.html#template-strings[String templates] running on http://www.jython.org/[Jython]
[horizontal]
http://handlebarsjs.com/[Handlebars] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
https://mustache.github.io/[Mustache] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://facebook.github.io/react/[React] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.embeddedjs.com/[EJS] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.stuartellis.eu/articles/erb/[ERB] :: http://jruby.org[JRuby]
https://docs.python.org/2/library/string.html#template-strings[String templates] :: http://www.jython.org/[Jython]
[TIP]
====
The basic rule for a script engine is that it must implement the `ScriptEngine` and
`Invocable` interfaces.
The basic rule for integrating any other script engine is that it must implement the
`ScriptEngine` and `Invocable` interfaces.
====
[[mvc-view-script-dependencies]]
=== Requirements
[.small]#<<web-reactive.adoc#webflux-view-script-dependencies,Same in Spring WebFlux>>#
You need to have the script engine on your classpath:
@ -582,21 +578,18 @@ through http://www.webjars.org/[WebJars].
[[mvc-view-script-integrate]]
=== Script templates
To be able to use script templates, you have to configure it in order to specify various parameters
like the script engine to use, the script files to load and what function should be called to
render the templates. This is done thanks to a
[.small]#<<web-reactive.adoc#webflux-script-integrate,Same in Spring WebFlux>>#
Declare a `ScriptTemplateConfigurer` bean in order to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
Below is an exmaple with Mustache templates and the Nashorn JavaScript engine:
Below is an example with Mustache templates and the Nashorn JavaScript engine:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
@EnableWebMvc
public class MustacheConfig implements WebMvcConfigurer {
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
@ -682,7 +675,7 @@ browser facilities not available in the server-side script engine.
----
@Configuration
@EnableWebMvc
public class MustacheConfig implements WebMvcConfigurer {
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
@ -731,9 +724,9 @@ template engine configuration for example).
}
----
Check out Spring script templates unit tests
(https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script[java],
https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/script[resources])
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script[java], and
https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/script[resources],
for more configuration examples.
@ -2000,11 +1993,13 @@ document should appear listing each of the words in the model map.
[[mvc-view-jackson]]
== Jackson
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same in Spring WebFlux>>#
[[mvc-view-json-mapping]]
=== JSON
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same in Spring WebFlux>>#
The `MappingJackson2JsonView` uses the Jackson library's `ObjectMapper` to render the response
content as JSON. By default, the entire contents of the model map (with the exception of
@ -2027,6 +2022,7 @@ name(s) could be customized through the `jsonpParameterNames` property.
[[mvc-view-xml-mapping]]
=== XML
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same in Spring WebFlux>>#
The `MappingJackson2XmlView` uses the
https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML extension]'s `XmlMapper`