From 49eec6248df8c5634c2f4112894ae84c7525273a Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 29 Jan 2018 15:57:34 -0500 Subject: [PATCH] [docs] Reorder View Technologies From: Thymeleaf Groovy Markup FreeMarker JSP & JSTL Script Views XML Tiles XSLT PDF, Excel RSS, Atom Jackson To: Thymeleaf FreeMarker Groovy Markup Script views JSP & JSTL Tiles RSS, Atom PDF, Excel Jackson XML XSLT Also move View Technologies after MVC Config to align order with WebFlux config. Issue: SPR-16393 --- src/docs/asciidoc/web/webmvc-view.adoc | 1248 ++++++++++++------------ src/docs/asciidoc/web/webmvc.adoc | 9 +- 2 files changed, 629 insertions(+), 628 deletions(-) diff --git a/src/docs/asciidoc/web/webmvc-view.adoc b/src/docs/asciidoc/web/webmvc-view.adoc index 401e752348..193bc55381 100644 --- a/src/docs/asciidoc/web/webmvc-view.adoc +++ b/src/docs/asciidoc/web/webmvc-view.adoc @@ -34,90 +34,6 @@ See http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] for more detai -[[mvc-view-groovymarkup]] -== Groovy Markup - -http://groovy-lang.org/templating.html#_the_markuptemplateengine[Groovy Markup Template Engine] -is primarily aimed at generating XML-like markup (XML, XHTML, HTML5, etc) but that can -be used to generate any text based content. The Spring Framework has a built-in -integration for using Spring MVC with Groovy Markup. - -[TIP] -==== -The Groovy Markup Tempalte engine requires Groovy 2.3.1+. -==== - - - -[[mvc-view-groovymarkup-configuration]] -=== Configuration - -To configure the Groovy Markup Template Engine: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebMvc - public class WebConfig implements WebMvcConfigurer { - - @Override - public void configureViewResolvers(ViewResolverRegistry registry) { - registry.groovy(); - } - - // Configure the Groovy Markup Template Engine... - - @Bean - public GroovyMarkupConfigurer groovyMarkupConfigurer() { - GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer(); - configurer.setResourceLoaderPath("/WEB-INF/"); - return configurer; - } - } ----- - -To configure the same in XML: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - ----- - - - -[[mvc-view-groovymarkup-example]] -=== Example - -Unlike traditional template engines, Groovy Markup relies on a DSL that uses a builder -syntax. Here is a sample template for an HTML page: - -[source,groovy,indent=0] -[subs="verbatim,quotes"] ----- - yieldUnescaped '' - html(lang:'en') { - head { - meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"') - title('My page') - } - body { - p('This is an example of HTML contents') - } - } ----- - - - - [[mvc-view-freemarker]] == FreeMarker @@ -542,131 +458,412 @@ In similar fashion, HTML escaping can be specified per field: -[[mvc-view-jsp]] -== JSP & JSTL +[[mvc-view-groovymarkup]] +== Groovy Markup -The Spring Framework has a built-in integration for using Spring MVC with JSP and JSTL. +http://groovy-lang.org/templating.html#_the_markuptemplateengine[Groovy Markup Template Engine] +is primarily aimed at generating XML-like markup (XML, XHTML, HTML5, etc) but that can +be used to generate any text based content. The Spring Framework has a built-in +integration for using Spring MVC with Groovy Markup. +[TIP] +==== +The Groovy Markup Tempalte engine requires Groovy 2.3.1+. +==== -[[mvc-view-jsp-resolver]] -=== View resolvers -When developing with JSPs you can declare a `InternalResourceViewResolver` or a -`ResourceBundleViewResolver` bean. +[[mvc-view-groovymarkup-configuration]] +=== Configuration -`ResourceBundleViewResolver` relies on a properties file to define the view names -mapped to a class and a URL. With a `ResourceBundleViewResolver` you -can mix different types of views using only one resolver. Here is an example: +To configure the Groovy Markup Template Engine: -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - - - + @Configuration + @EnableWebMvc + public class WebConfig implements WebMvcConfigurer { - # And a sample properties file is uses (views.properties in WEB-INF/classes): - welcome.(class)=org.springframework.web.servlet.view.JstlView - welcome.url=/WEB-INF/jsp/welcome.jsp + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + registry.groovy(); + } - productList.(class)=org.springframework.web.servlet.view.JstlView - productList.url=/WEB-INF/jsp/productlist.jsp + // Configure the Groovy Markup Template Engine... + + @Bean + public GroovyMarkupConfigurer groovyMarkupConfigurer() { + GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer(); + configurer.setResourceLoaderPath("/WEB-INF/"); + return configurer; + } + } ---- -`InternalResourceBundleViewResolver` can also be used for JSPs. As a best practice, we -strongly encourage placing your JSP files in a directory under the `'WEB-INF'` -directory so there can be no direct access by clients. +To configure the same in XML: [source,xml,indent=0] [subs="verbatim,quotes"] ---- - - - - - ----- + + + + + + +---- -[[mvc-view-jsp-jstl]] -=== JSPs versus JSTL -When using the Java Standard Tag Library you must use a special view class, the -`JstlView`, as JSTL needs some preparation before things such as the I18N features will -work. +[[mvc-view-groovymarkup-example]] +=== Example +Unlike traditional template engines, Groovy Markup relies on a DSL that uses a builder +syntax. Here is a sample template for an HTML page: -[[mvc-view-jsp-tags]] -=== Spring's JSP tag library +[source,groovy,indent=0] +[subs="verbatim,quotes"] +---- + yieldUnescaped '' + html(lang:'en') { + head { + meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"') + title('My page') + } + body { + p('This is an example of HTML contents') + } + } +---- -Spring provides data binding of request parameters to command objects as described in -earlier chapters. To facilitate the development of JSP pages in combination with those -data binding features, Spring provides a few tags that make things even easier. All -Spring tags have__HTML escaping__ features to enable or disable escaping of characters. -The `spring.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`. -For a comprehensive reference on individual tags, browse the -{api-spring-framework}/web/servlet/tags/package-summary.html#package.description[API reference] -or see the tag library description. -[[mvc-view-jsp-formtaglib]] -=== Spring's form tag library +[[mvc-view-script]] +== Script Views -As of version 2.0, Spring provides a comprehensive set of data binding-aware tags for -handling form elements when using JSP and Spring Web MVC. Each tag provides support for -the set of attributes of its corresponding HTML tag counterpart, making the tags -familiar and intuitive to use. The tag-generated HTML is HTML 4.01/XHTML 1.0 compliant. +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: -Unlike other form/input tag libraries, Spring's form tag library is integrated with -Spring Web MVC, giving the tags access to the command object and reference data your -controller deals with. As you will see in the following examples, the form tags make -JSPs easier to develop, read and maintain. +* 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] -Let's go through the form tags and look at an example of how each tag is used. We have -included generated HTML snippets where certain tags require further commentary. +[TIP] +==== +The basic rule for a script engine is that it must implement the `ScriptEngine` and +`Invocable` interfaces. +==== -[[mvc-view-jsp-formtaglib-configuration]] -==== Configuration -The form tag library comes bundled in `spring-webmvc.jar`. The library descriptor is -called `spring-form.tld`. +[[mvc-view-script-dependencies]] +=== Requirements -To use the tags from this library, add the following directive to the top of your JSP -page: +You need to have the script engine on your classpath: -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> ----- +* 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. -where `form` is the tag name prefix you want to use for the tags from this library. +You need to have the script templating library. One way to do that for Javascript is +through http://www.webjars.org/[WebJars]. -[[mvc-view-jsp-formtaglib-formtag]] -==== The form tag -This tag renders an HTML 'form' tag and exposes a binding path to inner tags for -binding. It puts the command object in the `PageContext` so that the command object can -be accessed by inner tags. __All the other tags in this library are nested tags of the -`form` tag__. +[[mvc-view-script-integrate]] +=== Script templates -Let's assume we have a domain object called `User`. It is a JavaBean with properties -such as `firstName` and `lastName`. We will use it as the form backing object of our -form controller which returns `form.jsp`. Below is an example of what `form.jsp` would -look like: +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 -[source,xml,indent=0] +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: + +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - + @Configuration + @EnableWebMvc + public class MustacheConfig implements WebMvcConfigurer { + + @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 same in XML: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +The controller would look no different: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class SampleController { + + @GetMapping("/sample") + public String test(Model model) { + model.addObject("title", "Sample title"); + model.addObject("body", "Sample body"); + return "template"; + } + } +---- + +And the Mustache template is: + +[source,html,indent=0] +[subs="verbatim,quotes"] +---- + + + {{title}} + + +

{{body}}

+ + +---- + +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 MustacheConfig implements WebMvcConfigurer { + + @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 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]) +for more configuration examples. + + + + +[[mvc-view-jsp]] +== JSP & JSTL + +The Spring Framework has a built-in integration for using Spring MVC with JSP and JSTL. + + + +[[mvc-view-jsp-resolver]] +=== View resolvers + +When developing with JSPs you can declare a `InternalResourceViewResolver` or a +`ResourceBundleViewResolver` bean. + +`ResourceBundleViewResolver` relies on a properties file to define the view names +mapped to a class and a URL. With a `ResourceBundleViewResolver` you +can mix different types of views using only one resolver. Here is an example: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + # And a sample properties file is uses (views.properties in WEB-INF/classes): + welcome.(class)=org.springframework.web.servlet.view.JstlView + welcome.url=/WEB-INF/jsp/welcome.jsp + + productList.(class)=org.springframework.web.servlet.view.JstlView + productList.url=/WEB-INF/jsp/productlist.jsp +---- + +`InternalResourceBundleViewResolver` can also be used for JSPs. As a best practice, we +strongly encourage placing your JSP files in a directory under the `'WEB-INF'` +directory so there can be no direct access by clients. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + + + +[[mvc-view-jsp-jstl]] +=== JSPs versus JSTL + +When using the Java Standard Tag Library you must use a special view class, the +`JstlView`, as JSTL needs some preparation before things such as the I18N features will +work. + + + +[[mvc-view-jsp-tags]] +=== Spring's JSP tag library + +Spring provides data binding of request parameters to command objects as described in +earlier chapters. To facilitate the development of JSP pages in combination with those +data binding features, Spring provides a few tags that make things even easier. All +Spring tags have__HTML escaping__ features to enable or disable escaping of characters. + +The `spring.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`. +For a comprehensive reference on individual tags, browse the +{api-spring-framework}/web/servlet/tags/package-summary.html#package.description[API reference] +or see the tag library description. + + +[[mvc-view-jsp-formtaglib]] +=== Spring's form tag library + +As of version 2.0, Spring provides a comprehensive set of data binding-aware tags for +handling form elements when using JSP and Spring Web MVC. Each tag provides support for +the set of attributes of its corresponding HTML tag counterpart, making the tags +familiar and intuitive to use. The tag-generated HTML is HTML 4.01/XHTML 1.0 compliant. + +Unlike other form/input tag libraries, Spring's form tag library is integrated with +Spring Web MVC, giving the tags access to the command object and reference data your +controller deals with. As you will see in the following examples, the form tags make +JSPs easier to develop, read and maintain. + +Let's go through the form tags and look at an example of how each tag is used. We have +included generated HTML snippets where certain tags require further commentary. + + +[[mvc-view-jsp-formtaglib-configuration]] +==== Configuration + +The form tag library comes bundled in `spring-webmvc.jar`. The library descriptor is +called `spring-form.tld`. + +To use the tags from this library, add the following directive to the top of your JSP +page: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +---- + +where `form` is the tag name prefix you want to use for the tags from this library. + + +[[mvc-view-jsp-formtaglib-formtag]] +==== The form tag + +This tag renders an HTML 'form' tag and exposes a binding path to inner tags for +binding. It puts the command object in the `PageContext` so that the command object can +be accessed by inner tags. __All the other tags in this library are nested tags of the +`form` tag__. + +Let's assume we have a domain object called `User`. It is a JavaBean with properties +such as `firstName` and `lastName`. We will use it as the form backing object of our +form controller which returns `form.jsp`. Below is an example of what `form.jsp` would +look like: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +
@@ -1295,294 +1492,83 @@ The HTML would look like: ---- -The `spring-form.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`. -For a comprehensive reference on individual tags, browse the -{api-spring-framework}/web/servlet/tags/form/package-summary.html#package.description[API reference] -or see the tag library description. - - -[[mvc-rest-method-conversion]] -==== HTTP method conversion - -A key principle of REST is the use of the Uniform Interface. This means that all -resources (URLs) can be manipulated using the same four HTTP methods: GET, PUT, POST, -and DELETE. For each method, the HTTP specification defines the exact semantics. For -instance, a GET should always be a safe operation, meaning that is has no side effects, -and a PUT or DELETE should be idempotent, meaning that you can repeat these operations -over and over again, but the end result should be the same. While HTTP defines these -four methods, HTML only supports two: GET and POST. Fortunately, there are two possible -workarounds: you can either use JavaScript to do your PUT or DELETE, or simply do a POST -with the 'real' method as an additional parameter (modeled as a hidden input field in an -HTML form). This latter trick is what Spring's `HiddenHttpMethodFilter` does. This -filter is a plain Servlet Filter and therefore it can be used in combination with any -web framework (not just Spring MVC). Simply add this filter to your web.xml, and a POST -with a hidden _method parameter will be converted into the corresponding HTTP method -request. - -To support HTTP method conversion the Spring MVC form tag was updated to support setting -the HTTP method. For example, the following snippet taken from the updated Petclinic -sample - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - -

-
----- - -This will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a -request parameter, to be picked up by the `HiddenHttpMethodFilter`, as defined in -web.xml: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - - httpMethodFilter - org.springframework.web.filter.HiddenHttpMethodFilter - - - - httpMethodFilter - petclinic - ----- - -The corresponding `@Controller` method is shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @RequestMapping(method = RequestMethod.DELETE) - public String deletePet(@PathVariable int ownerId, @PathVariable int petId) { - this.clinic.deletePet(petId); - return "redirect:/owners/" + ownerId; - } ----- - - -[[mvc-view-jsp-formtaglib-html5]] -==== HTML5 tags - -Starting with Spring 3, the Spring form tag library allows entering dynamic attributes, -which means you can enter any HTML5 specific attributes. - -In Spring 3.1, the form input tag supports entering a type attribute other than 'text'. -This is intended to allow rendering new HTML5 specific input types such as 'email', -'date', 'range', and others. Note that entering type='text' is not required since 'text' -is the default type. - - - - -[[mvc-view-script]] -== Script views - -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: - -* 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] - -[TIP] -==== -The basic rule for a script engine is that it must implement the `ScriptEngine` and -`Invocable` interfaces. -==== - - - -[[mvc-view-script-dependencies]] -=== Requirements - -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]. - - - -[[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 - -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: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebMvc - public class MustacheConfig implements WebMvcConfigurer { - - @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 same in XML: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -The controller would look no different: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class SampleController { - - @GetMapping("/sample") - public String test(Model model) { - model.addObject("title", "Sample title"); - model.addObject("body", "Sample body"); - return "template"; - } - } ----- - -And the Mustache template is: - -[source,html,indent=0] -[subs="verbatim,quotes"] ----- - - - {{title}} - - -

{{body}}

- - ----- - -The render function is called with the following parameters: +The `spring-form.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`. +For a comprehensive reference on individual tags, browse the +{api-spring-framework}/web/servlet/tags/form/package-summary.html#package.description[API reference] +or see the tag library description. -* `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. +[[mvc-rest-method-conversion]] +==== HTTP method conversion -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. +A key principle of REST is the use of the Uniform Interface. This means that all +resources (URLs) can be manipulated using the same four HTTP methods: GET, PUT, POST, +and DELETE. For each method, the HTTP specification defines the exact semantics. For +instance, a GET should always be a safe operation, meaning that is has no side effects, +and a PUT or DELETE should be idempotent, meaning that you can repeat these operations +over and over again, but the end result should be the same. While HTTP defines these +four methods, HTML only supports two: GET and POST. Fortunately, there are two possible +workarounds: you can either use JavaScript to do your PUT or DELETE, or simply do a POST +with the 'real' method as an additional parameter (modeled as a hidden input field in an +HTML form). This latter trick is what Spring's `HiddenHttpMethodFilter` does. This +filter is a plain Servlet Filter and therefore it can be used in combination with any +web framework (not just Spring MVC). Simply add this filter to your web.xml, and a POST +with a hidden _method parameter will be converted into the corresponding HTTP method +request. -[source,java,indent=0] +To support HTTP method conversion the Spring MVC form tag was updated to support setting +the HTTP method. For example, the following snippet taken from the updated Petclinic +sample + +[source,xml,indent=0] [subs="verbatim,quotes"] ---- - @Configuration - @EnableWebMvc - public class MustacheConfig implements WebMvcConfigurer { - - @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: +This will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a +request parameter, to be picked up by the `HiddenHttpMethodFilter`, as defined in +web.xml: -[source,javascript,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - var window = {}; + + httpMethodFilter + org.springframework.web.filter.HiddenHttpMethodFilter + + + + httpMethodFilter + petclinic + ---- -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). +The corresponding `@Controller` method is shown below: -[source,javascript,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - function render(template, model) { - var compiledTemplate = Handlebars.compile(template); - return compiledTemplate(model); + @RequestMapping(method = RequestMethod.DELETE) + public String deletePet(@PathVariable int ownerId, @PathVariable int petId) { + this.clinic.deletePet(petId); + return "redirect:/owners/" + ownerId; } ---- -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]) -for more configuration examples. - - +[[mvc-view-jsp-formtaglib-html5]] +==== HTML5 tags -[[mvc-view-xml-marshalling]] -== XML Marshalling +Starting with Spring 3, the Spring form tag library allows entering dynamic attributes, +which means you can enter any HTML5 specific attributes. -The `MarshallingView` uses an XML `Marshaller` defined in the `org.springframework.oxm` -package to render the response content as XML. The object to be marshalled can be set -explicitly using ``MarhsallingView``'s `modelKey` bean property. Alternatively, the view -will iterate over all model properties and marshal the first type that is supported -by the `Marshaller`. For more information on the functionality in the -`org.springframework.oxm` package refer to the chapter <>. +In Spring 3.1, the form input tag supports entering a type attribute other than 'text'. +This is intended to allow rendering new HTML5 specific input types such as 'email', +'date', 'range', and others. Note that entering type='text' is not required since 'text' +is the default type. @@ -1764,161 +1750,73 @@ per preparer name (as used in your Tiles definitions). -[[mvc-view-xslt]] -== XSLT - -XSLT is a transformation language for XML and is popular as a view technology within web -applications. XSLT can be a good choice as a view technology if your application -naturally deals with XML, or if your model can easily be converted to XML. The following -section shows how to produce an XML document as model data and have it transformed with -XSLT in a Spring Web MVC application. - -This example is a trivial Spring application that creates a list of words in the -`Controller` and adds them to the model map. The map is returned along with the view -name of our XSLT view. See <> for details of Spring Web MVC's -`Controller` interface. The XSLT Controller will turn the list of words into a simple XML -document ready for transformation. - - - -[[mvc-view-xslt-beandefs]] -=== Beans - -Configuration is standard for a simple Spring application. -The MVC configuration has to define a `XsltViewResolver` bean and -regular MVC annotation configuration. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@EnableWebMvc -@ComponentScan -@Configuration -public class WebConfig implements WebMvcConfigurer { - - @Bean - public XsltViewResolver xsltViewResolver() { - XsltViewResolver viewResolver = new XsltViewResolver(); - viewResolver.setPrefix("/WEB-INF/xsl/"); - viewResolver.setSuffix(".xslt"); - return viewResolver; - } - -} ----- - -And we need a Controller that encapsulates our word generation logic. - - +[[mvc-view-feeds]] +== RSS, Atom -[[mvc-view-xslt-controllercode]] -=== Controller +Both `AbstractAtomFeedView` and `AbstractRssFeedView` inherit from the base class +`AbstractFeedView` and are used to provide Atom and RSS Feed views respectfully. They +are based on java.net's https://rome.dev.java.net[ROME] project and are located in the +package `org.springframework.web.servlet.view.feed`. -The controller logic is encapsulated in a `@Controller` class, with the -handler method being defined like so... +`AbstractAtomFeedView` requires you to implement the `buildFeedEntries()` method and +optionally override the `buildFeedMetadata()` method (the default implementation is +empty), as shown below. [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Controller - public class XsltController { - - @RequestMapping("/") - public String home(Model model) throws Exception { - - Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - Element root = document.createElement("wordList"); + public class SampleContentAtomView extends AbstractAtomFeedView { - List words = Arrays.asList("Hello", "Spring", "Framework"); - for (String word : words) { - Element wordNode = document.createElement("word"); - Text textNode = document.createTextNode(word); - wordNode.appendChild(textNode); - root.appendChild(wordNode); - } + @Override + protected void buildFeedMetadata(Map model, + Feed feed, HttpServletRequest request) { + // implementation omitted + } - model.addAttribute("wordList", root); - return "home"; + @Override + protected List buildFeedEntries(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + // implementation omitted } } ---- -So far we've only created a DOM document and added it to the Model map. Note that you -can also load an XML file as a `Resource` and use it instead of a custom DOM document. - -Of course, there are software packages available that will automatically 'domify' -an object graph, but within Spring, you have complete flexibility to create the DOM -from your model in any way you choose. This prevents the transformation of XML playing -too great a part in the structure of your model data which is a danger when using tools -to manage the domification process. - -Next, `XsltViewResolver` will resolve the "home" XSLT template file and merge the -DOM document into it to generate our view. - - - -[[mvc-view-xslt-transforming]] -=== Transformation - -Finally, the `XsltViewResolver` will resolve the "home" XSLT template file and merge the -DOM document into it to generate our view. As shown in the `XsltViewResolver` -configuration, XSLT templates live in the war file in the `'WEB-INF/xsl'` directory -and end with a `"xslt"` file extension. +Similar requirements apply for implementing `AbstractRssFeedView`, as shown below. -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - - - + public class SampleContentAtomView extends AbstractRssFeedView { - - - Hello! - -

My First Words

-
    - -
- - -
+ @Override + protected void buildFeedMetadata(Map model, + Channel feed, HttpServletRequest request) { + // implementation omitted + } - -
  • -
    + @Override + protected List buildFeedItems(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + // implementation omitted + } -
    + } ---- -This is rendered as: +The `buildFeedItems()` and `buildFeedEntires()` methods pass in the HTTP request in case +you need to access the Locale. The HTTP response is passed in only for the setting of +cookies or other HTTP headers. The feed will automatically be written to the response +object after the method returns. -[source,html,indent=0] -[subs="verbatim,quotes"] ----- - - - - Hello! - - -

    My First Words

    -
      -
    • Hello
    • -
    • Spring
    • -
    • Framework
    • -
    - - ----- +For an example of creating an Atom view please refer to Alef Arendsen's Spring Team Blog +https://spring.io/blog/2009/03/16/adding-an-atom-view-to-an-application-using-spring-s-rest-support[entry]. [[mvc-view-document]] -== Document views: PDF, Excel +== PDF, Excel @@ -2100,71 +1998,6 @@ document should appear listing each of the words in the model map. -[[mvc-view-feeds]] -== Feed views: RSS, Atom - -Both `AbstractAtomFeedView` and `AbstractRssFeedView` inherit from the base class -`AbstractFeedView` and are used to provide Atom and RSS Feed views respectfully. They -are based on java.net's https://rome.dev.java.net[ROME] project and are located in the -package `org.springframework.web.servlet.view.feed`. - -`AbstractAtomFeedView` requires you to implement the `buildFeedEntries()` method and -optionally override the `buildFeedMetadata()` method (the default implementation is -empty), as shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class SampleContentAtomView extends AbstractAtomFeedView { - - @Override - protected void buildFeedMetadata(Map model, - Feed feed, HttpServletRequest request) { - // implementation omitted - } - - @Override - protected List buildFeedEntries(Map model, - HttpServletRequest request, HttpServletResponse response) throws Exception { - // implementation omitted - } - - } ----- - -Similar requirements apply for implementing `AbstractRssFeedView`, as shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class SampleContentAtomView extends AbstractRssFeedView { - - @Override - protected void buildFeedMetadata(Map model, - Channel feed, HttpServletRequest request) { - // implementation omitted - } - - @Override - protected List buildFeedItems(Map model, - HttpServletRequest request, HttpServletResponse response) throws Exception { - // implementation omitted - } - - } ----- - -The `buildFeedItems()` and `buildFeedEntires()` methods pass in the HTTP request in case -you need to access the Locale. The HTTP response is passed in only for the setting of -cookies or other HTTP headers. The feed will automatically be written to the response -object after the method returns. - -For an example of creating an Atom view please refer to Alef Arendsen's Spring Team Blog -https://spring.io/blog/2009/03/16/adding-an-atom-view-to-an-application-using-spring-s-rest-support[entry]. - - - - [[mvc-view-jackson]] == Jackson @@ -2205,3 +2038,170 @@ XML mapping can be customized as needed through the use of JAXB or Jackson's pro annotations. When further control is needed, a custom `XmlMapper` can be injected through the `ObjectMapper` property for cases where custom XML serializers/deserializers need to be provided for specific types. + + + + +[[mvc-view-xml-marshalling]] +== XML + +The `MarshallingView` uses an XML `Marshaller` defined in the `org.springframework.oxm` +package to render the response content as XML. The object to be marshalled can be set +explicitly using ``MarhsallingView``'s `modelKey` bean property. Alternatively, the view +will iterate over all model properties and marshal the first type that is supported +by the `Marshaller`. For more information on the functionality in the +`org.springframework.oxm` package refer to the chapter <>. + + + + +[[mvc-view-xslt]] +== XSLT + +XSLT is a transformation language for XML and is popular as a view technology within web +applications. XSLT can be a good choice as a view technology if your application +naturally deals with XML, or if your model can easily be converted to XML. The following +section shows how to produce an XML document as model data and have it transformed with +XSLT in a Spring Web MVC application. + +This example is a trivial Spring application that creates a list of words in the +`Controller` and adds them to the model map. The map is returned along with the view +name of our XSLT view. See <> for details of Spring Web MVC's +`Controller` interface. The XSLT Controller will turn the list of words into a simple XML +document ready for transformation. + + + +[[mvc-view-xslt-beandefs]] +=== Beans + +Configuration is standard for a simple Spring application. +The MVC configuration has to define a `XsltViewResolver` bean and +regular MVC annotation configuration. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@EnableWebMvc +@ComponentScan +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Bean + public XsltViewResolver xsltViewResolver() { + XsltViewResolver viewResolver = new XsltViewResolver(); + viewResolver.setPrefix("/WEB-INF/xsl/"); + viewResolver.setSuffix(".xslt"); + return viewResolver; + } + +} +---- + +And we need a Controller that encapsulates our word generation logic. + + + +[[mvc-view-xslt-controllercode]] +=== Controller + +The controller logic is encapsulated in a `@Controller` class, with the +handler method being defined like so... + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class XsltController { + + @RequestMapping("/") + public String home(Model model) throws Exception { + + Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + Element root = document.createElement("wordList"); + + List words = Arrays.asList("Hello", "Spring", "Framework"); + for (String word : words) { + Element wordNode = document.createElement("word"); + Text textNode = document.createTextNode(word); + wordNode.appendChild(textNode); + root.appendChild(wordNode); + } + + model.addAttribute("wordList", root); + return "home"; + } + + } +---- + +So far we've only created a DOM document and added it to the Model map. Note that you +can also load an XML file as a `Resource` and use it instead of a custom DOM document. + +Of course, there are software packages available that will automatically 'domify' +an object graph, but within Spring, you have complete flexibility to create the DOM +from your model in any way you choose. This prevents the transformation of XML playing +too great a part in the structure of your model data which is a danger when using tools +to manage the domification process. + +Next, `XsltViewResolver` will resolve the "home" XSLT template file and merge the +DOM document into it to generate our view. + + + +[[mvc-view-xslt-transforming]] +=== Transformation + +Finally, the `XsltViewResolver` will resolve the "home" XSLT template file and merge the +DOM document into it to generate our view. As shown in the `XsltViewResolver` +configuration, XSLT templates live in the war file in the `'WEB-INF/xsl'` directory +and end with a `"xslt"` file extension. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + Hello! + +

    My First Words

    +
      + +
    + + +
    + + +
  • +
    + +
    +---- + +This is rendered as: + +[source,html,indent=0] +[subs="verbatim,quotes"] +---- + + + + Hello! + + +

    My First Words

    +
      +
    • Hello
    • +
    • Spring
    • +
    • Framework
    • +
    + + +---- \ No newline at end of file diff --git a/src/docs/asciidoc/web/webmvc.adoc b/src/docs/asciidoc/web/webmvc.adoc index aa740a3b47..9aff5be5b8 100644 --- a/src/docs/asciidoc/web/webmvc.adoc +++ b/src/docs/asciidoc/web/webmvc.adoc @@ -3760,6 +3760,11 @@ https://tools.ietf.org/html/rfc7232#section-2.3[RFC 7232 Section 2.3]. +include::webmvc-view.adoc[leveloffset=+1] + + + + [[mvc-config]] == MVC Config [.small]#<># @@ -4578,10 +4583,6 @@ detected through a `` declaration. -include::webmvc-view.adoc[leveloffset=+1] - - - [[mvc-http2]] == HTTP/2 [.small]#<># -- GitLab
    First Name: