Spring Boot Tutorials Part #3: Building a Web Application

{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 | ToolsEclipse...).


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;
@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Override
    public List<Employee> getAllEmployees() {     return employeeRepository.findAll();
    
    }
    
    @Override
    public void saveEmployee(Employee employee) {
employeeRepository.save(employee);
    }
    @Override
    public Employee getEmployeeById(Long id) {
        return employeeRepository.findById(id).orElse(null);
    }
    @Override
    public 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 {
    @Autowired
    private EmployeeService employeeService;
    // Display list of employees
    @GetMapping
    public 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 bind
form 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 database
        employeeService.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 service
        Employee employee = employeeService.getEmployeeById(id);
    
        // set employee as a model attribute to pre-populate the form
        model.addAttribute("employee", employee);
        return "update_employee";
    }
    // Delete employee from database
    @GetMapping("/deleteEmployee/{id}")
    public String deleteEmployee(@PathVariable(value = "id") long id) {    

        // call delete employee method 
this.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><a
    th:href="@{/employees/showFormForUpdate/{id}(id=${employee.id})}">Update</a>     | <a
    th: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 model
        attribute --> <!-- 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!



Previous Post Next Post