Spring Boot Thymeleaf CRUD Database Real-Time Project
Spring Boot Thymeleaf CRUD Database Real-Time Project
2. Maven Dependencies
<?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.2.7.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>springboot-thymeleaf-crud-web-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-thymeleaf-crud-web-app</name>
<description>Demo project for Spring Boot and thymeleaf</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-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>mysql</groupId>
<artifactId>mysql-connector-java</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>
3. Project Structure
2. Database Setup
Create a database with the name "demo" in the MySQL database server.
spring.datasource.url=jdbc:mysql://localhost:3306/demo?
useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect =
org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
I have also specified the log levels for hibernate so that we can debug the SQL
queries executed by hibernate.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "employees")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "first_name")
@Column(name = "last_name")
@Column(name = "email")
return id;
return firstName;
this.firstName = firstName;
return lastName;
this.lastName = lastName;
return email;
this.email = email;
}
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 2
author: Ramesh Fadatare
1. Back-end changes
First, we will complete the back-end changes.
EmployeeRepository.java
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.model.Employee;
@Repository
package net.javaguides.springboot.service;
import java.util.List;
import net.javaguides.springboot.model.Employee;
List<Employee> getAllEmployees();
EmployeeServiceImpl.java
package net.javaguides.springboot.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
@Service
@Autowired
@Override
return employeeRepository.findAll();
EmployeeController.java
package net.javaguides.springboot.controller;
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 net.javaguides.springboot.service.EmployeeService;
@Controller
@GetMapping("/")
model.addAttribute("listEmployees", employeeService.getAllEmployees());
return "index";
2. Front-end changes
index.html
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>Employee Email</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 3
author: Ramesh Fadatare
EmployeeService.java
package net.javaguides.springboot.service;
import java.util.List;
import net.javaguides.springboot.model.Employee;
EmployeeServiceImpl.java
The complete code:
package net.javaguides.springboot.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
@Service
@Autowired
@Override
return employeeRepository.findAll();
@Override
this.employeeRepository.save(employee);
}
index.html changes
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>Employee Email</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
EmployeeController changes
@GetMapping("/showNewEmployeeForm")
model.addAttribute("employee", employee);
return "new_employee";
}
Create new_employee.html
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<div class="container">
<hr>
<h2>Save Employee</h2>
</form>
<hr>
</div>
</body>
</html>
EmployeeController changes
@PostMapping("/saveEmployee")
employeeService.saveEmployee(employee);
return "redirect:/";
package net.javaguides.springboot.controller;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
@Controller
@Autowired
@GetMapping("/")
model.addAttribute("listEmployees", employeeService.getAllEmployees());
return "index";
@GetMapping("/showNewEmployeeForm")
model.addAttribute("employee", employee);
return "new_employee";
@PostMapping("/saveEmployee")
return "redirect:/";
}
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 4
author: Ramesh Fadatare
1. Back-end changes
package net.javaguides.springboot.service;
import java.util.List;
import net.javaguides.springboot.model.Employee;
}
EmployeeServiceImpl.java class change
@Override
if (optional.isPresent()) {
employee = optional.get();
} else {
return employee;
package net.javaguides.springboot.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
@Service
@Autowired
@Override
return employeeRepository.findAll();
@Override
this.employeeRepository.save(employee);
@Override
if (optional.isPresent()) {
employee = optional.get();
} else {
return employee;
}
EmployeeController changes
@GetMapping("/showFormForUpdate/{id}")
model.addAttribute("employee", employee);
return "update_employee";
package net.javaguides.springboot.controller;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
@Controller
public class EmployeeController {
@Autowired
@GetMapping("/")
model.addAttribute("listEmployees", employeeService.getAllEmployees());
return "index";
@GetMapping("/showNewEmployeeForm")
model.addAttribute("employee", employee);
return "new_employee";
@PostMapping("/saveEmployee")
employeeService.saveEmployee(employee);
return "redirect:/";
@GetMapping("/showFormForUpdate/{id}")
model.addAttribute("employee", employee);
return "update_employee";
2. Front-end changes
Add below button in actions column:
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>Employee Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td><a th:href="@{/showFormForUpdate/{id}(id=$
{employee.id})}" class="btn btn-primary">Update</a></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Create update_employee.html
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<div class="container">
<hr>
<h2>Update Employee</h2>
</form>
<hr>
</div>
</body>
</html>
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 5
author: Ramesh Fadatare
1. Back-end changes
package net.javaguides.springboot.service;
import java.util.List;
import net.javaguides.springboot.model.Employee;
@Override
this.employeeRepository.deleteById(id);
package net.javaguides.springboot.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
@Service
@Autowired
@Override
return employeeRepository.findAll();
}
@Override
this.employeeRepository.save(employee);
@Override
if (optional.isPresent()) {
employee = optional.get();
} else {
return employee;
@Override
this.employeeRepository.deleteById(id);
}
EmployeeController changes
@GetMapping("/deleteEmployee/{id}")
this.employeeService.deleteEmployeeById(id);
return "redirect:/";
package net.javaguides.springboot.controller;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
@Controller
@GetMapping("/")
model.addAttribute("listEmployees", employeeService.getAllEmployees());
return "index";
@GetMapping("/showNewEmployeeForm")
model.addAttribute("employee", employee);
return "new_employee";
@PostMapping("/saveEmployee")
employeeService.saveEmployee(employee);
return "redirect:/";
@GetMapping("/showFormForUpdate/{id}")
model.addAttribute("employee", employee);
return "update_employee";
@GetMapping("/deleteEmployee/{id}")
this.employeeService.deleteEmployeeById(id);
return "redirect:/";
2. Front-end changes
Add "Delete" button in index.html file:
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>Employee Email</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td> <a th:href="@{/showFormForUpdate/{id}(id=$
{employee.id})}" class="btn btn-primary">Update</a>
<a th:href="@{/deleteEmployee/{id}(id=${employee.id})}"
class="btn btn-danger">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 6 | Pagination using Spring
Data JPA
author: Ramesh Fadatare
@NoRepositoryBean
/**
* @param sort
*/
/**
* @param pageable
*/
JpaRepository interface extends PagingAndSortingRepository interface so if
For example, use the following to get the first page from the database, with 5
items per page:
int pageNumber = 1;
int pageSize = 5;
With a Page object you can know the total rows in the database and the total
pages according to the given page size:
This information is useful for implementing pagination in the view with the
Thymeleaf template.
1. Back-end changes
package net.javaguides.springboot.service;
import java.util.List;
import org.springframework.data.domain.Page;
import net.javaguides.springboot.model.Employee;
@Override
public Page<Employee> findPaginated(int pageNo, int pageSize) {
return this.employeeRepository.findAll(pageable);
@GetMapping("/page/{pageNo}")
int pageSize = 5;
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("listEmployees", listEmployees);
return "index";
<div class="col-sm-2">
</div>
<div class="col-sm-1">
</span>
</div>
<div class="col-sm-1">
</div>
<div class="col-sm-1">
</div>
</div>
</div>
The complete code:
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>Employee Email</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<a th:href="@{/deleteEmployee/{id}(id=${employee.id})}"
class="btn btn-danger">Delete</a>
</td>
</tr>
</tbody>
</table>
<div class="col-sm-2">
</div>
<div class="col-sm-1">
</span>
</div>
<div class="col-sm-1">
</div>
<div class="col-sm-1">
</div>
</div>
</div>
</div>
</body>
</html>
Spring Boot Thymeleaf CRUD
Database Real-Time Project -
PART 7 | Sorting with Spring
Data JPA
author: Ramesh Fadatare
@NoRepositoryBean
/**
* @param sort
*/
/**
* @param pageable
The users will be able to sort the employee's list by clicking on the column
header of the table.
Sort sort =
Sort.by("fieldName1").ascending().and(Sort.by("fieldName2").descending());
1. Back-end changes
package net.javaguides.springboot.service;
import java.util.List;
import org.springframework.data.domain.Page;
import net.javaguides.springboot.model.Employee;
Page < Employee > findPaginated(int pageNo, int pageSize, String sortField,
String sortDirection);
@Override
Sort.by(sortField).descending();
return this.employeeRepository.findAll(pageable);
}
The complete code:
package net.javaguides.springboot.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
@Service
@Autowired
@Override
return employeeRepository.findAll();
@Override
@Override
if (optional.isPresent()) {
employee = optional.get();
} else {
return employee;
@Override
this.employeeRepository.deleteById(id);
@Override
public Page < Employee > findPaginated(int pageNo, int pageSize, String
sortField, String sortDirection) {
Sort.by(sortField).descending();
return this.employeeRepository.findAll(pageable);
}
3.EmployeeController.java changes
@GetMapping("/page/{pageNo}")
Model model) {
int pageSize = 5;
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("listEmployees", listEmployees);
return "index";
}
Also provide default sorting field and sorting direction for home page:
@GetMapping("/")
package net.javaguides.springboot.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
@Controller
@GetMapping("/")
@GetMapping("/showNewEmployeeForm")
model.addAttribute("employee", employee);
return "new_employee";
@PostMapping("/saveEmployee")
employeeService.saveEmployee(employee);
return "redirect:/";
@GetMapping("/showFormForUpdate/{id}")
model.addAttribute("employee", employee);
return "update_employee";
@GetMapping("/deleteEmployee/{id}")
this.employeeService.deleteEmployeeById(id);
return "redirect:/";
@GetMapping("/page/{pageNo}")
Model model) {
int pageSize = 5;
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("listEmployees", listEmployees);
return "index";
2. Front-end changes
1.index.html
We make the header columns of the table sortable by adding hyperlinks with
the following code:
<th>
</th>
<th>
</th>
<th>
Employee Email</a>
</th>
<th> Actions </th>
</div>
</span>
</div>
</div>
<div class="col-sm-1">
</div>
</div>
</div>
The complete code:
<!DOCTYPE html>
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-
MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<h1>Employees List</h1>
<thead>
<tr>
<th>
</th>
<th>
</th>
<th>
Employee Email</a>
</th>
</tr>
</thead>
<tbody>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
</td>
</tr>
</tbody>
</table>
</div>
</span>
</div>
</div>
<div class="col-sm-1">
</div>
</div>
</div>
</div>
</body>
</html>