👉 So what is Thymeleaf? According to
thymeleaf.org, it is a
modern server-side Java template engine for web and standalone
environments. According to Wikipedia, a "template processor" (also known
as a "template engine" or "template parser") is software designed to combine
templates with a data model to produce result documents.
👉 So how does Thymeleaf help build Spring Web applications? The Spring
Web Framework is built using the MVC (Model-View-Controller) pattern.
In the MVC pattern, "Model" is actually the data, and "View" is
how we arrange the data to present it to the world. Now the template engine,
like Thymeleaf, helps us bind the data model with views. We use HTML to
create views. To bind the dynamic content with the HTML, we use
Thymeleaf expressions, and the Thymeleaf expressions can access
Java codes, objects, and Spring Beans.
Create Spring Boot Project
Here is the pom.xml of the Spring Boot project:
<?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.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.raven</groupId>
<artifactId>springboot-thymeleaf-demo</artifactId>
<version>springboot-thymeleaf-demo-1.0.0</version>
<name>springboot-thymeleaf-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
We have used 2.7.8 as our Spring Boot version. We have added a spring-boot-starter-thymeleaf
dependency to use Thymeleaf in our web application.
👉 To demonstrate how to use Thymeleaf with a Spring MVC Web application,
we create a controller class to generate a model and then bind the model in
the Thymeleaf template (a simple HTML page) using Thymeleaf expressions.
Motivation Controller
Create a package of name controller under the root package. Inside this
controller package, create a class:
MotivationController and add the following code snippet:
package com.raven.springbootthymeleafdemo.controller;
import java.util.Random;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MotivationController {
@GetMapping("/motivation")
public String motivation(Model _model) {
String motivationString = "";
Random random = new Random();
int randomInt = random.nextInt(9); // random integers from 0 to 8
switch (randomInt) {
case 0:
motivationString = "Inspiration does exist, but it must find you working. — Pablo Picasso";
break;
case 1:
motivationString = "Success is stumbling from failure to failure with no loss of enthusiasm. — Winston Churchill";
break;
case 2:
motivationString = "Keep your eyes on the stars, and your feet on the ground. — Theodore Roosevelt";
break;
case 3:
motivationString = "Get a good idea and stay with it. Dog it, and work at it until it’s done right. — Walt Disney";
break;
case 4:
motivationString = "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence. — Helen Keller";
break;
case 5:
motivationString = "Life is like riding a bicycle. To keep your balance you must keep moving. — Albert Einstein";
break;
case 6:
motivationString = "I have never let my schooling interfere with my education. — Mark Twain";
break;
case 7:
motivationString = "If you really want to do something, you'll find a way. If you don't, you'll find an excuse. — Jim Rohn";
break;
case 8:
motivationString = "Be sure you put your feet in the right place, then stand firm. — Abraham Lincoln";
break;
}
_model.addAttribute("motivationString", motivationString);
return "motivation";
}
}
We are using Spring Model as the container for our application data. We
can put anything in the model - string, list, object, etc. Then in the
Thymeleaf template (view page) we can retrieve the data from the model
and bind the data with the HTML tag using Thymeleaf expressions.
So we have added the data in the model using addAttribute() method
and the attribute name is motivationString.
Finally returns a string motivation. As we have added the
Thymeleaf dependency in the pom.xml, Spring Framework will
automatically configure the Thymeleaf for us. So when we
return motivation, Spring Framework will look for motivation.html
resource in the template directory.
Motivation View
Now we will create a view page (Thymeleaf template). So create an
HTML page named motivation.html in the /resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<title>Motivation</title>
</head>
<body>
<p th:text="${motivationString}" style="font-size:24px; color:red;"></p>
</body>
</html>
To use the Thymeleaf expressions in the HTML page, we have added the
Thymeleaf namespace at the beginning using xmlns:th. Now we can use th:* attributes in
our HTML page.
We used the Thymeleaf expression
th:text="${motivationString}" to bind the motivationString
attribute with the HTML tag that was set into the model in our controller
class.
Here th:text attribute is used to
evaluate the expression that is assigned to it and set the result of the
evolution in the HTML tag. Using
${...} we are defining the expression.
This type of expression is known as value expression which is generally
used to execute the model attributes. There are other types of expressions:
selection variable or asterisk expressions (*{...}) execute on the selected objects, message expressions (#{...}) are for internationalization, and link expressions (@{...}) re-write URLs.
Run the application and put this URL http://localhost:8082/motivation
in the browser. You can see one of the motivational strings in the browser. If
you refresh the page the string will change.
So when we put the URL in the browser on the client side, the browser
will forward this request to the server. On the server, this request is sent
to MotivationController, the controller then creates a model with some
data, the model is sent to the Thymeleaf Template, and finally, plain
HTML is generated by the template engine and sends it back to the
browser. So the Thymeleaf template is processed on the server.
👉 Now we create a Thymeleaf template with an HTML table to bind
data using Thymeleaf expressions. To do this, we create a Customer class, the CustomerController class, and the
Thymeleaf template.
Customer Class
Create a package of name model under the root package. Inside this
model package, create a class: Customer, and then add the
following code snippet:
package com.raven.springbootthymeleafdemo.model;
public class Customer {
private int id;
private String fullName;
private String phone;
private String email;
private String address;
public Customer() {
}
public Customer(int id, String fullName,
String phone, String email,
String address) {
this.id = id;
this.fullName = fullName;
this.phone = phone;
this.email = email;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Customer [id=" + id + ", fullName=" + fullName +
", phone=" + phone + ", email=" + email + ", address="
+ address + "]";
}
}
We use this customer class in the controller.
Customer Controller
Inside this controller package, create a class:
CustomerController and add the following code snippet:
package com.raven.springbootthymeleafdemo.controller;
// imports are omitted ...
@Controller
@RequestMapping("/customers")
public class CustomerController {
private List<Customer> customers;
@PostConstruct
private void loadCustomers() {
this.customers = new ArrayList<>();
Customer customer = new Customer(1, "Schwartz J. Wright", "(000) 666-6666", "schwartz@example.com",
"5659 Heavner AvenueAtlanta, GAUnited States");
this.customers.add(customer);
customer = new Customer(2, "Patricia L. Dubose", "(098) 765-5411", "patricia@example.com",
"1462 Brown AvenueEnoree, SC, 41231United States");
this.customers.add(customer);
customer = new Customer(3, "Patricia L. Dubose", "(098) 765-5411", "patricia@example.com",
"1462 Brown AvenueEnoree, SC, 41231United States");
this.customers.add(customer);
customer = new Customer(4, "Raquel M. Morgan", "(123) 333-3333", "raquel@example.com",
"1333 Plainfield AvenueNY, 1234United States");
this.customers.add(customer);
customer = new Customer(5, "Jill J. Morris", "(123) 555-5555", "jill@example.com",
"2508 Timber Oak DriveRiverside, CA, 75421United States");
this.customers.add(customer);
}
@GetMapping("/list")
public ModelAndView listCustomers() {
ModelAndView modelAndView = new ModelAndView("customers/customerlist");
modelAndView.addObject("customers", this.customers);
return modelAndView;
}
}
You can see inside the loadCustomers() method, we have created a
customer list, and using @PostConstruct annotation we are loading
the customer list in the memory.
Inside the listCustomers() method, we have used
ModelAndView class which holds both Model and
View in the Spring Web MVC Framework. We have created an object of
ModelAndView by passing the template name
(customers/customerlist) in its constructor. Then we put our customer
list object in the model with the attribute name customers using
the addObject() method. We will use this attribute in the
Thymeleaf template to access the customer list.
Here is the template name: customers/customerlist. So, we have to
create customerlist.html in the customers directory.
Customer Table View
Create a directory of customers in the /resources/templates directory. Now create an HTML file
named customerlist.html in /resources/templates/customers and add this code
snippet:
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Customers</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
<hr>
<h3>Customers</h3>
<hr>
<table class="table table-striped table-hover">
<thead class="thead-dark">
<tr>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr th:each="customer : ${customers}">
<td th:text="${customer.fullName}" />
<td th:text="${customer.phone}" />
<td th:text="${customer.email}" />
<td th:text="${customer.address}" />
</tr>
</tbody>
</table>
<hr>
</div>
</body>
</html>
We receive the customer list data from the MVC model in
the customers attribute. Using the looping expression (th:each="customer : ${customers}") of Thymeleaf, we iterate the customer list. Then binds the customer
properties one by one in the table.
Restart the application and put this URL
http://localhost:8082/customers/list
in the browser. Here is the output:
👉 Now we will learn how to use HTML form in Thymeleaf template to bind
data. To do this, we will update the CustomerController class,
and then create a new Thymeleaf template to bind the data with the HTML form
controls.
Customer Controller
Open the CustomerController class and update it with this code snippet:
package com.raven.springbootthymeleafdemo.controller;
// imports are omitted ...
@Controller
@RequestMapping("/customers")
public class CustomerController {
// ...
// existing codes
// ...
@GetMapping("/getCustomerDetails")
public ModelAndView getCustomerDetails() {
ModelAndView modelAndView = new ModelAndView("customers/customer_details");
Customer customer = new Customer(4, "Raquel M. Morgan", "(123) 333-3333", "raquel@example.com",
"1333 Plainfield AvenueNY, 1234United States");
modelAndView.addObject("customer", customer);
return modelAndView;
}
}
As you can see inside the getCustomerDetails() method, we have created
an object of ModelAndView by passing the template name
(customers/customer_details) in its constructor. Then we put our
customer object in the model with the attribute name
customer using the addObject() method. We will use this
attribute in the Thymeleaf template to access the customer.
Customer Details Form View
Create an HTML file named customer-details.html in
/resources/templates/customers and add this code snippet:
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Customer details</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
<hr>
<h3>Customers details</h3>
<hr>
<form action="#" th:object="${customer}">
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-4">
<input type="text" class="form-control" th:field="*{fullName}">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Phone</label>
<div class="col-sm-4">
<input type="text" class="form-control" th:field="*{phone}">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-4">
<input type="text" class="form-control" th:field="*{email}">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Address</label>
<div class="col-sm-8">
<input type="text" class="form-control" th:field="*{address}">
</div>
</div>
</form>
<hr>
</div>
</body>
</html>
As you can see, in the th:object expression we have passed our model
attribute (customer) to bind the customer data with the HTML form. Then
in the input fields, we bind the customer properties one by one using
th:field expression. In th:field, we have used the selection value or asterisk expression (*{...}) to select the properties of the referenced object. In the
expression, we have passed fullName, phone, email, and address property of the customer (model attribute).
Restart the application and put this URL
http://localhost:8082/customers/getCustomerDetails
in the browser. Here is the output:
You can download the source code from
here.
Happy coding!!! 😊
References:
No comments:
Post a Comment