y0ngb1n

Aben Blog

欢迎来到我的技术小黑屋ヾ(◍°∇°◍)ノ゙
github

Spring Boot 2.0 Integration with Thymeleaf Module Engine

Thymeleaf is a Java XML / XHTML / HTML5 template engine that can be used in both web and non-web environments. It is more suitable for providing XHTML / HTML5 in the view layer of MVC-based web applications, but it can also handle any XML file even in offline environments. It provides full integration with the Spring Framework.

Development Environment#

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.0.RELEASE</version>
</parent>

<properties>
  <java.version>1.8</java.version>
</properties>

Introduce Dependencies#

Mainly add the spring-boot-starter-thymeleaf dependency:

  • spring-boot-starter-thymeleaf: Automatically configures the Thymeleaf template engine
<dependencies>
  ...

  <!-- Thymeleaf Start -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>
  <!-- Thymeleaf End -->
  
  ...
</dependencies>

Configure Thymeleaf#

application.yml

spring:
  thymeleaf:
    cache: false                  # Whether to enable template caching, default is: true, turn off caching during development, otherwise you won't see real-time pages!
    mode: HTML                    # Specify the mode of the template, default is: HTML
    encoding: UTF-8               # Specify the encoding of the template, default is: UTF-8
    prefix: classpath:/templates/ # Specify the prefix of the template, default is: classpath:/templates/
    suffix: .html                 # Specify the suffix of the template, default is: .html
    servlet:
      content-type: text/html     # Specify Content-Type value, default is: text/html

From org.thymeleaf.templatemode.TemplateMode, it can be seen that Thymeleaf started using HTML instead of HTML5, LEGACYHTML5, XHTML, VALIDXHTML from version 3.0.0. If you are still using a version prior to 3.0.0 and want to use non-strict HTML, you need to do the following configuration:

  • Introduce the nekohtml dependency in pom.xml
  • Configure spring.thymeleaf.mode=LEGACYHTML5 in application.yml

For more property configurations, please refer to the property introduction of the # THYMELEAF (ThymeleafAutoConfiguration) module in "Appendix A. Common application properties." (TIPS: Use CTRL + F for quick navigation)

Create Test Controller#

Create a Controller to assign a value to the message attribute and set the redirection, the code is as follows:

IndexController.java

@Controller
public class IndexController {

  @GetMapping(path = {"/", "index"})
  public String indexPage(Model model) {
    model.addAttribute("message", "Hello Thymeleaf!");
    return "index";
  }
}

Create Test HTML Page#

Create an index.html file in the templates directory and declare the Thymeleaf namespace xmlns:th="http://www.thymeleaf.org" in the html tag, the code is as follows:

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8"/>
    <title>Thymeleaf</title>
  </head>
  <body>
    <h1 th:text="${message}">Hello World!</h1>
  </body>
</html>

The key code is:

xmlns="http://www.thymeleaf.org"

This mainly allows the IDE to recognize the Thymeleaf namespace, so when you enter th: in the tag, the IDE will prompt the corresponding syntax, facilitating development! Not adding this line of code will not affect the rendering of the Thymeleaf template engine or the normal display of the page.

Test Access#

After a successful startup, visit http://127.0.0.1:8080 to see the effect:

Hello Thymeleaf

Access result: Hello Thymeleaf!


Common Thymeleaf Syntax#

Get Variable Value#

<p th:text="'Hello! ' + ${name} + '!'" >name</p>

It can be seen that to get the variable value, the $ symbol is used, and for JavaBeans, the variable name and property name are used to access it, which is the same as the EL expression.

Additionally, the $ expression can only be written inside th tags; otherwise, it will not take effect. The above example uses the value of the th:text tag to replace the value inside the <p>...</p> tag, while the original value inside p is just for display during front-end development. This achieves a good separation of front and back ends.

Content Information Output: th:text and th:utext#

  • th:text: Outputs in plain text
  • th:utext: Outputs in HTML tag format, which the browser can render normally

th and th

HTML code:

<body>
  <h2 th:text="' th:text &nbsp » ' + ${content}">Output in plain text</h2>
  <h2 th:utext="'th:utext      » ' + ${content}">Output in HTML tag format, which the browser can render normally</h2>
</body>

JAVA code:

@GetMapping("/text-utext")
public String textAndutext(Model model) {
  model.addAttribute("content", "<span style='color:red'>thymeleaf text output</span>");
  return "text-utext";
}

Referencing URLs#

URL handling is done using the syntax @{…}:

Referencing URLs

HTML code:

<body>
  <ul>
    <li>
      <a th:href="@{https://github.com/{username}(username=${username})}">Absolute Path 1</a>,
      <a th:href="@{https://www.baidu.com}">Absolute Path 2</a>
    </li>
    <li>
      <a th:href="@{/}">Relative Path</a>
    </li>
    <li>
      <a th:href="@{/css/app.css}">Content Path, default accesses CSS files under static</a>
    </li>
  </ul>
</body>

JAVA code:

@GetMapping("/refer-url")
public String referUrl(Model model) {
  model.addAttribute("username", "y0ngb1n");
  return "refer-url";
}

Similar tags include: th:href and th:src

String Replacement#

Often, we may only need to replace a certain part of a large piece of text, which can be done through string concatenation:

<p th:text="'Welcome to our application, ' + ${user.name} + '!'">

This can be done in a more concise way:

<p th:text="|Welcome to our application, ${user.name}!|">

String replacement can also be combined with other expressions:

<p th:text="${onevar} + ', ' + |${twovar}, ${threevar}|">

Of course, this form has more limitations; |…| can only contain variable expressions ${…}, and cannot include other constants, conditional expressions, etc.

String Replacement

HTML code:

<body>
  <p th:text="'Welcome to our application, ' + ${user.name} + '!'">
  <p th:text="|Welcome to our application, ${user.name}!|">
  <p th:text="${onevar} + ', ' + |${twovar}, ${threevar}|">
</body>

JAVA code:

@GetMapping("replace-text")
public String replaceText(Model model) {
  model.addAttribute("user", user);
  model.addAttribute("onevar", "one");
  model.addAttribute("twovar", "two");
  model.addAttribute("threevar", "three");
  return "replace-text";
}

Operators#

Various arithmetic operators can be used in expressions, such as +, -, *, /, %:

th:with="isEven=(${user.age} % 2 == 0)"

Logical operators >, <, <=, >=, ==, != can also be used. The only thing to note is that when using <, >, you need to use their HTML escape characters:

th:if="${user.age} &gt; 1"
th:text="'Environment is ' + ((${env} == 'dev') ? 'Development' : 'Production')"

Operators

HTML code:

<body>
  <h2 th:text="|name: ${user.name}, age: ${user.age}, env: ${env}|"></h2>

  <p th:with="isEven=(${user.age} % 2 == 0)">Age is even</p>
  <p th:with="isEven=(${user.age == 18})">Wow, only 18!</p>

  <p th:if="${user.age}  &gt; 18">Current age is greater than 18</p>

  <div th:class="${env} == 'dev' ? 'dev' : 'prod'"></div>

  <p th:text="'Current environment: ' + ((${env} == 'dev') ? 'Development' : 'Production')"></p>
</body>

JAVA code:

@GetMapping("/operator")
public String operator(Model model) {
  model.addAttribute("user", user);
  model.addAttribute("env", "dev");
  return "operator";
}

Conditional Judgments#

th:if, th:unless#

Use th:if and th:unless attributes for conditional judgments. In the example below, the tag will only be displayed if the condition in th:if is met:

<a th:href="@{/login}" th:if=${user == null}>Login</a>
<a th:href="@{/login}" th:unless=${user != null}>Login</a>

th:unless is exactly the opposite of th:if; it will only display its content if the condition in the expression is not met.

th:switch, th:case#

Supports multi-way switch structures:

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
</div>

The default attribute can be represented by *:

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p>
</div>

Message expression: #{...}, also known as text externalization, internationalization, or i18n

Conditional Judgments

HTML code:

<body>
  <a th:href="@{/login}" th:unless="${user == null}">Login</a>
  <p th:if="${user != null}">Welcome, <span th:text="|${user.name}(role: ${user.role})|">tony</span></p>

  <div th:switch="${user.role}">
    <p th:case="'admin'">User is an administrator</p>
    <p th:case="#{roles.manager}">User is a manager</p>
    <p th:case="*">User is some other thing</p>
  </div>
</body>

JAVA code:

@GetMapping("/condition")
public String condition(Model model) {
  model.addAttribute("user", user);
  return "condition";
}

Looping#

Rendering list data is a very common scenario. For example, if there are n records that need to be rendered into a table, the data collection must be iterable, using the th:each tag:

HTML code:

<body>
  <table>
    <tr>
      <th>NAME</th>
      <th>AGE</th>
      <th>ADMIN</th>
    </tr>
    <tr th:each="user : ${users}">
      <td th:text="${user.name}">Onions</td>
      <td th:text="${user.age}">22</td>
      <td th:text="${user.role} == 'admin' ? #{true} : #{false}">yes</td>
    </tr>
  </table>
</body>

As you can see, the th:each tag needs to be added to the element being looped over (here it is the <tr>), where th:each="prod : ${prods}" means iterating over the collection variable prods, and the loop variable is prod, which can be accessed in the loop body through expressions.

JAVA code:

@GetMapping("/loop")
public String loop(Model model) {
  List<User> users = new ArrayList<>(3);
  users.add(user);
  users.add(User.builder().name("tony").age(23).role("user").build());
  users.add(User.builder().name("tom").age(21).role("user").build());

  model.addAttribute("users", users);
  return "loop";
}

Looping

For more tag usage, please refer to "Common Thymeleaf Syntax" and "Thymeleaf Reference Manual" to unlock more tips 😜


References#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.