Thymeleaf Tutorial: Chapter 4. Standard Expression Syntax
- Tutorial
4 Standard Expression Syntax
We will take a short break in the development of our virtual grocery store to learn about one of the most important parts of the Thymeleaf Standard Dialect: The Thymeleaf Expression Syntax Standard .
We have already seen two types of valid attribute values expressed in this syntax: messages and variables:
Welcome to our grocery store!
Today is: 13 february 2011
But there are much more expressions. First, let's take a quick look at Standard Expression:
- Simple expressions:
- Variable : $ {...}
- Selected Variable : * {...}
- Message : # {...}
- Link URL : @ {...}
- Snippet : ~ {...}
- Literals:
- Text : 'one text', 'Another one!', ...
- Number : 0, 34, 3.0, 12.3, ...
- Boolean : true, false
- Null : null
- Tokens : one, sometext, main, ...
- Text:
- Line Join : +
- Substrings : | The name is $ {name} |
- Arithmetic:
- Binary : +, -, *, /,%
- Minus (unary operator) : -
- Boolean:
- Binary : and, or
- Boolean negation (unary operator) :!, Not
- Comparison and equality:
- Comparison :>, <,> =, <= (gt, lt, ge, le)
- Equality : ==,! = (Eq, ne)
- Conditional:
- If-then : (if)? (then)
- If-then-else : (if)? (then): (else)
- Default : (value)?: (Defaultvalue)
- Special Tokens:
- No-Operation : _
Expressions can be combined and nested :
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))4.1 Messages
As we know, the message expression # {...} allows us to bind:
Welcome to our grocery store!
… from:
home.welcome=¡Bienvenido a nuestra tienda de comestibles!But there is one aspect that we have not thought about yet: what happens if the message text is not completely static? What if, for example, our application knows which user is visiting the site, and we would like to greet the user by name?
¡Bienvenido a nuestra tienda de comestibles, John Apricot!
This means that we need to add a parameter to our message. Like this:
home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!The parameter is defined relative to the standard syntax java.text.MessageFormat, which means that you can format numbers and dates.
To specify the value for our parameter from the HTTP session attribute called by the user, we will write:
Welcome to our grocery store, Sebastian Pepper!
Several parameters can be defined by separating them with commas. Also, the message keys themselves can come from a variable:
Welcome to our grocery store, Sebastian Pepper!
4.2 Variables
We already mentioned that the $ {...} expressions are actually OGNL (Object-Graph Navigation Language) expressions executed on map variables contained in the context.
For more information about the syntax and functions of OGNL, you should read the OGNL Language Guide.
In Spring MVC-enabled applications, OGNL will be replaced by SpringEL, but its syntax is very similar to the OGNL syntax (in fact, exactly the same for most common cases).
From the OGNL syntax, we know that the expression:
Today is: 13 february 2011.
is equivalent to:
ctx.getVariable("today");But OGNL allows you to create more powerful expressions like this:
Welcome to our grocery store, Sebastian Pepper!
... get the username:
((User) ctx.getVariable("session").get("user")).getName();But getter is just one of the features of OGNL. Let's see more:
/*
* Доступ к свойствам с использованием точки (.). Эквивалент вызывающим getter свойств.
*/
${person.father.name}
/*
* Доступ к свойству может быть так же через скобки ([]) и написание
* имени свойства как переменной или между простыми кавычками.
*/
${person['father']['name']}
/*
* Если объект является map, оба синтаксиса точки и скобки будет эквивалентен
* выполнению метода get(...).
*/
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}
/*
* Доступ к массиву или коллекции так же выполняется через скобки,
* с написанием индекса без скобок.
*/
${personsArray[0].name}
/*
* Могут быть вызваны методы даже с аргументами.
*/
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}Expression Basic Objects
When you run an OGNL expression with context variables, some objects become available for more flexibility. These objects can be referenced (according to the OGNL standard), starting with the symbol # :
#ctx : context.
#vars : context variables.
#locale : context locale.
#request : (only in Web Contexts) an HttpServletRequest object.
#response : (only in Web Contexts) an HttpServletResponse object.
#session : (only in Web Contexts) an HttpSession object.
#servletContext : (only in Web Contexts) ServletContext object.
We can also do the following:
USYou can read the full references to these objects in Appendix A .
Expression Utilities
In addition to these core objects, Thymeleaf offers us a set of useful objects to help us perform common tasks in our expressions.
#execInfo : information about the current template.
#messages : methods for receiving messages inside expressions, just as they will be received using the syntax # {...}.
#uris : methods for escaping parts of a URL / URI.
#conversions : methods for making conversion service settings (if present).
#dates : methods for java.util.Date objects: formatting, extracting components, etc.
#calendars: similar to #dates, but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String object: contains, startsWith, prepending / appending, etc.
#objects : common methods for objects.
#bools : methods for boolean conversions.
#arrays : methods for arrays.
#lists : methods for List.
#sets : methods for Sets.
#maps : methods for Maps.
#aggregates : methods for aggregating masses or collections.
#ids : methods for processing id identifiers that can be repeated (for example, as a result of an iteration).
You can check which functions are available for each of these objects in the Annex Bed and .
Reformatting the date on the Home page
Now we know about these object utilities and can use them to change the way the date is displayed on our home page. Instead, in our HomeController:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
Calendar cal = Calendar.getInstance();
WebContext ctx = new WebContext(request, servletContext, request.getLocale());
ctx.setVariable("today", dateFormat.format(cal.getTime()));
templateEngine.process("home", ctx, response.getWriter());... we can do the following:
WebContext ctx =
new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("today", Calendar.getInstance());
templateEngine.process("home", ctx, response.getWriter());... and then format the date in the view layer itself:
Today is: 13 May 2011
4.3 Selection expressions / selections (asterisk syntax)
Expressions with variables can be written not only through $ {...} , but also as * {...} .
There is a difference between the options: the syntax with an asterisk converts the expression over the selected object rather than over the entire context. This means that if there is no selected object, the dollar and the asterisk do the same thing.
What is a selected item? The result of an expression using the " th: object " attribute . We use it on the profile page (userprofile.html):
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Which is equivalent:
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
Of course, the dollar and the asterisk can mix:
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
When the selected object is in place, the selected object will be as accessible with the dollar as the #object variable:
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
As said, if there is no selected object, the dollar and asterisk are equivalent.
Name: Sebastian.
Surname: Pepper.
Nationality: Saturn.
4.4 Link URL
Because of their importance, URLs are first-class citizens in web application templates, and the Thymeleaf Standard Dialect has a special “@” syntax for them: @ {...}
There are different types of URLs:
- Absolute URLs: www.thymeleaf.org
- Relative URLs:
- Relative on the page: user / login.html
- Relative context: / itemdetails? Id = 3 (the context name will be added on the server)
- Relative servers: ~ / billing / processInvoice (allow calling URLs in a different context (= application) on the same server.
- Relative protocol: //code.jquery.com/jquery-2.0.3.min.js
The actual processing of these expressions and their conversion to the URLs that will be displayed are performed using the implementation of the org.thymeleaf.linkbuilder.ILinkBuilder interface, which are registered in the ITemplateEngine object used.
By default, one implementation of this interface is represented by the org.thymeleaf.linkbuilder.StandardLinkBuilder class, which is sufficient for both stand-alone (non-web sites) and web-based scripts based on the Servlet API. Other scenarios (for example, integration with non-ServletAPI web frameworks) may require specific implementations of the link builder interface.
Let's use the new syntax. Meet the attribute " th: href ":
viewviewviewA few notes:
- " th: href " is a modifying attribute: once executed, it will calculate the URL link and set the value of the "href" attribute of the tag .
- We are allowed to use expressions for URL parameters (as you can see in orderId = $ {o.id}. The required operations of encoding URL parameters will also be automatically performed.
- If multiple parameters are required, they will be separated by commas: @ {/ order / process (execId = $ {execId}, execType = 'FAST')}
- Variable templates are also allowed in the URLs: @ {/ order / {orderId} / details (orderId = $ {orderId})}
- Relative URLs starting with / (for example: / order / details) will be automatically prefixed with the name of the application context.
- If cookies are not enabled or it is not yet known, the suffix "; jsessionid = ..." can be added to relative URLs so that session is saved. This is called URL Rewriting and Thymeleaf allows you to connect your own rewrite filters using the response.encodeURL (...) mechanism from the servlet API for each URL.
- The th: href attribute allows us (optionally) to have a valid href static attribute in our template so that our template links remain navigation for the browser when opened directly for prototyping purposes.
- The th: href attribute allows us (optionally) to have a valid href static attribute in our template so that our template links remain navigation for the browser when opened directly for prototyping purposes.
As with message syntax (# {...}), URLs can also result from another expression:
viewview
Menus for our homepage
Now we know how to create URLs, what about adding a small navigation menu to our homepage?
Please select an option
- Product List
- Order List
- Subscribe to our Newsletter
- See User Profile
Links URLs relative to the server root directory
Additional syntax can be used to create URLs based on the root directory (instead of context-sensitive) URLs to refer to different contexts on the same server. These URLs will be listed as @ {~ / path / to / something}
4.5 Fragments
Fragment expressions are an easy way to represent fragments of markup and move them between patterns. This allows us to copy, pass them to other templates as arguments and so on.
The most common use is to insert a fragment using th: insert or th: replace (more on this in the next section):
But they can be used everywhere, like any other variable:
Later in this tutorial, there is a whole section on Template Layout , including a deeper explanation of fragment expressions.
4.6 Literals
Text literals
Text literals are just character strings specified between single quotes. They can include any character, but you should avoid any single quotes inside them using \ ' .
Now you are looking at a template file.
Numeric Literals
Numeric literals are just numbers.
The year is 1492.
In two years, it will be 1494.
Boolean literals Boolean literals
are true and false. For example:
...
In this example, "== false" is written outside the brackets, then Thymeleaf takes care of the expression. If the equality was contained inside the brackets, the OGNL / SpringEL engine would take care of it:
...
Literal null The
literal null can also be used:
...
Literal Tokens
Numeric, Boolean, and null literals are a special case of literal tokens.
These tokens simplify Standard Expressions a bit. They work exactly like text literals ('...'), but only allow letters (AZ and az), numbers (0-9), brackets ([and]), periods (.), Hyphens (-) and underscores (_). No spaces, no commas, etc.
The good part? Tokens do not need quotes surrounding them . Therefore, we can do:
...instead:
...4.7 Appending texts
Texts, whether they are literals or the result of processing variables or messages, can be easily added using the + operator :
4.8 Replacement Literals
Literal replacements make it easy to format strings containing values from variables, without the need to add literals using '...' + '...'.
These replacements must be surrounded by vertical bars (|) , for example:
Which is equivalent:
Literal substitutions can be combined with other types of expressions:
Only variable / message expressions ($ {...}, * {...}, # {...}) are allowed inside | ... | literal replacements. No other literals ('...'), boolean / numeric tokens, conditional expressions, etc.
4.9 Arithmetic operations
Some arithmetic operations are also available: +, -, *, /,% .
Note that these operators can also be applied directly to the OGNL expressions themselves (in which case OGNL will be executed instead of the Thymeleaf Standard Expression mechanism):
Please note that for some of these operators text aliases exist: div (/), mod (%).
4.10 Comparisons and Equality
The values in the expressions can be compared with the symbols >, <,> = and <=, ==,! = Operators are used to check for equality (or its absence). Note that XML sets <and> characters should not be used in attribute values, and therefore they must be replaced with <and>.
A simpler alternative may be to use the text aliases that exist for some of these operators: gt (>), lt (<), ge (> =), le (<=), not (!). Also eq (==), neq / ne (! =).
4.11 Conditional expressions
Conditional expressions are designed to perform only one of two expressions, depending on the result of evaluating the condition (which is itself another expression).
Let's look at an example fragment (introducing another attribute modifier, th: class ):
...
All three parts of the conditional expression (condition, then and else) are themselves expressions, which means that they can be variables ( $ {...} , * {...} ), messages ( # {...} ), URLs ( @ {...} ) or literals ( '...' ).
Conditional expressions can also be nested with parentheses:
...
Other expressions may also be omitted, in which case a null value is returned if the condition is false:
...
4.12 Default / Default expression (Elvis statement)
The default expression is a special kind of conditional value without any part. This is equivalent to the Elvis operator, which is present in some languages, for example, Groovy, which allows you to specify two expressions: the first is used if it is not null, but if it is, then the second is used.
Let's see how it works on our profile page:
...
Age: 27.
As you can see, the operator is?:, And we use it here to specify the default value for the name (literal value in this case) only if the result of the calculation * * age is null. Therefore, this is equivalent to:
Age: 27.
Like conditional values, they can contain nested expressions between parentheses:
Name:
Sebastian
4.13 No-Operation Token
The No-Operation token is represented by the symbol (_) .
The idea of this token is to indicate that the desired result for the expression is to do nothing: do exactly as if the processed attribute (for example, th: text) was completely absent.
Among other features, this allows developers to use prototype text as default values. For example, instead of:
...... we can directly use 'no user authenticated' as the prototyping text, which leads to the fact that the code is more concise and universal in terms of design:
no user authenticated4.15 Data Conversion / Formatting
Thymeleaf defines the double-bracket syntax for variables ( $ {...} ) and allocated ( * {...} ) expressions, which allows us to apply data transformation using the configuration of the transformation service.
Basically it looks like this:
...Did you notice the double bracket ?: $ {{...}} . This instructs Thymeleaf to pass the result of the user.lastAccessDate expression to the conversion service and prompts you to perform a formatting operation (conversion to String) before returning the result.
Assuming user.lastAccessDate is of type java.util.Calendar, if a conversion service (implementation of IStandardConversionService) has been registered and contains a valid conversion for Calendar -> String, it will apply.
By default, the implementation of IStandardConversionService (class StandardConversionService) simply executes .toString () for any object. For more information about how to register a custom implementation of a transformation service, see the "More Configuration Information" section.
The official integration packages thymeleaf-spring3 and thymeleaf-spring4 transparently integrate the Thymeleaf conversion service engine with the native Conversion Service Spring infrastructure, so that the conversion services and formats declared in the Spring configuration will be automatically available for $ {{...}} and * {{...}}.
4.14 Preprocessing
In addition to all these functions for processing expressions, Thymeleaf has a preprocessor expression function.
Pre-processing is the execution of expressions made before the execution of standard expressions, which allows you to modify the expression that will ultimately be executed.
Pre-processed expressions are exactly the same as normal ones, but appear surrounded by a double underscore (for example, __ $ {expression} __).
Suppose we have an i18n Messages_fr.properties record containing an OGNL expression that calls a static method specific to a language, for example:
[email protected]@translateToFrench({0})... and the equivalent of Messages_es.properties:
[email protected]@translateToSpanish({0})We can create a markup fragment that executes one expression or the other depending on the locale. To do this, we first select the expression (by preprocessing) and then run Thymeleaf:
Some text here...
Note that the pre-processing step for the French language will create the following equivalent:
Some text here...
The preprocessor string __ can be escaped in attributes using \ _ \ _ .