Overview
In this lesson, we will demonstrate how we can use Thymeleaf in a Spring Boot based application to show data in a simple template frontend. We will be using the Spring Initializr tool for setting up the project quickly. We will also mention the dependencies present in our project if you choose to setup the project manually. You can find full source code here.
Setting up the project
We will make use of Spring Initializr tool for quickly setting up the project. We will use following dependencies:
Download the project and unzip it.
Maven Dependencies
Though we already completed the setup with the tool, if you want to set it up manually, we use Maven build system for this project and here are the dependencies we used:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javabeginnerstutorial</groupId>
<artifactId>boot-hibernate-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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>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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Make sure to use stable version for Spring Boot from the maven central.
Project Structure
By the end of this lesson, this is the project structure which we will be having:
Keep the focus on the package structure. To directly use the application, we will use it with a command line runner.
Defining the Model
To save an object into the H2 in-memory database, we define a Person model object with basic fields:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private int age;
//standard getters and setters
}
It is a standard POJO with getters and setters.
Defining JPA Repository
Let us use simple JPA interface to add database interaction capability into our project:
import com.javabeginnerstutorial.bootdemo.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> { }
This is empty as all the functionality we need is already fulfilled by the default JPA methods. We will explore them in coming section.
Defining the Service
We will now define a simple service layer which will server Controller layer. In this layer, we will first define some contract methods in an interface. Let’s see the code snippet here:
import com.javabeginnerstutorial.bootdemo.model.Person;
import java.util.List;
public interface PersonService {
Person createPerson(Person person);
Person getPerson(Long id);
Person editPerson(Person person);
void deletePerson(Person person);
void deletePerson(Long id);
List<Person> getAllPersons(int pageNumber, int pageSiz);
List<Person> getAllPersons();
}
This interface just defines some contract methods the service layer must implement. Let’s move to the implementation now.
Providing Service Implementation
Let’s implement the methods defined above using the JPA Repository bean:
import com.javabeginnerstutorial.bootdemo.model.Person;
import com.javabeginnerstutorial.bootdemo.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonRepository personRepository;
@Override
public Person createPerson(Person person) {
return personRepository.save(person);
}
@Override
public Person getPerson(Long id) {
return personRepository.findOne(id);
}
@Override
public Person editPerson(Person person) {
return personRepository.save(person);
}
@Override
public void deletePerson(Person person) {
personRepository.delete(person);
}
@Override
public void deletePerson(Long id) {
personRepository.delete(id);
}
@Override
public List<Person> getAllPersons(int pageNumber, int pageSize) {
return personRepository.findAll(new PageRequest(pageNumber, pageSize)).getContent();
}
@Override
public List<Person> getAllPersons() {
return personRepository.findAll();
}
}
All the methods were actually having a single line of body. This was made possible by the JPA Repository interface itself as we were able to use the methods defined in the repository interface.
Defining Templates
We will now define the Thymeleaf based templates for our two pages. First page will be a form where we can enter data which needs to be saved to the database.
The page, when constructed will look like:
The page HTML will look like:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot: javabeginnerstutorial.com</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>New Person</h1>
<form action="#" th:action="@{/person}" th:object="${person}" method="post">
<p>Name: <input type="text" th:field="*{name}"/></p>
<p>Age: <input type="number" th:field="*{age}"/></p>
<p><input type="submit" value="Submit"/> <input type="reset" value="Reset"/></p>
</form>
</body>
</html>
Next, we will design a page where we can see all data. The page, when constructed will look like:
The page HTML will look like:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot: javabeginnerstutorial.com</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<div th:if="${not #lists.isEmpty(persons)}">
<h2>Person List</h2>
<table class="glyphicon glyphicon-calendar">
<tr>
<th>Id</th>
<th>Name</th>
<th>Age</th>
</tr>
<tr th:each="person : ${persons}">
<td th:text="${person.id}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.Age}"></td>
</tr>
</table>
</div>
</body>
</html>
Finally, let us make a controller which provides API endpoints.
Defining Controller
The Controller will have request mappings. First to present the user the form where he can enter data.
Second mapping will present page with all data present. Let’s see our Controller now:
import com.javabeginnerstutorial.bootdemo.model.Person;
import com.javabeginnerstutorial.bootdemo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class PersonController {
private final PersonService personService;
@Autowired
public PersonController(PersonService personService) {
this.personService = personService;
}
@RequestMapping(value = "", method = RequestMethod.GET)
public String homePage(Model model) {
model.addAttribute("person", new Person());
return "greeting";
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public String addPagePerson(@ModelAttribute Person person, Model model) {
personService.createPerson(person);
model.addAttribute("persons", personService.getAllPersons());
return "result";
}
}
With Thymeleaf on our classpath, Spring Boot detects it and infers the String we return as the name for HTML Thymeleaf templates and pick them from the resource directory.
Conclusion
In this lesson, we looked at how much ease Spring Boot provides us with quick project setup and how we can integrate Thymeleaf with minimal and yet powerful configuration. Feel free to leave comments below.
Making a Spring Boot & Thymeleaf CRUD Application
I am getting white label error.
This code is not working for me , any configuration is pending
Hi Neha,
Could you please let us know the problem you are facing. We tried again and it is working fine.
And please make sure you are running on Java 8.
Coz Java 9 and beyond requires extra dependencies.
Regards