Overview of This Lesson

Refresh this page because I am probably still making changes to it.

In the previous lesson you learned how to make data accessible in the response by using Model attributes. This allows you to dynamically add data to the response so that it's sent back to the client. For example, you can configure an HTML page to show a collection of book data retrieved on the server, and that book data is embedded in the HTML page and sent back to the client in the response.

Recall that Thymeleaf is a template engine. We can create an HTML page and include Thmeleaf code to format how dynamic data appears and even include expressions and calculations. This is exactly what the /templates directory of your /resources directory is for!

Thymeleaf is coded by adding special thymeleaf expressions inside Thymeleaf attributes (such as th:text) added to HTML elements. All Thymeleaf attributes are prefixed with th:, so they're part of the Thymeleaf namespace. That way, they won't get confused with the existing HTML attributes.

Let's begin by learning the syntax of Thymeleaf expressions and the different attributes you can use (tip: you already know all the attributes!)

Pre-Requisites

For this lesson, it's important that you've already learned how to use Model Attributes from the Introduction to Thymeleaf lesson.

Helpful Resources

Basic Variable Expressions and Operators

The ${ } part of the expression you learned in the previous lesson is a variable expression. Inside the curly braces you can put any object variable or object property, a model attribute, an implicit object, etc.

Variable expressions can contain operators. For example, all the basic mathematical operations are supported:

Arithmetic Operators
Sample ExpressionResultComments
${12.5 + 4}16.5 
${1.25E3 + 4}12541.25E3 is exponential notation for 1250
${15 % 6}3 
${2 + 3 * 4}14 
${(2 + 3) * 4}20 
${15 > 100}false 

Some variable expressions can also evaluate to a boolean value, so the standard relational operations are supported. Note however, that you can't place a < or > symbol inside an HTML attribute value, so you'll have to use character entities such as &lt; and &gt; or use the alternative operators lt and gt (more of these are outlined further down).

Boolean Expressions
Sample ExpressionResultComments
${"foo" == "foo"}truecompares string value
${"foo" == "bar"}falsecompares string value
${"foo" != "foo"}false 
${fabric == "FAUX_FUR"}  When comparing enum constants, treat them as a String literal. In this example, "FAUX_FUR" will automatically be converted to a Fabric enum value before being compared, it's just like typing fabric == Fabric.FAUX_FUR in Java.
${"foo" == "foo" && 15 > 100}falsenote you can't use > or < symbols in an expression so you have to character entities or one of the alternate text operators (see table below)
${"foo" == "foo" && 15 <= 100}truenote you can't use > or < symbols in an expression so you have to character entities or one of the alternate text operators (see table below)
${!(15 gt 100)}truenote you can't use > or < symbols in an expression so you have to character entities or one of the alternate text operators (see table below)

String operations are also supported.

Concatenation is done with the + operator.

You can perform literal substitution using the | (pipe, vertical line) symbol. For example:

<span th:style="|background-color:${cat.colorCode}|">blue siamese</span>

can also be written as

<span th:style="'background-color:'+ ${cat.colorCode}">blue siamese</span>

Alternatives to Standard Operators

Most of the operators discussed above have alternative symbolism that uses letters. As mentioned earlier, you can't use certain operators such as < and > inside an HTML attribute, so many developers use the alternatives, isntead. The table below outlines the different operators and their symbols and alternatives:

Expression Operators
Arithmetic Operators
OperatorAlternativeExample
+   ${12.5 + 4}
-   ${12.5 - 4}
*   ${12.5 * 4}
/ div ${12.5 / 4}
${12.5 div 4}
% mod ${15 % 6}
${15 mod 6}
Relational Operators
OperatorAlternativeExample
== eq ${"foo" == "foo"}
${"foo" eq "foo"}
!= ne ${"foo" == "foo"}
${"foo" ne "foo"}
< lt ${x < y}
${x lt y}
> gt ${x > y}
${x gt y}
<= le ${x <= y}
${x le y}
>= ge ${x >= y}
${x ge y}
Logical Operators
OperatorAlternativeExample
&& and ${customer.active && customer.balance > 100}
${customer.active and customer.balance > 100}
|| or ${customer.active || customer.balance <= 100}
${customer.active or customer.balance <= 100}
! not ${!customer.active}
${not customer.active}

Unescaped Text

Normally when you use th:text, any special HTML characters are escaped. So if you had a model attribute called "output" with the content "<span class='foo'>Foo!</span>" and you then wrote the Thymeleaf code:

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

The value assigned to th:text would be parsed and sent back in the response body as

<p>&lt;span class='foo'&gt;Foo!&lt;/span&gt;</p>

So that would actually render on the page as a paragraph element containing the content

<span class='foo'>Foo!</span>

Try it in your own program and you'll see what I mean!

If you want to display text that has any HTML code in it, and you want that code to be treated like actual HTML code (where the special characters aren't escaped and the HTML code is actually rendered as pure HTML) you should use th:utext instead. The th:utext attribute will not escape any special HTML characters such as <, >, &, etc.

Give it a try, add a model attribute in your handler method with some HTML, such as:

model.addAttribute("test", "How does <strong>this</strong> display?");

Display the attribute on your output page using a paragraph or div with th:text and a different paragraph/div using th:utext.

Check the source after you reload your page.

Exercise

Try out some basic Thymeleaf expressions: start a new project (add dependencies for Spring Web, Dev Tools, Thymeleaf, and Lombok) and add a controller and an HTML page index.html in the /templates directory. Make sure you add the Thymeleaf namespace to the <html> element of your page. Add your Book bean to your project's .beans package.

In a handler for the index page, add some model attributes:

Model AttributeValue
firstNameyour first name
lastNameyour last name
numberyour favourite number, any number
booka book object that you will have to instantiate

Add these template objects with Thymeleaf expressions to your page (don't forget to include fallback text):

  • Add a level-1 heading containing your first name and last name.
  • Add a paragraph or div element that displays true if your number is even and false if your number is odd.
  • A paragraph or div element with the book object's title, followed by " by ", followed by the book's author.
  • A paragraph or div element with the result of your number times the price of the book.

You might find there are several ways to do the same thing. For example, all of these produce the exact same output:

<p>Example 1</p>
<p th:text="${attrib1} + ' ' + ${attrib2} + ' ' 
    + ${attrib3}">example 1</p>
<p>Example 2</p>
<p th:text="|${attrib1} ${attrib2} ${attrib3}|">example 2</p>
<p>Example 3</p>
<p><span th:text="${attrib1}">a1</span> 
  <span th:text="${attrib2}">a2</span>
  <span th:text="${attrib3}">a3</span></p>

Is one of these solutions better than another? It depends on what you want to do with the rest of your page. If you wanted to style the individual attribte values, Solution 3 would be better because you can easily create different CSS classes for each SPAN nested inside the P element. If you wanted to use fewer elements (to make the DOM more efficient), you might prefer Solution 1 or 2.

Referencing CSS and Images

When referencing external resources, you have to use a URL expression instead of a variable expression. A URL expression uses @{ }. Inside the curly braces, you put the location of the resource. If the resource is a file, make sure it starts with the forward-slash / if you're referencing it from the context path.

Recall that all web resources such as images, scripts, and CSS files are stored in the /static directory. Always reference the /static directory in a URL expression with a forward slash, followed by the file or sub-directory that resides inside /static. For example, assuming you have an image file "picture.jpg" inside /static/images, your URL expression would be

@{/images/picture.jpg}

Therefore, adding such an image to an HTML page using Thymeleaf would be something like:

<img src="../static/images/mypicture.jpg" alt="accessible description here"
th:src="@{/images/mypicture.jpg}">

Note that we should still include the static image src attribute as a fallback!

You can do something similar with an external CSS file: assuming you follow the industry standard and have a /css or /styles directory in your /static directory, you can link to a CSS file from any static page normally. From a /templates page, you would use a link tag such as:

<link rel="stylesheet" type="text/css" media="all"
href="../static/css/main.css" th:href="@{/css/main.css}">
            

Once again, notice that you should include the regular href attribute as fallback code.

Thymeleaf Attributes

What else can you do with Thymeleaf? To be honest, there is just SO MUCH you can do that we are unable to cover it all in this course, so make sure you take some time later to go over the Thymeleaf tutorial, and make note of the Thymeleaf documentation in case you ever want to search for how to do something specific.

Attribute Modifiers

Attribute modifiers are Thymeleaf versions of existing HTML attributes. Most of the HTML5 attributes have a Thymeleaf version, such as th:class, th:name, th:id, th:action, th:alt, th:for, th:href, th:pattern, th:placeholder, th:src, th:style, th:target, th:title, and th:value. There are several others: obviously listing them all here is not practical.

All of these types of attributes can be used with Thymeleaf expressions. For example:

<input type="text" name="itemname"
  value="Item Name" th:value="${inv.itemName}">

In this example, an input element is using th:value to assign a dynamic value to the input field, which in this case is whatever is inside inv.itemName.

Notice we are also including value="Item Name" as a fallback: if for some reason Thymeleaf isn't working, the input field's value will be "Item Name".

Exercise

Start a new project and add the dependencies for Spring Boot, Dev Tools, Thymeleaf, and Lombok. Add your book bean and a controller to the project, along with an index HTML page.

On your index page, create a form that allows a user to enter book information.

In the controller, add a handler method that loads the index page. Instantiate a Book object and add it to the Model as an attribute.

Now go back to your form and add the th:value attribute to each input field so that the fields contain the existing book object's data when the index page loads.