{getToc} $title={Table of Contents}
Building a Web Application with Spring Boot, Spring MVC and Thymeleaf:
Spring Boot Tutorials Part #3: Building a Web Application |
Hi all, this is the continue part #3 about Spring Boot Tutorials. If
you not yet read the first part of this tutorial yet, then you can read it
here: Spring Boot Tutorials Part #1 (khmerside.blogspot.com).
In this part #3, we will learn how to use Spring Boot to create a web
application with Spring MVC and Thymeleaf. We will use Maven as the build
tool and Spring Boot Starter Web and Spring Boot Starter Thymeleaf as the
dependencies. We will also use Spring Data JPA and H2 database to perform
CRUD operations on a simple entity.
Prerequisites:
To follow this tutorial, you need to have:
- Java 8 or later installed on your system.
- Maven 3.5 or later installed on your system.
- An IDE of your choice (Spring | Tools, Eclipse...).
Creating the Project:
We will use
Spring Initializr
to generate the project skeleton. Go to Spring Initializr and fill in the following details:
- Project: Maven Project
- Language: Java
- Spring Boot: 2.6.3
- Group: com.example
- Artifact: spring-boot-thymeleaf-demo
- Name: spring-boot-thymeleaf-demo
- Description: Demo project for Spring Boot with Thymeleaf
- Package name: com.example.springbootthymeleafdemo
- Packaging: Jar
- Java: 8
Then, add the following dependencies:
- Spring Web
- Thymeleaf
- Spring Data JPA
- H2 Database
Click on Generate to download the project zip file. Extract the zip file
and import the project into your IDE.
Creating the Entity:
We will create a simple entity called Employee that has the following
properties:
id: Long
firstName: String
lastName: String
email: String
We will use Lombok annotations to generate getters, setters, constructors
and toString methods for this class. We will also use JPA annotations to
map this class to a database table.
Create a new package called com.example.springbootthymeleafdemo.model and
a new class called Employee.java inside it. Add the following code to this
class:
package com.example.springbootthymeleafdemo.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
@Table(name = "employees")
public class Employee {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String firstName;private String lastName;private String email;}
Creating the Repository:
We will use Spring Data JPA to create a repository interface for
performing CRUD operations on the Employee entity. We will extend the
JpaRepository interface that provides generic methods for saving,
updating, deleting and finding entities.
Create a new package called
com.example.springbootthymeleafdemo.repository and a new interface
called EmployeeRepository.java.
The following code to this interface:
package com.example.springbootthymeleafdemo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.springbootthymeleafdemo.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {}
Creating the Service:
We will create a service layer that will use the repository layer
to perform business logic on the Employee entity. And define an
interface that declares the methods for listing, saving, updating,
deleting and finding employees. And we will also provide an
implementation class that implements these methods using the
repository instance.
Create a new package called
com.example.springbootthymeleafdemo.service and a new interface
called EmployeeService.java.
The following code of this interface:
package com.example.springbootthymeleafdemo.service;
import java.util.List;
import com.example.springbootthymeleafdemo.model.Employee;
public interface EmployeeService {
List<Employee> getAllEmployees();void saveEmployee(Employee employee);Employee getEmployeeById(Long id);void deleteEmployeeById(Long id);}
Create a new class called EmployeeServiceImpl.java and follow this
code:
package com.example.springbootthymeleafdemo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.example.springbootthymeleafdemo.model.Employee;
import com.example.springbootthymeleafdemo.repository.EmployeeRepository;@Servicepublic class EmployeeServiceImpl implements EmployeeService {@Autowiredprivate EmployeeRepository employeeRepository;@Overridepublic List<Employee> getAllEmployees() { return employeeRepository.findAll();}@Overridepublic void saveEmployee(Employee employee) {employeeRepository.save(employee);}@Overridepublic Employee getEmployeeById(Long id) {return employeeRepository.findById(id).orElse(null);}@Overridepublic void deleteEmployeeById(Long id) {employeeRepository.deleteById(id);}}
Creating the Controller:
Let's create a controller layer that will handle the HTTP
requests and responses for the Employee entity. We'll use the
@Controller annotation to mark this class as a Spring MVC
controller. And also use the @RequestMapping annotation to map the
URL paths to the controller methods. And then use the service
layer to perform the business logic and the Thymeleaf template
engine to render the views.
Now, create a new package called
com.example.springbootthymeleafdemo.controller and a new class
called EmployeeController.java:
package com.example.springbootthymeleafdemo.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 org.springframework.web.bind.annotation.RequestMapping;import com.example.springbootthymeleafdemo.model.Employee;import com.example.springbootthymeleafdemo.service.EmployeeService;@Controller@RequestMapping("/employees")public class EmployeeController {@Autowiredprivate EmployeeService employeeService;// Display list of employees@GetMappingpublic String viewHomePage(Model model) {model.addAttribute("listEmployees", employeeService.getAllEmployees());return "index";}// Show new employee form@GetMapping("/showNewEmployeeForm")public String showNewEmployeeForm(Model model) {// create model attribute to bindform data Employee employee = new Employee();model.addAttribute("employee", employee);return "new_employee";}// Save employee to database@PostMapping("/saveEmployee")public String saveEmployee(@ModelAttribute("employee") Employee employee) {// save employee to databaseemployeeService.saveEmployee(employee);return "redirect:/employees";}// Show update form@GetMapping("/showFormForUpdate/{id}")public String showFormForUpdate(@PathVariable(value = "id") long id, Model model) {// get employee from the serviceEmployee employee = employeeService.getEmployeeById(id);// set employee as a model attribute to pre-populate the formmodel.addAttribute("employee", employee);return "update_employee";}// Delete employee from database@GetMapping("/deleteEmployee/{id}")public String deleteEmployee(@PathVariable(value = "id") long id) {// call delete employee methodthis.employeeService.deleteEmployeeById(id);return "redirect:/employees";}}
Creating the Views:
Now, it's time to create the views for the Employee entity
using Thymeleaf templates. For the user view, we'll use HTML
files with the .html extension and place them in the
src/main/resources/templates folder. And then use Thymeleaf
tags and expressions to bind the model data and render the
dynamic content.
Okay, let's create a new file called index.html in the
templates folder and add the following code:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>Employee Management System</title></head><body><div align="center"><h1>Employee Management System</h1> <a th:href="@{/employees/showNewEmployeeForm}">Add Employee</a><br><br><table border="1" cellpadding="10"><thead><tr><th>First Name</th><th>Last Name</th><th>Email</th><th>Actions</th></tr></thead><tbody><tr th:each="employee : ${listEmployees}"><td th:text="${employee.firstName}"></td><td th:text="${employee.lastName}"></td><td th:text="${employee.email}"></td><td><ath:href="@{/employees/showFormForUpdate/{id}(id=${employee.id})}">Update</a> | <ath:href="@{/employees/deleteEmployee/{id}(id=${employee.id})}">Delete</a></td></tr></tbody></table></div></body></html>
This is the home page that displays the list of employees and
provides links to add, update and delete employees. We use the
@{} syntax to create links with URL expressions. And use the
${} syntax to access model attributes and properties. And the
th:each attribute to iterate over the list of employees and
create table rows for each employee.
Now, create a new file called new_employee.html in the
templates folder and add the following code:
<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>Add New Employee</title></head><body><div align="center"><h1>Add New Employee</h1> <!-- create a form to add a new employee --><!-- use *{...} syntax to bind form fields to model properties --><!-- use th:object to specify the model attribute --><!-- use th:action to specify the controller method --><!-- use th:method to specify the HTTP method --><form action="#" th:action="@{/employees/saveEmployee}"th:object="${employee}" method="post">First Name: <input type="text" th:field="*{firstName}"><br><br>Last Name: <input type="text" th:field="*{lastName}"><br><br>Email: <input type="email" th:field="*{email}"><br><br><!-- use th:value to specify the button value --> <!-- use th:name to specify the button name --><input type="submit" value="Save" th:name="save"><input type="reset" value="Reset" th:name="reset"></form><!-- provide a link to go back to home page --> <a th:href="@{/employees}">Go Back</a></div></body></html>
This is the form page that allows adding a new employee. We
use the *{} syntax to bind form fields to model properties.
And use the th:object attribute to specify the model
attribute. Then use the th:action attribute to specify the
controller method. And then we use the th:method attribute to
specify the HTTP method. We also use the th:value and th:name
attributes to specify the button value and name.
Next, let's create a new file called update_employee.html in
the templates folder with the following code:
<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>Update Employee</title></head><body><!-- create a form to update an existing employee --><!-- use *{...} syntax to bind form fields to model properties --><!-- use th:object to specify the modelattribute --> <!-- use th:action to specify the controller method--><!-- use th:method to specify the HTTP method --><div align="center"><h1>Update Employee</h1><form action="#" th:action="@{/employees/saveEmployee}"th:object="${employee}" method="post"><!-- use th:value to pre-populate the form field with the employee id --> <!-- use th:name to specify the form field name --><!-- use th:type to specify the form field type --><input type="hidden" th:value="${employee.id}"th:name="id" th:type="number">First Name: <input type="text" th:field="*{firstName}"><br><br>Last Name: <input type="text" th:field="*{lastName}"><br><br>Email: <input type="email" th:field="*{email}"><br><br><!-- use th:value to specify the button value --><!-- use th:name to specify the button name --><input type="submit" value="Update" th:name="update"><input type="reset" value="Reset" th:name="reset"></form><!-- provide a link to go back to home page --><a th:href="@{/employees}">Go Back</a></div></body> </html>
It's the form page that allows updating an existing
employee. We have used the same syntax as the
new_employee.html file, except we add a hidden input field
to store the employee id. And then we have changed the
button value and name to "Update".
Running the Application:
Lastly, we can run the application by executing the
main method in the DemoApplication.java class.
Alternatively, we can use the Maven command as
bellow:
mvn spring-boot:run
The application will start on the default port 8080. We
can access the home page by opening the browser and
navigating to http://localhost:8080/employees. At this point,I'm not going to demo it for you, but you can see
such forms and pages as:
- Home page: We can add a new employee by clicking
on the “Add Employee” link. Then it will redirect to the
add employee form.
- Can update an existing employee by clicking on the
“Update” link. It'll redirect to the Update
employee form.
- And can delete an existing employee by clicking on
the “Delete” link. You should see a confirmation message
and the employee will be removed from the list.
Conclusion:
In this tutorial, we have learned how to use Spring
Boot to create a web application with Spring MVC and
Thymeleaf. And we have used Maven as the build tool and
Spring Boot Starter Web and Spring Boot Starter
Thymeleaf as the dependencies. And then we have also
used Spring Data JPA and H2 database to perform CRUD
operations on a simple entity.
Good Luck!