diff --git a/src/docs/asciidoc/web/webflux-view.adoc b/src/docs/asciidoc/web/webflux-view.adoc new file mode 100644 index 00000000000..79c3254ce45 --- /dev/null +++ b/src/docs/asciidoc/web/webflux-view.adoc @@ -0,0 +1,288 @@ +[[webflux-view]] += View Technologies +[.small]#<># + +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-view-thymeleaf]] +== Thymeleaf +[.small]#<># + +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]#<># + +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]#<># + +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]#<># + +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 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]#<># + +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]#<># + +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]#<># + +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]#<># + +For <> 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 +<> from `spring-web` such as `Jackson2JsonEncoder`, +`Jackson2SmileEncoder`, or `Jaxb2XmlEncoder`. + +Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`, +but instead is <> 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. + + + + diff --git a/src/docs/asciidoc/web/webflux.adoc b/src/docs/asciidoc/web/webflux.adoc index 7c5dc0875d0..822ab6478bf 100644 --- a/src/docs/asciidoc/web/webflux.adoc +++ b/src/docs/asciidoc/web/webflux.adoc @@ -729,6 +729,8 @@ To configure view resolution is as simple as adding a `ViewResolutionResultHandl to your Spring configuration. <> provides a dedicated configuration API for view resolution. +See <> 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]#<># @@ -2494,6 +2501,8 @@ on the `HttpMessageWriterView` implementation which accepts any of the available } ---- +See <> for more on the view technologies integrated with Spring WebFlux. + diff --git a/src/docs/asciidoc/web/webmvc-view.adoc b/src/docs/asciidoc/web/webmvc-view.adoc index 193bc55381a..a63410da066 100644 --- a/src/docs/asciidoc/web/webmvc-view.adoc +++ b/src/docs/asciidoc/web/webmvc-view.adoc @@ -1,11 +1,6 @@ [[mvc-view]] = View Technologies - - - - -[[mvc-view-introduction]] -== Introduction +[.small]#<># 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-view-thymeleaf]] == Thymeleaf +[.small]#<># 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]#<># 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]#<># To configure FreeMarker as a view technology: @@ -99,19 +97,14 @@ properties: ---- - - -[[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]#<># 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]#<># 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]#<># 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]#<># 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]#<># [[mvc-view-json-mapping]] === JSON +[.small]#<># 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]#<># The `MappingJackson2XmlView` uses the https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML extension]'s `XmlMapper`