How to use Spring Boot and Thymyleaf in Java Web Application? Example Tutorial

Hello guys, if you are looking for a Spring Boot and Thymyleaf example, tutorial, or a project then you have come to the right place. Thymyleaf is one of the most popular, modern, server-side Java template engine to generate HTML and XHTML content. Earlier, I have shared Spring Boot + Reactjs project, as well a complete project to create Spring Boot + REST and Spring Boot + Microservices and in this tutorial, you will learn about how to create a spring boot and thyme leaf application using the h2 database.  So before moving to an example, let's discuss what is thymyleaf? Thymeleaf is a web application development library based on Java. It offers excellent support for providing XHTML/HTML5 in web applications.

And, if you are preparing for Java and Spring Boot Interviews, I have also shared 15 Spring Boot questions, Spring Cloud questions, Spring Data Questions, and Microservice questions, you can can check them as well..

Now coming back to Thymeleaf example, Thymeleaf converts your files into well-formed XML files. It contains 6 types of templates as given below.
  1. XML
  2. Valid XML
  3. XHTML
  4. Valid XHTML
  5. HTML5
  6. Legacy HTML5
These are well-formed valid XML files except the legacy HTML5. This legacy HTML5 allows us to render the HTML5 tags in the web page including non-closed tags. So let's have a look at how to a simple web application using spring boot and thymyleaf.





How to use Thymeleaf with Spring Boot in Java?

First, let's add the dependencies to 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.6.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.student</groupId>
<artifactId>crudapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>crudapp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

Spring Boot + Thymyleaf Example Tutorial for Java Programmers



The model class

After adding all the dependencies to our project, let's create the model class of our spring boot project. This project is containing one single class which is responsible for modeling the user entities.

package com.student.crudapp.model;

import javax.persistence.*;

@Entity
@Table(name = "STUDENT")
public class Student {

@Column(name = "id")
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

@NotBlank(message = "Name is mandatory")
@Column(name = "name")
private String name;

@NotBlank(message = "Email is mandatory")
@Column(name = "email")
private String email;

@NotBlank(message = "Grade is mandatory")
@Column(name = "grade")
private String grade;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getGrade() {
return grade;
}

public void setGrade(String grade) {
this.grade = grade;
}

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", grade='" + grade + '\'' +
'}';
}
}


We have annotated the model class with @Entity annotation which is responsible for make CRUD operations on domain entities. Here, used @NotBlank annotation is a hibernate validator which is capable of validating the constrained fields before persisting or updating an entity in the database.







The Repository Layer

Spring data JPA allows to implement the JPA-based repositories with minimum efforts. 

Spring Data JPA is a crucial component of Spring Boot's spring-boot-starter-data-jpa that provides a robust layer of abstraction on top of a JPA implementation to make it easy to add CRUD functionality. We may access the persistence layer through this abstraction layer instead of writing our own DAO implementations from start.

To make the crud funtionalities within our projec, we extends the StudentRepository interface with CrudRepository. The example code is given below.


package com.student.crudapp.repository;

import com.student.crudapp.model.Student;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface StudentRepository extends CrudRepository<Student, Integer> {

List<Student> findAll();
Student findById(int id);
int deleteById(int id);


}





The Controller Layer

We can add some CRUD functionality to our app using the basic web tier. In this case, there only needs one controller class which is having the GET and POST requests.


@Controller
public class StudentController {

@Autowired
StudentRepository studentRepository;

@GetMapping("/signup")
public String showStudentSignUpForm(Student student) {
return "add-student";
}

@PostMapping("/addstudent")
public String addStudent(@Valid Student student, BindingResult result, Model model) {
if (result.hasErrors()) {
return "add-student";
}

studentRepository.save(student);
return "redirect:/index";
}

@GetMapping("/index")
public String showStudentList(Model model) {
model.addAttribute("students", studentRepository.findAll());
return "index";
}


@PostMapping("/update/{id}")
public String updateStudent(@PathVariable("id") long id, @Valid User user,
BindingResult result, Model model) {
if (result.hasErrors()) {
user.setId(id);
return "update-student";
}

studentRepository.save(student);
return "redirect:/index";
}

@GetMapping("/delete/{id}")
public String deleteStudent(@PathVariable("id") long id, Model model) {
Student student = studentRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Invalid studentId:" + id));
studentRepository.delete(student);
return "redirect:/index";
}
}

If the entity doesn't pass the validation, the signup page will be displayed. Otherwise, this program allows saving the entity. We'll also have the updateStudent() function in the StudentController, which is responsible for obtaining the Student entity from the database that matches the specified id.

Here, the updateStudent() function in the controller class is responsible for updating the persisted entity in the database while deleteStudent() function is used to delete a specific entity from the database.




The Controller Layer

The viewing part in the spring boot and thymyleaf is very important as users are dealing with these layers. We need to have better and clear user interfaces in developing web applications as this might be the first impression of users whether they use the application or not. 

We can create the HTML templates required to display the signup form and also view students' screens under the src/main/resources/templates folder. So there, we will be using thymyleaf as the underlying template engine for passing the template files. 


<form action="#" th:action="@{/addStudent}" th:object="${student}" method="post">
  <label for="name">Name</label>
  <input type="text" th:field="*{name}" id="name" placeholder="Name">
  <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
  <label for="email">Email</label>
  <input type="text" th:field="*{email}" id="email" placeholder="Email">
  <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
<label for="email">Grade</label>
  <input type="text" th:field="*{grade}" id="grade" placeholder="Grade">
    <span th:if="${#fields.hasErrors('grade')}" th:errors="*{grade}"></span>
  <input type="submit" value="Add Student">  
</form>


In here, we used the @/addStudent URL expression to specify the form's action attribute the:field="*{}" to embed dynamic content to the template.

Then, let's look at the updated student function in thymyleaf.

<form action="#" th:action="@{/update/{id}(id=${student.id})}"
  th:object="${student}"
  method="post">
  <label for="name">Name</label>
  <input type="text" th:field="*{name}" id="name" placeholder="Name">
  <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
  <label for="email">Email</label>
  <input type="text" th:field="*{email}" id="email" placeholder="Email">
  <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
<label for="email">Grade</label>
  <input type="text" th:field="*{grade}" id="grade" placeholder="Grade">
    <span th:if="${#fields.hasErrors('grade')}" th:errors="*{grade}"></span>
  <input type="submit" value="Update Student">  
</form>



So these are the signup.html and addstudent.html files which we configured in this application. Let's have a look at the index.html file which displays the list of persisted entities along with the links for editing and removing existing ones.




<div th:switch="${student}">
  <h2 th:case="null">No students </h2>
      <div th:case="*">
          <h2>All Students</h2>
          <table>
              <thead>
                  <tr>
                      <th>Name</th>
                      <th>Email</th>
                      <th>Grade</th>
                      <th>Edit</th>
                      <th>Delete</th>
                  </tr>
              </thead>
              <tbody>
              <tr th:each="student : ${student}">
                  <td th:text="${student.name}"></td>
                  <td th:text="${student.email}"></td>
                  <td th:text="${student.grade}"></td>
                  <td><a th:href="@{/edit/{id}(id=${student.id})}">Edit</a></td>
                  <td><a th:href="@{/delete/{id}(id=${student.id})}">Delete</a></td>
              </tr>
          </tbody>
      </table>
  </div>      
  <p><a href="/signup">Add a new student</a></p>
</div>


To get a better user experience, we can use bootstrap along with this. Here, we are not going to add this bootstrap to the HTML file as the main focus of this application is to make a project using spring boot and thymyleaf.

In order to run this application, you need to follow the same procedure of running a spring boot application. You can either rung the application.java file by right-clicking it or run through the project(Clicking "Run" in the IDE). This will open up in the browser and point it to http://localhost:8080/
That's all about Spring Boot and Thymyleaf example in Java. In this step by step tutorial, we discussed how to create a simple spring boot and thymyleaf application by using the CRUD application. Hope you enjoy the tutorial much and hope to see you in the next tutorial. Until then bye.


Other Java and Spring Tutorial you may like
  • 13 Spring Boot Actuator Interview questions (boot questions)
  • Difference between @Autowired and @Inject in Spring? (answer)
  • Top 5 Frameworks Java Developer Should Know (frameworks)
  • Difference between @RequestParam and @PathVariable in Spring (answer)
  • Top 7  Courses to learn Microservices in Java (courses)
  • How to use @Bean in Spring framework (Example)
  • How to update an entity using Spring Data JPA? (example)
  • 20 Spring Boot Interview Questions with answers (questions)
  • What is @Conditional annotation in Spring? (conditional example)
  • How Spring MVC works internally? (answer)
  • Spring Data JPA @Query Example (query example)
  • 10 Advanced Spring Boot Courses for Java developers (courses)
  • Spring Data JPA Repository Example in Java (JpaReposistory example)
  • 20+ Spring MVC Interview Questions for Programmers (answer)
  • How to fix No property type found in Spring Data JPA? [Solution]
  • 5 Spring Cloud annotations Java programmer should learn (cloud)
  • Top 5 Courses to Learn and Master Spring Cloud (courses)
  • 5 Courses to Learn Spring Security for Java programmers (courses)
  • 10 Spring MVC annotations Java developer should know (annotations)
  • @SpringBootApplication vs. @EnableAutoConfiguration? (answer)
  • 15 Spring Boot Interview Questions for Java Developers (questions)
  • Difference between @Component, @Service, and @Controller in Spring (answer)

Thanks for reading this article so far. If you find this full-stack Spring Boot and Thymyleaf tutorial and example, then please share it with your friends and colleagues. If you have any questions or feedback, then please drop a note.

P. S. - If you are a Spring Boot beginner and want to learn the Spring Boot framework from scratch and look for some of the best online resources, you can also check out these best Spring Boot courses for Java developersThis list contains free Udemy and Pluralsight courses to learn Spring Boot from scratch.     


2 comments:

  1. User class is used in 'updateStudent' method signature. It should be Student, I guess

    ReplyDelete
  2. User class is used in 'updateStudent' method signature. It should be Student, I guess.

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.