Thymeleaf + Spring Boot – Complete Tutorial (Step by Step with Source Codes)

1. Introduction to Thymeleaf (Video)

In this walk-through, we would build an application to store student records. Users would be able to:

  • access list of students in html page
  • add new student
  • update student
  • delete student

We would learn the following technologies:

  • Springboot
  • JPA Repository
  • H2 In-Memory Database
  • Thymeleaf
  • Javascript, Bootstrap and JQuery
  • and more!

What is Thymeleaf? Thymeleaf is a server side template engine for processing pages (HTML5, XML, XHTML)

Thing to install:

MySQL – The free community edition can be gotten from here

Spring Tool Suite – download for free from here


2. Project Setup in Spring Initializr (Video)

Goto  and create a project. Use the following settings:

  • Project: Maven Project
  • Language: Java
  • Spring Boot: 2.1.6
  • Group: com.kindsonthegenius (you can change this )
  • Artifact: thymeleaf-app
  • Name: thymeleaf-app
  • Description: Thymeleaf Application
  • Package Name: com.kindsonthegenius.thymeleaf-app
  • Packaging: Jar
  • Java: 8

Add the following dependencies: H2 Database, MySql Driver, Spring Data JPA, Thymeleaf,  Spring web starter

Generated the project. So the the project is downloaded as as zip file

Unzip the file and open it in Spring Tool Suite


3. Add Additional Dependencies (Video)

Open the pom.xml file to ensure the dependencies are specified

Add the following additional dependencies:

  • spring-web
  • spring-context
  • Bootstrap (4.3.1)
  • JQuery (3.4.1)

This dependencies are gotten from Maven Repository

Remove the versions tag from spring-web and spring-context

Save the project


The general architecture or our application is given below

Spring Boot Thymeleaf Architecture


4. Create a html and Test Thymeleaf (Video)

Create a class called HomeController in the com.kindsonthegenius.thymeleafapp package

Annotate this class with the @Controller annotation

Write a String method called test to return “index”.

Annotate this method with @RequestMapping(“/home”)

The content of the file is as shown below

public class HomeController {
	public String test() {
		return "index";


Create a html file inside the templates folder. The templates folder is inside the src/main/resources folder.

The content of the html file is as shown below

Run the application

Then visit http://localhost:8080/home and ensure the page displays


5. Setup and test H2 Database (Video)

Open the file and add the following directives



Run the application

Then visit http://localhost:8080/h2-console

Ensure the name of the database is studentdb

Then click on connect. You will now see the h2-console open up.


6. Setup MySQL Database (Video)

Open the file again

Add the following code to configure MySQL datasource

Note the the datasource configuration for H2 database has been commented out. This is because you can have two datasources at the same time

#H2 Database Configuration

#MySQL Database Configuration

#if you receive Timezone error, then replace the datasource url with the one below


7.  Create the Model (the Student class) (Video)

Create a class called Student in the models package

The class should have the following member variables:

  • Id (Integer)
  • name (String)
  • department (String)
  • updatedBy (String)
  • updatedOn (Date

Annotate the class with the @Entity annotion

Annotate the Id field with the @Id annotation

Annotate the updatedOn field with the @DataTimeFormat(pattern=”yyyy-MM-dd”) annotation

The class would be as shown below


public class Student {
	private Integer Id;
	private String name;
	private String department;
	private String updatedBy;
	private String updatedOn;


Generated the constructors, getter and setters and the toString method


8. Write and Test Database Initialization Query (Video)

Create a file called data.sql in the src/main/resources folder

Write a query the insert some initial data. The content of the file would be as shown below;

insert into student values(1, 'Kindson Munonye', 'Computer Science', 'The Tech Pro', '2019-06-27');
insert into student values(2, 'Kate Winston', 'Managment', 'The Tech Pro', '2019-06-27');
insert into student values(3, 'Solace Okeke', 'Data Science', 'The Tech Pro', '2019-06-27');


Now, test the application.

First, check that the the Student table is created in the mySQL server and the data is inserted

Next, do the same for the H2 database

Remember to modify the file before you test each of the databases;


9. Create the Crude Repository (Video)

Create an interface called StudentRepository in the repositories folder

Make this interface extend CrudRepository

Specify the class and Id type as Student and Integer respectively

Annotate the class with the @Repository annotation


10. Create the Business Service (Video)

Create a class called StudentService in the services folder

Annotate this class with the @Service annotation

Autowire the StudentRepository into the StudentService


11. Create the Controller (Video)

Create a class called StudentController

Annotate the class with the @Controller annotation

Annotate this class with the @RequestMapping(“/students”)

Autowire the StudentService into the StudentController


12. Write the getAll() Method (Video)

In the StudentService, write a GetAll method . This method should call the findAll() method of the repository.

This method should return a List<Student>

 In the StudentController, write the getAll method. This method should call the getAll method of the service

Annotate this method with @RequestMapping(“/getAll”)

This method should return a string of “students

The code is shown below

public String getAll(Model model) {
	List<Student> students = studentService.getAll();
	model.addAttribute("students", students);
	return "students";


13. Setup and test the html page (Video)

To ensure that that StudentController can serve a page using Thymeleaf;

Create a html page in the templates folder and call it students.html

Write some text in the page.

The go ahead to run the application.

Navigate to http://localhost:8080/students/getAll. Confirm that the html page display

Optional: Change the @Controller annotation to @RestController. Also modify the function to return List<Student>. Then test if it actually return the data.


14. Setup Bootstrap and JQuery (Video)

In the html page, include in the header section:

  • the link to bootstrap.css
  • jquery.js script
  • bootstrap.js script

For me, it is as shown below:

<link href="/webjars/bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet" />
<script type="text/javascript" src="/webjars/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/webjars/jquery/3.4.1/jquery.min.js"></script>

Create a simple table and test it using table table-stripped class

Note: if the link and script doesn’t work, try using the CDN links  from the website


15. Send data from Controller to View (Video)

Modify the getAll method in the controller, add a model object as parameter

Now call the service to return a  list of students.

Then assign this list as an attribute to the model object. In this way, this list would be available in the view.

The method would then be as shown below:

public String getAll(Model model) {
	List<Student> students = studentService.getAll();
	model.addAttribute("students", students);
	return "students";


16. Receive data in the View (html page) (Video)

Modify the table in the html page to have five columns and two rows.

Then add the Thymeleaf markup to display the data from the models.

The final table would be as shown below

<table class="table table-stripped">
<td>Updated By</td>
<td>Updated On</td>
<tr th:each="student:${students}">
<td th:text="${student.Id}">Id</td>
<td th:text="${}">Name</td>
<td th:text="${student.department}">Department</td>
<td th:text="${student.updatedBy}">Updated By</td>
<td th:text="${student.updatedOn}">Updated On</td>


Run the application and check that the data is displayed in the page


17. Write and test the getOne() method (Video)

In the Service class, write a the method getOne() to return a single record.

In the Controller class, write the method getOne()

It is going to return a single Student. Also, it would take an Integer parameter, Id.

Annotate this method with @RequestMapping(“/getOne”)

At the the, the getOne method in the controller would look like this:

public Optional<Student> getOne(Integer Id)
	return studentService.getOne(Id);


18. Write the addNew Method (Video)

In the StudentService, write the addNew method.

This method would take a Student object and save it to the repository.

In the StudentController, writhe the addNew method

Annotate the method with the @RequestMapping(value=”/addNew” method=”post”)

public String addNew(Student student) {
	return "redirect:/students/getAll";

Note: there is not spaces in the redirect statement!


19. Set up the AddModal Dialog (Video)

The easiest way to do this is to go to the Bootstrap website and get a modal form template. Copy and add the code to the students.html page.

Copy the code for the button as well

Move the form tag to the uppermost level div tag!

Modify the name and text in the add button.

Then modify the form to add the textfields.

Change the Ids of the textfield to something relevant.

Test the application to see the appearance


20. Complete and Test the Insert operation (Video)

Give the textfields name attributes that corresponds to the name used in the model.

Change the type of button for the Save operation from “button” to “submit”

Set the th:action of the form to @”{/students/addNew}”.

Set the method to post

Test the application and try to insert data into the database. If it works, congrats!

If not, watch the video and leave me a comment to let me know so I can help you.


21. Write the Update Methods (Video)

In the Student Service, write the update method. This method should call the save() method of the repository.

Also, in the Controller, write the update method.

This method take a single parameter of Student.

Annotates this method with @RequestMapping…….

It returns a redirect to the students/findAll url

The final update() method for the controller is shown below

@RequestMapping(value="/update", method = {RequestMethod.PUT, RequestMethod.GET})
public String update(Student student) {
	return "redirect:/students/getAll";


22. Setup the Edit Modal (Video)

The easiest way to do this is to make a copy of the existing addModal. Then change the name to editModal

Change the names of the textfields to something relevant

Set the action of the editModal like this – th:action = “@{/students/update}”

Now, in the table, add a sixth column and name it Edit.

Then add a button and set its data-target attribute to #editModal (we would later change it to a link)

Set the class of this button to “btn btn-warning”

Test the application to ensure that the modal displays

Then change the button to an anchor tag


23. Create the Custom js File (Video)

Now, if you test the application, you will see that nothing happens when we click on the Edit button. We would write a custom script that runs when the button is clicked.

Inside the static folder of the src/main/resources, create a folder js.

Then create a file called main.js.

In the students.html page, add a link to this file in the head section. The link would be as follows:

<script type="text/javascript" src="../static/js/main.js" th:src="@{/js/main.js}"></script>

Note: Make sure to get this right!

Inside this file, write a function to display the editModal. The file would be as follows:


	$('.table #editButton').on('click',function(event){	

Note: no space between ‘click’ and function

Note: the event.preventDefault() stops the link from navigating to a response page. Try to remove it an rerun the application so you understand how it works.

Then test the application and ensure the editModal form displays


24. Complete and Test the Edit Method (Video)

Two things should when the editButton is clicked:

  • request is sent to /students/getOne?Id={Id} to retrieve a particular record
  • the values retrieved are assigned to the edit text fields

Add the href attribute to the editButton. The attribute is as shown below:



Now modify the main.js file. Write the codes to assign the values of the student record to the textfields.  At the end the final code would be:


25. Write the Delete Method (Video)

Write the delete method in the studentService.

Also write the delete method in the StudentController file

The delete method would take on parameter which is the Id of record to be deleted.

The delete() method is shown below:

@RequestMapping(value="/delete", method = {RequestMethod.DELETE, RequestMethod.GET})	
public String delete(Integer Id) {
	return "redirect:/students/getAll";


26. Setup  the Delete Modal (Video)

Now that the add and update is working well, I’l say congrats to you!

To add the delete we would a modal from the bootstrap website.

Place the modal in the page and give it an id of deleteModal

Change the texts on it to something relevant.

Change button to an anchor tag and add the href set to “”

Add a delete link in the table just like the Edit link, but this time to the /delete endpoint

Modify the main.js file to display the deleteModal

Test the application and check that the modal displays.


27. Complete and Test the Delete Modal (Video)

Now give the button in the deleteModal an id of delRef

In the main.js file, write the code to complete the delete operation

The js code for the deleteButton is shown below:

$('.table #deleteButton').on('click',function(event){
	var href = $(this).attr('href');
	$('#deleteModal #delRef').attr('href', href);		

Test the application to make sure it works.


28. Display Logged In Username with Thymeleaf (Video)

User authentication and authorization are covered under spring security. I’m currently working on the tutorials on Spring Security and would publish it in the next few day.

For now, the easiest way to pass the logged in user details to the view is to place it in the model. This can be done in the getAll function since that is the only page we are working with.

Just write this one line of code in the getAll() method:

String username = "Kindson";
model.addAttribute("username", username);


Then in the students.html page, you can retrieve the value using the code below:

Welcome,  <span th:text="${username}">Welcome guest!


29. Using BootStrap for UI
(Only Video!)






Kindson Munonye is currently completing his doctoral program in Software Engineering in Budapest University of Technology and Economics

View all posts by kindsonthegenius →

9 thoughts on “Thymeleaf + Spring Boot – Complete Tutorial (Step by Step with Source Codes)

  1. Pingback: 14 Setup Bootstrap and JQuery | Nikkies Tutorials
  2. Pingback: 0. All in One – Java, Thymeleaf, Springboot, Bootstrap, JQuery, MySQL, H2, JavaScript | Nikkies Tutorials
  3. Sir thank you for the tutorials but please help my form is not displaying when adding the modal i included jquery before bootstrap still its not working…..Any help?

Leave a Reply

Your email address will not be published.