7.2 Standard Expression Syntax

In this section, we focus on Standard Expression Syntax, including:

  • Expressions on selections (asterisk syntax)
  • Link URLs
  • Fragments

Expressions on selections

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.

<div th:object="${user}">
    <p>Age: <span th:text="*{age}">18</span></p>
    <p>Name: <span th:text="*{name}">Bob</span></p>
</div>

Which is exactly equivalent to:

<div>
    <p>Age: <span th:text="${user.age}">18</span></p>
    <p>Name: <span th:text="${user.name}">Bob</span></p>
</div>

By the way, dollar and asterisk syntax can be mixed.

We did not cover how to represent link URLs in JSPs using JSTL in Section 5, although link URLs are very important for websites. For example, every book at Douban can be accessed by a URL, and this is the link for HFBook: https://book.douban.com/subject/3223139/. Here 3223139 is the ID of HFBook.

There are two types of URLs:

  • Absolute URLs: https://book.douban.com/subject/3223139/
  • Relative URLs, which can be:
    • Page relative: user/login.html
    • Context-relative: /book?id=3 (context name in server will be added automatically)
    • Server-relative: ~/billing/pay
    • Protocol-relative URLs: //code.jquery.com/jquery-2.0.3.min.js

Thymeleaf provides a special for URL, the @ syntax: @{...}. Generally, it may be error-prone to distinguish page relative and context-relative, so we illustrate the difference using an example in the following.

Suppose we are now in the page http://localhost:8080/thymeleaf/, and BookServlet accepts a parameter id and then makes a response of a book:

@WebServlet(name = "BookServlet", value = "/books")
public class BookServlet extends HttpServlet {

And we look at how URLs are used in <a>'s href attribute.

It is a page relative URL, and it would produce books?id=3. By the way, Theymeleaf also provides an elegant way to URL rewriting if cookies are not enabled:

<a th:href="@{books(id=3)}" href="#">@{books(id=3)}</a>

So we always prefer (...) over ? syntax for GET parameters.

It is a context relative URL, and it would produce /thymeleaf/books?id=3. And we can also put variables into it:

<a th:href="@{books(id=${bookID})}" href="#">@{books(id=${bookID})}</a>

But suppose we are now in http://localhost:8080/thymeleaf/test/123. The page relative URL will finally become

http://localhost:8080/thymeleaf/test/books?id=3

And it is incorrect. However, the context relative URL will work well.

Fragments

It is common that web pages share some components (e.g., header, footer and menu), and we also have learned that include directive in JSP is used to include one file at translation time. Similarly, th:insert and th:replace can be used in this scenario[1].

We create a footer.html under webapp | WEB-INF | templates:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
    &copy; 2022 SWUFE
</div>
</body>
</html>

And in book.html, we can include this file using ~{templatename::selector}:

<div th:insert="~{footer.html :: copy}"></div>

[1] th:insert is the simplest: it will simply insert the specified fragment as the body of its host tag; th:replace actually replaces its host tag with the specified fragment.