This tutorial will build a simple Student Management System web application using Spring Boot, Spring MVC, Thymeleaf, Spring Data JPA, and MySQL database.
We will build a CRUD operation for the Student entity in our Student Management System web application.
Video
Tools and Technologies Used
- Java 17
- Spring Boot 3
- Spring MVC
- Spring Data JPA ( Hibernate)
- MySQL
- Thymeleaf
- Eclipse STS
1. Create Spring Boot Project
Let's open STS ( Spring Suite Tool) IDE to develop and bootstrap the Spring boot project.
Use the below guide to create a Spring boot project in Eclipse STS IDE:
Selected below dependencies while creating spring boot project using spring initializr:
- Spring Web
- Thymeleaf
- Spring Data JPA
- MySQL Driver
- Spring Boot Devtools
2. Create Spring Boot Project Structure
Let's create the below packages in our Spring boot project:
- controller
- service
- repository
- entity
3. Maven Dependencies
Note that we are using Spring Boot 3 and it requires minimum Java version 17 or later.
<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>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>
3. Create Student JPA Entity
Let's create a Student JPA entity under the entity package and add the following content to it:
package net.javaguides.sms.entity; import jakarta.persistence.*; @Entity @Table(name = "students") public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "first_name", nullable = false) private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "email") private String email; public Student() { } public Student(String firstName, String lastName, String email) { super(); this.firstName = firstName; this.lastName = lastName; this.email = email; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
- @Entity - This annotation specifies that the class is an entity. This annotation can be applied to Class, Interface of Enums.
- @Table - JPA annotation specifies the table in the database with which this entity is mapped.
- @Id - The @Id JPA annotation specifies the primary key of the entity.
- @Column - The @Column annotation is used to specify the mapping between a basic entity attribute and the database table column.
4. Create JPA StudentRepository
Let's create a StudentRepository interface under the repository package and add the following content:
package net.javaguides.sms.repository; import org.springframework.data.jpa.repository.JpaRepository; import net.javaguides.sms.entity.Student; public interface StudentRepository extends JpaRepository<Student, Long>{ }
5. Configure MySQL Database
Before configuring the MySQL database configuration in our Spring boot project, first, create a database named SMS in MySQL workbench:
create database sms
Let's open the application.properties file and add following content to it:
spring.datasource.url=jdbc:mysql://localhost:3306/sms?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
#Hibernate
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
#Hibernate auto ddl
spring.jpa.hibernate.ddl-auto=update
logging.level.org.hibernate.SQL=DEBUG
6. Creating Service Layer
StudentService Interface
Let's create a StudentService interface under the service package and add the following content to it:
package net.javaguides.sms.service;
import java.util.List;
import net.javaguides.sms.entity.Student;
public interface StudentService {
List<Student> getAllStudents();
Student saveStudent(Student student);
Student getStudentById(Long id);
Student updateStudent(Student student);
void deleteStudentById(Long id);
}
StudentServiceImpl Class
Let's create a new package called impl inside the service package. Let's create StudentServiceImpl class and add the following content to it:
package net.javaguides.sms.service.impl;
import java.util.List;
import org.springframework.stereotype.Service;
import net.javaguides.sms.entity.Student;
import net.javaguides.sms.repository.StudentRepository;
import net.javaguides.sms.service.StudentService;
@Service
public class StudentServiceImpl implements StudentService{
private StudentRepository studentRepository;
public StudentServiceImpl(StudentRepository studentRepository) {
super();
this.studentRepository = studentRepository;
}
@Override
public List<Student> getAllStudents() {
return studentRepository.findAll();
}
@Override
public Student saveStudent(Student student) {
return studentRepository.save(student);
}
@Override
public Student getStudentById(Long id) {
return studentRepository.findById(id).get();
}
@Override
public Student updateStudent(Student student) {
return studentRepository.save(student);
}
@Override
public void deleteStudentById(Long id) {
studentRepository.deleteById(id);
}
}
7. Controller Layer
Let's create a StudentController class and add the following content to it:
package net.javaguides.sms.controller;
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.sms.entity.Student;
import net.javaguides.sms.service.StudentService;
@Controller
public class StudentController {
private StudentService studentService;
public StudentController(StudentService studentService) {
super();
this.studentService = studentService;
}
// handler method to handle list students and return mode and view
@GetMapping("/students")
public String listStudents(Model model) {
model.addAttribute("students", studentService.getAllStudents());
return "students";
}
@GetMapping("/students/new")
public String createStudentForm(Model model) {
// create student object to hold student form data
Student student = new Student();
model.addAttribute("student", student);
return "create_student";
}
@PostMapping("/students")
public String saveStudent(@ModelAttribute("student") Student student) {
studentService.saveStudent(student);
return "redirect:/students";
}
@GetMapping("/students/edit/{id}")
public String editStudentForm(@PathVariable Long id, Model model) {
model.addAttribute("student", studentService.getStudentById(id));
return "edit_student";
}
@PostMapping("/students/{id}")
public String updateStudent(@PathVariable Long id,
@ModelAttribute("student") Student student,
Model model) {
// get student from database by id
Student existingStudent = studentService.getStudentById(id);
existingStudent.setId(id);
existingStudent.setFirstName(student.getFirstName());
existingStudent.setLastName(student.getLastName());
existingStudent.setEmail(student.getEmail());
// save updated student object
studentService.updateStudent(existingStudent);
return "redirect:/students";
}
// handler method to handle delete student request
@GetMapping("/students/{id}")
public String deleteStudent(@PathVariable Long id) {
studentService.deleteStudentById(id);
return "redirect:/students";
}
}
8. View Layer
resources/templates/students.html
Let's create a students.html file and add the following content to it:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Student Management System</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Student Management System</a>
<!-- Toggler/collapsibe Button -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Navbar links -->
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" th:href="@{/students}">Student Management</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/students}">Teacher Management</a>
</li>
</ul>
</div>
</nav>
<div class ="container">
<div class = "row">
<h1> List Students </h1>
</div>
<div class = "row">
<div class = "col-lg-3">
<a th:href = "@{/students/new}" class = "btn btn-primary btn-sm mb-3"> Add Student</a>
</div>
</div>
<table class = "table table-striped table-bordered">
<thead class = "table-dark">
<tr>
<th> Student First Name</th>
<th> Student Last Name</th>
<th> Student Email </th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr th:each = "student: ${students}">
<td th:text = "${student.firstName}"></td>
<td th:text = "${student.lastName}"></td>
<td th:text = "${student.email}"></td>
<td>
<a th:href = "@{/students/edit/{id}(id=${student.id})}"
class = "btn btn-primary">Update</a>
<a th:href = "@{/students/{id}(id=${student.id})}"
class = "btn btn-danger">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
We have used th:each Thymeleaf attribute in our template to iterate the list of students:
resources/templates/create_student.html
Let's create a create_student.html file and add the following content to it:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Student Management System</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Student Management System</a>
<!-- Toggler/collapsibe Button -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Navbar links -->
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" th:href="@{/students}">Student Management</a>
</li>
</ul>
</div>
</nav>
<br>
<br>
<div class = "container">
<div class = "row">
<div class ="col-lg-6 col-md-6 col-sm-6 container justify-content-center card">
<h1 class = "text-center"> Create New Student </h1>
<div class = "card-body">
<form th:action="@{/students}" th:object = "${student}" method="POST">
<div class ="form-group">
<label> Student First Name </label>
<input
type = "text"
name = "firstName"
th:field = "*{firstName}"
class = "form-control"
placeholder="Enter Student First Name"
/>
</div>
<div class ="form-group">
<label> Student Last Name </label>
<input
type = "text"
name = "lastName"
th:field = "*{lastName}"
class = "form-control"
placeholder="Enter Student Last Name"
/>
</div>
<div class ="form-group">
<label> Student Email </label>
<input
type = "text"
name = "email"
th:field = "*{email}"
class = "form-control"
placeholder="Enter Student Email"
/>
</div>
<div class = "box-footer">
<button type="submit" class = "btn btn-primary">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
resources/templates/edit_student.html
Let's create an edit_student.html file and add the following content to it:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Student Management System</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Student Management System</a>
<!-- Toggler/collapsibe Button -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Navbar links -->
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" th:href="@{/students}">Student Management</a>
</li>
</ul>
</div>
</nav>
<br>
<br>
<div class = "container">
<div class = "row">
<div class ="col-lg-6 col-md-6 col-sm-6 container justify-content-center card">
<h1 class = "text-center"> Update Student </h1>
<div class = "card-body">
<form th:action="@{/students/{id} (id=${student.id})}" th:object = "${student}" method="POST">
<div class ="form-group">
<label> Student First Name </label>
<input
type = "text"
name = "firstName"
th:field = "*{firstName}"
class = "form-control"
placeholder="Enter Student First Name"
/>
</div>
<div class ="form-group">
<label> Student Last Name </label>
<input
type = "text"
name = "lastName"
th:field = "*{lastName}"
class = "form-control"
placeholder="Enter Student Last Name"
/>
</div>
<div class ="form-group">
<label> Student Email </label>
<input
type = "text"
name = "email"
th:field = "*{email}"
class = "form-control"
placeholder="Enter Student Email"
/>
</div>
<div class = "box-footer">
<button type="submit" class = "btn btn-primary">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
9. Run Spring Boot Application
Run the Spring boot application with the main class:
package net.javaguides.sms;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudentManagementSystemApplication{
public static void main(String[] args) {
SpringApplication.run(StudentManagementSystemApplication.class, args);
}
}
10. Demo
Once the Spring boot application is up and running then use the below URL to access this application:
your tutorials are helping me a lot in learning spring
ReplyDeleteThank you for this tutorial its helping a lot. Question like if we want to add a column of marks and we want to return total number of marks in thymeleaf, how can we display that total in thymeleaf ?
ReplyDelete