2024.4.28 Sunday
Contents
- 8. Thymeleaf Template Engine
- 8.1. Template Engine
- 8.2. Integrating Thymeleaf
- 8.2.1. How to Integrate
- 8.2.2. Thymeleaf Official Website
- 8.2.3. Thymeleaf on Github
- 8.2.4. Official Spring Documentation: Find the relevant version
- 8.2.5. Find the corresponding pom dependency: Feel free to delve into the original package’s source code!
- 8.2.6. Remove index.html
- 8.2.7. Search (double-click shift) to enter ThymeleafProperties.java
- 8.2.8. Create IndexController.java
- 8.2.9. Create test.html
- 8.2.10. Restart and Run
- 8.3. Learning Thymeleaf Syntax
8. Thymeleaf Template Engine
8.1. Template Engine
The front end hands us HTML pages. In previous developments, we needed to convert them to JSP pages. The advantage of JSP is that once we fetch some data and forward it to a JSP page, we can easily display the data and handle interactions.
JSP supports very powerful features, including the ability to write Java code. However, in our current scenario with SpringBoot, the project is initially in a JAR format, not WAR. Secondly, we use an embedded Tomcat, so JSP is not supported by default.
If JSP is not supported and we use purely static pages, it would cause significant development challenges. So, what should we do?
SpringBoot recommends using a template engine:
Template engines are widely known; in fact, JSP is a template engine. Other popular ones include Freemarker and Thymeleaf, recommended by SpringBoot. There are many template engines, but the core idea behind them is the same. Let’s take a look at this diagram:
The role of a template engine is to write a page template with some expressions for dynamic values. These values are encapsulated in the backend. The template and data are then processed by the template engine, which parses and fills in the expressions at the designated spots, ultimately generating the content we need. This concept is common to all template engines, whether JSP or others, though their syntax may vary. I won’t go into others but will focus on introducing Thymeleaf, a high-level language template engine recommended by SpringBoot. Its syntax is simpler and its functionality more powerful.
Let’s take a look at this template engine, starting with how it is used in SpringBoot.
8.2. Integrating Thymeleaf
8.2.1. How to Integrate
For SpringBoot, everything revolves around “starters.” Let’s introduce it into the project. Refer to the following three URLs:
8.2.2. Thymeleaf Official Website
8.2.3. Thymeleaf on Github
https://github.com/thymeleaf/thymeleaf
8.2.4. Official Spring Documentation: Find the relevant version
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
8.2.5. Find the corresponding pom dependency: Feel free to delve into the original package’s source code!
In the pom.xml’s dependencies section, remove the webjars dependency and add the thymeleaf dependency.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-03-web2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-03-web2</name>
<description>springboot-03-web2</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
8.2.6. Remove index.html
8.2.7. Search (double-click shift) to enter ThymeleafProperties.java
Notice the public static final String DEFAULT_PREFIX = “classpath:/templates/”; and public static final String DEFAULT_SUFFIX = “.html”; so, edit a .html file in the templates folder under the resources folder, and Thymeleaf will render it automatically.
【Convention over configuration】
8.2.8. Create IndexController.java
package com.P14.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/testtemplates")
public String test(){
//classpath:/templates/test.html
return "test";
}
}
8.2.9. Create test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>test in templates</h1>
</body>
</html>
8.2.10. Restart and Run
http://localhost:8080/testtemplates
8.3. Learning Thymeleaf Syntax
8.3.1. Download Official Documentation
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
Let’s start with a simple exercise: we need to fetch some data and display it on the page.
8.3.2. Modify Test Request, Add Data Transmission
8.3.2.1. Modify IndexController.java
package com.P14.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/testtemplates")
public String test(Model model){
//Store data
model.addAttribute("message","Hello, Thymeleaf");
//classpath:/templates/test.html
return "test";
}
}
8.3.2.2. Modify test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--Import namespace constraint xmlns:th="http://www.thymeleaf.org" from official document P11-->
<!--Standard Expression Syntax and more on P17-->
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--Thymeleaf can take over any HTML element: th:element-->
<div th:text="${message}"></div>
<!--Using <h1>${message}</h1> won't work, it'll just print ${message} directly-->
</body>
</html>
8.3.3. Restart and Test
http://localhost:8080/testtemplates
8.3.4. Thymeleaf Syntax
8.3.4.1. We can use any th:attr to replace the value of native HTML attributes.
8.3.4.2. What expressions can we write?
Simple expressions:
Variable Expressions: ${...}: Obtain variable values; OGNL;
1) Access object properties, call methods.
2) Use built-in basic objects: #18
#ctx : the context object.
#vars: the context variables.
#locale : the context locale.
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.
3) Some built-in utility objects:
#execInfo : information about the template being processed.
#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.
#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.
==================================================================================
Selection Variable Expressions: *{...}: Selection expression: Same functionality as ${}.
Message Expressions: #{...}: Retrieve internationalization content.
Link URL Expressions: @{...}: Define URL.
Fragment Expressions: ~{...}: Fragment reference expression.
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: Conditional operator (Ternary operator)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No-Operation: _
8.3.4.3. Exercise Test
8.3.4.3.1.Modify IndexController.java
package com.P14.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Array;
import java.util.Arrays;
@Controller
public class IndexController {
@RequestMapping("/testtemplates")
public String test(Model model){
// Store data
// Note: Not escaped is considered as a string, escaped is for rendering on the page
model.addAttribute("message","<h1>hello,springboot</h1>");
//How do I iterate over a set of two elements
model.addAttribute("users", Arrays.asList("zhangsan","lisi"));
//classpath:/templates/test.html
return "test";
}
}
8.3.4.3.2.Modify test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- All html elements can be replaced by thymeleaf: th: element name -->
<!-- Escape -->
<div th:text="${message}"></div>
<!-- no escape -->
<div th:utext="${message}"></div>
<hr><!-- Generate long horizontal lines of separation -->
<!-- Traversing the data -->
<h3 th:each="user:${users}" th:text="${user}"></h3>
<hr>
<h3 th:each="user:${users}">[[ ${user} ]]</h3>
<!-- The above two lines are equivalent, the first (CH9) is recommended, not recommended to use inline writing (located in document CH12) -->
</body>
</html>