Spring Boot CRUD with Thymeleaf

In this topic, we will perform CRUD operation in the Spring Boot web application using the Thymeleaf template for UI design. We will create step-by-step an example of a web application in Spring Boot with Spring MVC support and an H2 database.
Table of content
1. Keep eclipse IDE ready(STS integrated)
2. Create a Spring Boot Starter Project 
3. Maven Dependency
4. H2 database configuration in application.properties file
5. Create an Entity class
6. Thymeleaf Templates
7. Create a Repository
8. Create a Service
9. Create a Controller
10. Run the app
11. Conclusion

1. Keep eclipse IDE ready(STS Integrated) 
Refer to this article How to Create Spring Project in IDE to create Spring Boot Project in Eclipse IDE.
2. Create a Spring Boot Starter Project 
Add the following dependencies: 
• Spring Web
• Spring Data JPA
• H2 Database
• Lombok 
• Thymeleaf

spring_boot_crud_with_thymeleaf

3. Maven Dependency
 pom.xml:

<?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.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.springjava.poc</groupId>
	<artifactId>Spring_Boot_CRUD_With_Thymeleaf</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>Spring_Boot_CRUD_With_Thymeleaf</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-data-jpa</artifactId>
		</dependency>
		<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>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</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>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

4. H2 database configuration in application.properties file

spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto= update
spring.h2.console.enabled=true

Copy

5. Create an Entity class
Staff.java:

package com.springjava.poc.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;

@Entity
@Data
public class Staff {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
 private Integer id;
 private String name;
 private String desgn;
 private String emailId;
}

→ In this Entity class we used Lombok.
6. Thymeleaf Templates
add-edit-staff.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Add Staff</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
</head>

<body>
    <div class="container my-5">
        <h3> Add Staff</h3>
        <div class="card">
            <div class="card-body">
                <div class="col-md-10">
<form action="#" th:action="@{/save-staff}" th:object="${staff}" method="post">
                        <div class="row">
                            <div class="form-group col-md-8">
                                <label for="name" class="col-form-label">Name</label> 
                                <input type="text" th:field="*{name}" class="form-control" 
                                            id="name" placeholder="Enter Name" />
                            </div>
                            <div class="form-group col-md-8">
                                <label for="name" class="col-form-label">Designation</label> 
                                <input type="text" th:field="*{desgn}" class="form-control" 
                                            id="desgn" placeholder="Enter Designation" />
                            </div>
                            <div class="form-group col-md-8">
                                <label for="email" class="col-form-label">Email</label> 
                                <input type="text" th:field="*{emailId}" class="form-control" 
                                            id="email" placeholder="Email Id" />
                            </div>

                            <div class="col-md-6">
                                <input type="submit" class="btn btn-primary" value=" Submit ">
                            </div>

                            <input type="hidden" id="id" th:field="*{id}">
    
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

list-staffs.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>All Staffs</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
  </head>
  <body>
    <div class="container my-2">
      <div class="card">
        <div class="card-body">
          <div th:switch="${staffs}" class="container my-5">
            <p class="my-5">
              <a href="/Spring_Boot_CRUD_With_Thymeleaf/add-staff" class="btn btn-primary">
                <i class="fas fa-user-plus ml-2"> Add Staff </i>
              </a>
            </p>
            <div class="col-md-10">
              <h2 th:case="null">No record found !!</h2>
              <div th:case="*">
                <table class="table table-striped table-responsive-md">
                  <thead>
                    <tr>
                      <th>Name</th>
                      <th>Designation</th>
                      <th>Email</th>
                      <th>Edit</th>
                      <th>Delete</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr th:each="staff : ${staffs}">
                      <td th:text="${staff.name}"></td>
                      <td th:text="${staff.desgn}"></td>
                      <td th:text="${staff.emailId}"></td>
                      <td>
                        <a th:href="@{/staff-update/{id}(id=${staff.id})}" class="btn btn-primary">
                          <i class="fas fa-user-edit ml-2"></i>
                        </a>
                      </td>
                      <td>
                        <a th:href="@{/staff-delete/{id}(id=${staff.id})}" class="btn btn-primary">
                          <i class="fas fa-user-times ml-2"></i>
                        </a>
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

7. Create a Repository
StaffRepo.java:

package com.springjava.poc.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.springjava.poc.entity.Staff;

public interface StaffRepo extends JpaRepository<Staff, Integer> {

}

8. Create a Service
StaffService.java:

package com.springjava.poc.service;
import java.util.List;
import com.springjava.poc.entity.Staff;

public interface StaffService {
void save(Staff staff);
List<Staff> getAll();
Staff getById(Integer id);
void delete(Staff staff);
}

StaffServiceImp.java:

package com.springjava.poc.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.springjava.poc.entity.Staff;
import com.springjava.poc.repository.StaffRepo;

@Service
public class StaffServiceImpl implements StaffService {
	@Autowired
	StaffRepo staffRepo;

	@Override
	public void save(Staff staff) {
		if (staff.getId() == null) {
			staffRepo.save(staff);
		} else {
			Staff staffUpdate = staffRepo.findById(staff.getId()).get();
			staffUpdate.setName(staff.getName());
			staffUpdate.setDesgn(staff.getDesgn());
			staffUpdate.setEmailId(staff.getEmailId());
			staffRepo.save(staffUpdate);
		}
	}

	@Override
	public List<Staff> getAll() {
		return staffRepo.findAll();
	}

	@Override
	public Staff getById(Integer id) {
		return staffRepo.findById(id).get();
     }

	@Override
	public void delete(Staff staff) {
		staffRepo.delete(staff);
	}
}

9. Create a Controller
StaffController.java:

package com.springjava.poc.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import com.springjava.poc.entity.Staff;
import com.springjava.poc.service.StaffService;

@Controller
public class StaffController {
	@Autowired
	StaffService staffService;

	@GetMapping("/")
	public String getAllSatffs(Model model) {
		List<Staff> staffList = staffService.getAll();
		if(staffList.size()>0) {
		model.addAttribute("staffs", staffList);
		}
		return "list-staffs";
	}

	@GetMapping("/add-staff")
	public String addStaff(Model model) {
		model.addAttribute("staff", new Staff());
		return "add-edit-staff";
	}

	@PostMapping("/save-staff")
	public String saveStaff(Staff staff) {
		staffService.save(staff);
		return "redirect:/";
	}

	@GetMapping("/staff-update/{id}")
	public String getStaff(Model model, @PathVariable("id") Integer id) {
		Staff staff = staffService.getById(id);
		model.addAttribute("staff", staff);
		return "add-edit-staff";
	}
	
	@GetMapping("/staff-delete/{id}")
	public String deleteStaff(@PathVariable("id") Integer id) {
		Staff deleteStaff = staffService.getById(id);
		staffService.delete(deleteStaff);
		return "redirect:/";
	}
}

→ The Model is an interface and is available in the org.springframework.ui package. This acts as a data container that contains the data of the application. This stored data can be of any form such as String, Object, data from the Database, etc.

10. Run the app
Right-click on the app then click on Run As and select Run on Server.

11. Conclusion
In this topic, we implemented CRUD operation in the Spring Boot web application with the Thymeleaf template.

Leave a Comment