Home Java Manual:Thymeleaf+ Spring.Part 3

Manual:Thymeleaf+ Spring.Part 3

by admin

Part 1
Second part

7 Check and error messages

Most of our forms should show validation messages to inform the user of errors they have made.
Thymeleaf offers several tools for this :several functions in the object #fields attributes th:errors and th:errorclass

7.1 Field errors

Let’s see how we can set a specific CSS class for a field if it contains an error :

<input type="text" th:field="*{datePlanted}"th:class="${#fields.hasErrors('datePlanted')}? fieldError" />

As you can see, the function #fields.hasErrors(…) gets a field expression as a parameter ( datePlanted ) and returns a boolean value indicating whether there are any validation errors for that field.
We can also get allthe errors for this field and repeat them :

<ul><li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" /></ul>

Instead of iterating, we could also use th:errors , a specialized attribute that creates a list with all errors for the specified selector, separated by <br /> :

<input type="text" th:field="*{datePlanted}" /><p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}"> Incorrect date</p>

Simplifying CSS Styles Based on Errors : th:errorclass
The example we saw above, setting a CSS class for form input if there are errors in that field is so common that Thymeleaf offers a special attribute to accurately perform : th:errorclass
Applied to a form field tag (input, select, textarea…), it will read the nameof the field to be checked from any existing attributes name or th:field in the same tag, and then add the specified CSS class to the tag if such a field has any related errors :

<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />

If in datePlanted has errors, it will look like this :

<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />

7.2 All errors

What if we want to show all errors in the form? We just need to query the methods #fields.hasErrors(…) and #fields.errors(…) with constants ‘ * ‘ or ‘ all ‘ (which are equivalent):

<ul th:if="${#fields.hasErrors('*')}"><li th:each="err : ${#fields.errors('*')}" th:text="${err}"> Input is incorrect</li></ul>

As in the above examples, we could get all the errors and iterate over them …

<ul><li th:each="err : ${#fields.errors('*')}" th:text="${err}" /></ul>

and also create a split <br /> list :

<p th:if="${#fields.hasErrors('all')}" th:errors="*{all}"> Incorrect date</p>

Finally, note that #fields.hasErrors(‘*’) is equivalent to #fields.hasAnyErrors(‘) , and #fields.errors(‘*’) equivalent to #fields.allErrors(‘) Use whatever syntax you prefer :

<div th:if="${#fields.hasAnyErrors()}"><p th:each="err : ${#fields.allErrors()}" th:text="${err}"> ...</p></div>

7.3 Global errors

There is a third type of error in the Spring form: globalerrors. These are errors that are not related to any specific fields in the form, but still exist.
Thymeleaf offers a constant global to access these errors :

<ul th:if="${#fields.hasErrors('global')}"><li th:each="err : ${#fields.errors('global')}" th:text="${err}"> Input is incorrect</li></ul>

<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}"> Incorrect date</p>

as well as equivalent auxiliary methods #fields.hasGlobalErrors() and #fields.globalErrors() :

7.4 Displaying errors outside the forms

Form validation errors can also be displayed outside the forms with variables ( ${…} ) instead of selection expressions ( *{…} ) and the prefix of the component name supporting the form :

<div th:errors="${myForm}"> ...</div><div th:errors="${myForm.date}"> ...</div><div th:errors="${myForm.*}"> ...</div><div th:if="${#fields.hasErrors('${myForm}')}"> ...</div><div th:if="${#fields.hasErrors('${myForm.date}')}"> ...</div><div th:if="${#fields.hasErrors('${myForm.*}')}"> ...</div><form th:object="${myForm}">...</form>

7.5 Rich error objects

Thymeleaf offers the ability to retrieve form error information as bean components (instead of simple strings) with attributes fieldName (String), message (String) and global (boolean).
These errors can be obtained using the service method #fields.detailedErrors() :

<ul><li th:each="e : ${#fields.detailedErrors()}" th:class="${e.global}? globalerr : fielderr"><span th:text="${e.global}? '*' : ${e.fieldName}"> The field name</span> |<span th:text="${e.message}"> The error message</span></li></ul>

8 This is still a prototype!

Our application is ready. But let’s take another look at the .html page we created …
One of the nicest consequences of working with Thymeleaf is that after all these features we have added to our HTML, we can still use that HTML as a prototype (we say that it Natural Template ). Let’s open seedstartermng.html directly in our browser without running our app :
Manual:Thymeleaf+ Spring.Part 3
This is it! It’s not a working app, it’s not real data … but it’s a perfectly valid prototype, made up of perfectly rendered HTML code.

9 The Conversion Service

9.1 Configuration

As explained earlier, Thymeleaf can use the Transformation Service registered in the application context. Our application configuration class, extending Spring’s own helper WebMvcConfigurerAdapter , will automatically register such a conversion service, which we can customize by adding the necessary formatting tools. Let’s look again at what this looks like :

@Overridepublic void addFormatters(final FormatterRegistry registry) {super.addFormatters(registry);registry.addFormatter(varietyFormatter());registry.addFormatter(dateFormatter());}@Beanpublic VarietyFormatter varietyFormatter() {return new VarietyFormatter();}@Beanpublic DateFormatter dateFormatter() {return new DateFormatter();}

9.2 Double Bracket Syntax

A conversion service can easily be applied to convert/format any object into a string. This is done using the syntax of expressions in double brackets :

  • For variable expressions : ${{…}}
  • To express a choice : *{{…}}

So, for example, given an Integer-to-String converter that adds commas as a thousands separator, this :

<p th:text="${val}"> ...</p><p th:text="${{val}}"> ...</p>

should lead to :

<p> 1234567890</p><p> 1, 234, 567, 890</p>

9.3 Use in Forms

We saw earlier that each attribute th:field will always apply the conversion service, so this :

<input type="text" th:field="*{datePlanted}" />

is actually equivalent to :

<input type="text" th:field="*{{datePlanted}}" />

Note that according to Spring’s requirement, this is the only script in which the conversion service is applied to expressions using single bracketed syntax.

9.4 #conversions object

The #conversions service object allows you to manually run the conversion service where needed :

<p th:text="${'Val: ' + #conversions.convert(val, 'String')}"> ...</p>

Syntax for this service object :

  • #conversions.convert(Object, Class) : converts an object into a specified class
  • #conversions.convert(Object, String) : Same as above, but specifying the target class as String (note that the java.lang. package can be omitted)

10 Draw Template Fragments (AJAXetc)

Thymeleaf offers the ability to visualize only part of a template as a result of its execution : fragment
This can be a useful componentization tool. For example, it can be used on controllers that are executed on calls to AJAX which can return snippets of page markup that is already loaded in the browser (to update selections, enable/disable buttons…).
Fragmentary rendering can be achieved using specifications Thymeleaf fragments:objects that implement the interface org.thymeleaf.fragment.IFragmentSpec
The most common of these implementations is org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec which allows you to specify a fragment using the DOM selector in exactly the same way as the ones used in th:include or th:replace

10.1 Defining fragments in a binary representation

The bean components of a view are the bean components of the class org.thymeleaf.spring4.view.ThymeleafView declared in the application context (annotation Bean if you are using the Java configuration).They allow you to specify fragments as follows :

@Bean(name="content-part")@Scope("prototype")public ThymeleafView someViewBean() {ThymeleafView view = new ThymeleafView("index"); // templateName = 'index'view.setMarkupSelector("content");return view;}

Given the above definition of the bean component, if our controller returns content-part (the name of the aforementioned bean component)…

@RequestMapping("/showContentPart")public String showContentPart() {...return "content-part";}

Thymeleaf will only return a fragment of content of the index pattern – whose location will probably be about the same as /WEB-INF/templates/index.html , after applying the prefix and suffix. Thus, the result will be completely equivalent to specifying index ::content :

<!DOCTYPE html><html>...<body>...<div th:fragment="content">Only this div will be rendered!</div>...</body></html>

Also note that thanks to Thymeleaf’s powerful markup selectors, we can select a fragment in a pattern without any attributes th:fragment Let’s use the attribute id , e.g. :

@Bean(name="content-part")@Scope("prototype")public ThymeleafView someViewBean() {ThymeleafView view = new ThymeleafView("index"); // templateName = 'index'view.setMarkupSelector("#content");return view;}

10.2 Defining fragments in the controller return value

Instead of declaration view beans , fragments can be defined from the controller using the syntax fragment expressions Simply as in attributes th:insert or th:replace

@RequestMapping("/showContentPart")public String showContentPart() {...return "index ::content";}

Of course, again the full power of the DOM selectors is available, so we can select our snippet based on standard HTML attributes, such as id="content" :

@RequestMapping("/showContentPart")public String showContentPart() {...return "index :: #content";}

And we can also use parameters such as :

@RequestMapping("/showContentPart")public String showContentPart() {...return "index :: #content ('myvalue')";}

11 Advanced Integration Features

11.1 Integration with RequestDataValueProcessor

Thymeleaf integrates easily with the Springinterface RequestDataValueProcessor This interface allows you to intercept link URLs, form URLs and form field values before writing them to the markup result, and transparently add hidden form fields that include security features such as : protection against CSRF (cross-site request forgery).
Implementation RequestDataValueProcessor can be easily configured in the context of an application. It should implement the interface org.springframework.web.servlet.support.RequestDataValueProcessor And have requestDataValueProcessor as the bin name :

@Beanpublic RequestDataValueProcessorrequestDataValueProcessor() {return new MyRequestDataValueProcessor();}

and Thymeleaf will use it as follows :

  • th:href and th:src call RequestDataValueProcessor.processUrl(…) Before rendering the URL
  • th:action calls RequestDataValueProcessor.processAction(…) Before rendering the attribute action form, and additionally it detects when this attribute is applied to the <form> tag, which should be the only place in any case, in which case it calls RequestDataValueProcessor.getExtraHiddenFields(…) and adds the returned hidden fields just before the closing tag </form>
  • th:value calls RequestDataValueProcessor.processFormFieldValue(…) To render the value it refers to, unless the same tag contains th:field (in which case th:field will take care of itself)
  • th:field calls RequestDataValueProcessor.processFormFieldValue(…) To render the value of the field to which it is applied (or the body of the tag, if it is <textarea> )

Note that there are very few scenarios in which you would need to explicitly implement RequestDataValueProcessor In your application. In most cases, this will automatically be used by the security libraries you transparently use, such as Spring Security’s CSRF.

11.1 Building URIs to controllers

As of version 4.1, Spring makes it possible to create references to annotated controllers directly from views, without having to know the URIs to which those controllers are mapped.
In Thymeleaf this can be achieved by using the expression #mvc.url(…) , which allows controller methods to be specified by capitalizing the controller class in which they reside, followed by the method name. This is equivalent to the custom function spring:mvcUrlx(…) In JSP.
For example, for :

public class ExampleController {@RequestMapping("/data")public String getData(Model model) { ... return "template" }@RequestMapping("/data")public String getDataParam(@RequestParam String type) { ... return "template" }}

The following code will create method references :

<a th:href="${(#mvc.url('EC#getData')).build()}"> Get Data Param</a><a th:href="${(#mvc.url('EC#getDataParam').arg(0, 'internal')).build()}"> Get Data Param</a>

You can read more about this mechanism at http://docs.spring.io/spring-framework/docs/4.1.2.RELEASE/spring-framework-reference/html/mvc.html#mvc-links-to-controllers-from-views

12 Spring WebFlow integration

Thymeleaf + Spring integration packages include integration with Spring WebFlow (2.3+).
WebFlow includes some AJAX capabilities to render portions of the displayed page when certain events (transitions) are triggered, and in order for Thymeleaf to track these AJAX requests, we need to use another ViewResolverimplementation configured as :

<bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.AjaxThymeleafViewResolver"><property name="viewClass" value="org.thymeleaf.spring4.view.FlowAjaxThymeleafView" /><property name="templateEngine" ref="templateEngine" /></bean>

and then this ViewResolver can be configured in WebFlow ViewFactoryCreator as :

<bean id="mvcViewFactoryCreator"class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"><property name="viewResolvers" ref="thymeleafViewResolver"/></bean>

From here you can define Thymeleaf patterns in your view-state’s:

<view-state id="detail" view="bookingDetail">...</view-state>

In the above example bookingDetail – is the Thymeleaf template, specified in the usual way, understood by any of the template resolvers configured in TemplateEngine.

12.2 AJAX snippets in Spring WebFlow

Note that this only explains how to create AJAX snippets for use with Spring WebFlow. If you’re not using WebFlow, creating a Spring MVC controller that responds to an AJAX request and returns a piece of HTML is just as easy as creating any other controller that returns a pattern, with the only exception that you’ll probably return a snippet like " main :: admin " from your controller method.
WebFlow allows you to define rendering via AJAX with <render> tags, like this :

<view-state id="detail" view="bookingDetail"><transition on="updateData"><render fragments="hoteldata"/></transition></view-state>

These fragments (in this case hoteldata ) can be a comma-separated list of fragments specified in the markup with th:fragment :

<div id="data" th:fragment="hoteldata">This is a content to be changed</div>

Always remember that the specified fragments must have the attribute id so that Spring JavaScript libraries running in the browser can replace the markup.
The <render> tags can also be specified with DOM selectors:
<view-state id="detail" view="bookingDetail">
which means that there is no need for th:fragment :

<div id="data">This is a content to be changed</div>

As for the code that triggers the transition updateData , it looks like this :

<script type="text/javascript" th:src="@{/resources/dojo/dojo.js}"> </script><script type="text/javascript" th:src="@{/resources/spring/Spring.js}"> </script><script type="text/javascript" th:src="@{/resources/spring/Spring-Dojo.js}"> </script>...<form id="triggerform" method="post" action=""><input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" /></form><script type="text/javascript">Spring.addDecoration(new Spring.AjaxEventDecoration({formId:'triggerform', elementId:'doUpdate', event:'onclick'}));</script>

You may also like