Welcome to our grocery store!
``` The first thing you will notice is that this file is HTML5 that can be correctly displayed by any browser because it does not include any non-HTML tags (browsers ignore all attributes they don't understand, like `th:text`). But you may also notice that this template is not really a _valid_ HTML5 document, because these non-standard attributes we are using in the `th:*` form are not allowed by the HTML5 specification. In fact, we are even adding an `xmlns:th` attribute to our `` tag, something absolutely non-HTML5-ish: ```html ``` ...which has no influence at all in template processing, but works as an *incantation* that prevents our IDE from complaining about the lack of a namespace definition for all those `th:*` attributes. So what if we wanted to make this template **HTML5-valid**? Easy: switch to Thymeleaf's data attribute syntax, using the `data-` prefix for attribute names and hyphen (`-`) separators instead of semi-colons (`:`): ```htmlWelcome to our grocery store!
``` Custom `data-` prefixed attributes are allowed by the HTML5 specification, so, with this code above, our template would be a *valid HTML5 document*. > Both notations are completely equivalent and interchangeable, but for the sake > of simplicity and compactness of the code samples, this tutorial will use the > *namespace notation* (`th:*`). Also, the `th:*` notation is more general and > allowed in every Thymeleaf template mode (`XML`, `TEXT`...) whereas the `data-` > notation is only allowed in `HTML` mode. ### Using th:text and externalizing text Externalizing text is extracting fragments of template code out of template files so that they can be kept in separate files (typically `.properties` files) and that they can be easily replaced with equivalent texts written in other languages (a process called internationalization or simply _i18n_). Externalized fragments of text are usually called *"messages"*. Messages always have a key that identifies them, and Thymeleaf allows you to specify that a text should correspond to a specific message with the `#{...}` syntax: ```htmlWelcome to our grocery store!
``` What we can see here are in fact two different features of the Thymeleaf Standard Dialect: * The `th:text` attribute, which evaluates its value expression and sets the result as the body of the host tag, effectively replacing the "Welcome to our grocery store!" text we see in the code. * The `#{home.welcome}` expression, specified in the _Standard Expression Syntax_, instructing that the text to be used by the `th:text` attribute should be the message with the `home.welcome` key corresponding to whichever locale we are processing the template with. Now, where is this externalized text? The location of externalized text in Thymeleaf is fully configurable, and it will depend on the specific `org.thymeleaf.messageresolver.IMessageResolver` implementation being used. Normally, an implementation based on `.properties` files will be used, but we could create our own implementations if we wanted, for example, to obtain messages from a database. However, we have not specified a message resolver for our template engine during initialization, and that means that our application is using the _Standard Message Resolver_, implemented by `org.thymeleaf.messageresolver.StandardMessageResolver`. The standard message resolver expects to find messages for `/WEB-INF/templates/home.html` in properties files in the same folder and with the same name as the template, like: * `/WEB-INF/templates/home_en.properties` for English texts. * `/WEB-INF/templates/home_es.properties` for Spanish language texts. * `/WEB-INF/templates/home_pt_BR.properties` for Portuguese (Brazil) language texts. * `/WEB-INF/templates/home.properties` for default texts (if the locale is not matched). Let's have a look at our `home_es.properties` file: ``` home.welcome=¡Bienvenido a nuestra tienda de comestibles! ``` This is all we need for making Thymeleaf process our template. Let's create our Home controller then. ### Contexts In order to process our template, we will create a `HomeController` class implementing the `IGTVGController` interface we saw before: ```java public class HomeController implements IGTVGController { public void process( final IWebExchange webExchange, final ITemplateEngine templateEngine, final Writer writer) throws Exception { WebContext ctx = new WebContext(webExchange, webExchange.getLocale()); templateEngine.process("home", ctx, writer); } } ``` The first thing we see is the creation of a *context*. A Thymeleaf context is an object implementing the `org.thymeleaf.context.IContext` interface. Contexts should contain all the data required for an execution of the template engine in a variables map, and also reference the locale that must be used for externalized messages. ```java public interface IContext { public Locale getLocale(); public boolean containsVariable(final String name); public Set¡Bienvenido a nuestra tienda de comestibles!
``` 3.2 More on texts and variables ------------------------------- ### Unescaped Text The simplest version of our Home page seems to be ready now, but there is something we have not thought about... what if we had a message like this? ```java home.welcome=Welcome to our fantastic grocery store! ``` If we execute this template like before, we will obtain: ```htmlWelcome to our <b>fantastic</b> grocery store!
``` Which is not exactly what we expected, because our `` tag has been escaped and therefore it will be displayed in the browser. This is the default behaviour of the `th:text` attribute. If we want Thymeleaf to respect our HTML tags and not escape them, we will have to use a different attribute: `th:utext` (for "unescaped text"): ```htmlWelcome to our grocery store!
``` This will output our message just like we wanted it: ```htmlWelcome to our fantastic grocery store!
``` ### Using and displaying variables Now let's add some more content to our home page. For example, we may want to display the date below our welcome message, like this: ``` Welcome to our fantastic grocery store! Today is: 12 july 2010 ``` First of all, we will have to modify our controller so that we add that date as a context variable: ```java public void process( final IWebExchange webExchange, final ITemplateEngine templateEngine, final Writer writer) throws Exception { SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); Calendar cal = Calendar.getInstance(); WebContext ctx = new WebContext(webExchange, webExchange.getLocale()); ctx.setVariable("today", dateFormat.format(cal.getTime())); templateEngine.process("home", ctx, writer); } ``` We have added a `String` variable called `today` to our context, and now we can display it in our template: ```htmlWelcome to our grocery store!
Today is: 13 February 2011
``` As you can see, we are still using the `th:text` attribute for the job (and that's correct, because we want to replace the tag's body), but the syntax is a little bit different this time and instead of a `#{...}` expression value, we are using a `${...}` one. This is a **variable expression**, and it contains an expression in a language called _OGNL (Object-Graph Navigation Language)_ that will be executed on the context variables map we talked about before. The `${today}` expression simply means "get the variable called today", but these expressions could be more complex (like `${user.name}` for "get the variable called user, and call its `getName()` method"). There are quite a lot of possibilities in attribute values: messages, variable expressions... and quite a lot more. The next chapter will show us what all these possibilities are. 4 Standard Expression Syntax ============================ We will take a small break in the development of our grocery virtual store to learn about one of the most important parts of the Thymeleaf Standard Dialect: the Thymeleaf Standard Expression syntax. We have already seen two types of valid attribute values expressed in this syntax: message and variable expressions: ```htmlWelcome to our grocery store!
Today is: 13 february 2011
``` But there are more types of expressions, and more interesting details to learn about the ones we already know. First, let's see a quick summary of the Standard Expression features: * Simple expressions: * Variable Expressions: `${...}` * Selection Variable Expressions: `*{...}` * Message Expressions: `#{...}` * Link URL Expressions: `@{...}` * Fragment Expressions: `~{...}` * Literals * Text literals: `'one text'`, `'Another one!'`,... * Number literals: `0`, `34`, `3.0`, `12.3`,... * Boolean literals: `true`, `false` * Null literal: `null` * Literal tokens: `one`, `sometext`, `main`,... * Text operations: * String concatenation: `+` * Literal substitutions: `|The name is ${name}|` * Arithmetic operations: * Binary operators: `+`, `-`, `*`, `/`, `%` * Minus sign (unary operator): `-` * Boolean operations: * Binary operators: `and`, `or` * Boolean negation (unary operator): `!`, `not` * Comparisons and equality: * Comparators: `>`, `<`, `>=`, `<=` (`gt`, `lt`, `ge`, `le`) * Equality operators: `==`, `!=` (`eq`, `ne`) * Conditional operators: * If-then: `(if) ? (then)` * If-then-else: `(if) ? (then) : (else)` * Default: `(value) ?: (defaultvalue)` * Special tokens: * No-Operation: `_` All these features can be combined and nested: ```html 'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown')) ``` 4.1 Messages ------------ As we already know, `#{...}` message expressions allow us to link this: ```htmlWelcome to our grocery store!
``` ...to this: ``` home.welcome=¡Bienvenido a nuestra tienda de comestibles! ``` But there's one aspect we still haven't thought of: what happens if the message text is not completely static? What if, for example, our application knew who is the user visiting the site at any moment and we wanted to greet them by name? ```html¡Bienvenido a nuestra tienda de comestibles, John Apricot!
``` This means we would need to add a parameter to our message. Just like this: ``` home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}! ``` Parameters are specified according to the [`java.text.MessageFormat`](https://docs.oracle.com/javase/10/docs/api/java/text/MessageFormat.html) standard syntax, which means you can format to numbers and dates as specified in the API docs for classes in the `java.text.*` package. In order to specify a value for our parameter, and given an HTTP session attribute called `user`, we could have: ```htmlWelcome to our grocery store, Sebastian Pepper!
``` > Note that the use of `th:utext` here means that the formatted message will > not be escaped. This example assumes that `user.name` is already escaped. Several parameters can be specified, separated by commas. The message key itself can come from a variable: ```htmlWelcome to our grocery store, Sebastian Pepper!
``` 4.2 Variables ------------- We already mentioned that `${...}` expressions are in fact OGNL (Object-Graph Navigation Language) expressions executed on the map of variables contained in the context. > For detailed info about OGNL syntax and features, you should read the > [OGNL Language Guide](http://commons.apache.org/ognl/) > > In Spring MVC-enabled applications OGNL will be replaced with **SpringEL**, > but its syntax is very similar to that of OGNL (actually, exactly the same for > most common cases). From OGNL's syntax, we know that the expression in: ```htmlToday is: 13 february 2011.
``` ...is in fact equivalent to this: ```java ctx.getVariable("today"); ``` But OGNL allows us to create quite more powerful expressions, and that's how this: ```htmlWelcome to our grocery store, Sebastian Pepper!
``` ...obtains the user name by executing: ```java ((User) ctx.getVariable("session").get("user")).getName(); ``` But getter method navigation is just one of OGNL's features. Let's see some more: ```java /* * Access to properties using the point (.). Equivalent to calling property getters. */ ${person.father.name} /* * Access to properties can also be made by using brackets ([]) and writing * the name of the property as a variable or between single quotes. */ ${person['father']['name']} /* * If the object is a map, both dot and bracket syntax will be equivalent to * executing a call on its get(...) method. */ ${countriesByCode.ES} ${personsByName['Stephen Zucchini'].age} /* * Indexed access to arrays or collections is also performed with brackets, * writing the index without quotes. */ ${personsArray[0].name} /* * Methods can be called, even with arguments. */ ${person.createCompleteName()} ${person.createCompleteNameWithSeparator('-')} ``` ### Expression Basic Objects When evaluating OGNL expressions on the context variables, some objects are made available to expressions for higher flexibility. These objects will be referenced (per OGNL standard) starting with the `#` symbol: * `#ctx`: the context object. * `#vars:` the context variables. * `#locale`: the context locale. So we can do this: ```html Established locale country: US. ``` You can read the full reference of these objects in [Appendix A](#appendix-a-expression-basic-objects). ### Expression Utility Objects Besides these basic objects, Thymeleaf will offer us a set of utility objects that will help us perform common tasks in our expressions. * `#execInfo`: information about the template being processed. * `#messages`: methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{...} syntax. * `#uris`: methods for escaping parts of URLs/URIs * `#conversions`: methods for executing the configured *conversion service* (if any). * `#dates`: methods for `java.util.Date` objects: formatting, component extraction, etc. * `#calendars`: analogous to `#dates`, but for `java.util.Calendar` objects. * `#temporals`: for dealing with dates and times using the `java.time` API in JDK8+. * `#numbers`: methods for formatting numeric objects. * `#strings`: methods for `String` objects: contains, startsWith, prepending/appending, etc. * `#objects`: methods for objects in general. * `#bools`: methods for boolean evaluation. * `#arrays`: methods for arrays. * `#lists`: methods for lists. * `#sets`: methods for sets. * `#maps`: methods for maps. * `#aggregates`: methods for creating aggregates on arrays or collections. * `#ids`: methods for dealing with id attributes that might be repeated (for example, as a result of an iteration). You can check what functions are offered by each of these utility objects in the [Appendix B](#appendix-b-expression-utility-objects). ### Reformatting dates in our home page Now we know about these utility objects, we could use them to change the way in which we show the date in our home page. Instead of doing this in our `HomeController`: ```java SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); Calendar cal = Calendar.getInstance(); WebContext ctx = new WebContext(webExchange, webExchange.getLocale()); ctx.setVariable("today", dateFormat.format(cal.getTime())); templateEngine.process("home", ctx, writer); ``` ...we can do just this: ```java WebContext ctx = new WebContext(webExchange, webExchange.getLocale()); ctx.setVariable("today", Calendar.getInstance()); templateEngine.process("home", ctx, writer); ``` ...and then perform date formatting in the view layer itself: ```htmlToday is: 13 May 2011
``` 4.3 Expressions on selections (asterisk syntax) ----------------------------------------------- Not only can variable expressions be written as `${...}`, but also as `*{...}`. There is an important difference though: the asterisk syntax evaluates expressions on _selected objects_ rather than on the whole context. That is, as long as there is no selected object, the dollar and the asterisk syntaxes do exactly the same. And what is a selected object? The result of an expression using the `th:object` attribute. Let's use one in our user profile (`userprofile.html`) page: ```htmlName: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Please select an option
``` ### Server root relative URLs An additional syntax can be used to create server-root-relative (instead of context-root-relative) URLs in order to link to different contexts in the same server. These URLs will be specified like `@{~/path/to/something}` 4.5 Fragments ------------- Fragment expressions are an easy way to represent fragments of markup and move them around templates. This allows us to replicate them, pass them to other templates as arguments, and so on. The most common use is for fragment insertion using `th:insert` or `th:replace` (more on these in a later section): ```html
Now you are looking at a template file.
``` ### Number literals Numeric literals are just that: numbers. ```htmlThe year is 1492.
In two years, it will be 1494.
``` ### Boolean literals The boolean literals are `true` and `false`. For example: ```htmlAge: 27.
Age: 27.
``` As with conditional values, they can contain nested expressions between parentheses: ```htmlName: Sebastian
``` 4.13 The No-Operation token --------------------------- The No-Operation token is represented by an underscore symbol (`_`). The idea behind this token is to specify that the desired result for an expression is to *do nothing*, i.e. do exactly as if the processable attribute (e.g. `th:text`) was not there at all. Among other possibilities, this allows developers to use prototyping text as default values. For example, instead of: ```html ... ``` ...we can directly use *'no user authenticated'* as a prototyping text, which results in code that is both more concise and versatile from a design standpoint: ```html no user authenticated ``` 4.14 Data Conversion / Formatting --------------------------------- Thymeleaf defines a *double-brace* syntax for variable (`${...}`) and selection (`*{...}`) expressions that allows us to apply *data conversion* by means of a configured *conversion service*. It basically goes like this: ```htmlSome text here...
``` Note that the preprocessing step for a French locale will be creating the following equivalent: ```htmlSome text here...
``` The preprocessing String `__` can be escaped in attributes using `\_\_`. 5 Setting Attribute Values ========================== This chapter will explain the way in which we can set (or modify) values of attributes in our markup. 5.1 Setting the value of any attribute -------------------------------------- Say our website publishes a newsletter, and we want our users to be able to subscribe to it, so we create a `/WEB-INF/templates/subscribe.html` template with a form: ```html ``` As with Thymeleaf, this template starts off more like a static prototype than it does a template for a web application. First, the `action` attribute in our form statically links to the template file itself, so that there is no place for useful URL rewriting. Second, the `value` attribute in the submit button makes it display a text in English, but we'd like it to be internationalized. Enter then the `th:attr` attribute, and its ability to change the value of attributes of the tags it is set in: ```html ``` The concept is quite straightforward: `th:attr` simply takes an expression that assigns a value to an attribute. Having created the corresponding controller and messages files, the result of processing this file will be: ```html ``` Besides the new attribute values, you can also see that the application context name has been automatically prefixed to the URL base in `/gtvg/subscribe`, as explained in the previous chapter. But what if we wanted to set more than one attribute at a time? XML rules do not allow you to set an attribute twice in a tag, so `th:attr` will take a comma-separated list of assignments, like: ```html
```
Given the required messages files, this will output:
```html
```
5.2 Setting value to specific attributes
----------------------------------------
By now, you might be thinking that something like:
```html
```
...is quite an ugly piece of markup. Specifying an assignment inside an
attribute's value can be very practical, but it is not the most elegant way of
creating templates if you have to do it all the time.
Thymeleaf agrees with you, and that's why `th:attr` is scarcely used in
templates. Normally, you will be using other `th:*` attributes whose task is
setting specific tag attributes (and not just any attribute like `th:attr`).
For example, to set the `value` attribute, use `th:value`:
```html
```
This looks much better! Let's try and do the same to the `action` attribute in
the `form` tag:
```html