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.
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:
=> Create Spring Boot Project in Spring Tool Suite [STS]
Selected below dependencies while creating spring boot project using spring initializr:
Let's create the below packages in our Spring boot project:
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>
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;
}
}
@Id
JPA annotation specifies the primary key of the
entity.@Column
annotation is used to specify the mapping
between a basic entity attribute and the database table column.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>{
}
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
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);
}
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 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);
}
}
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";
}
}
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:
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>
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>
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);
}
}
Once the Spring boot application is up and running then use the below URL to access this application:
URL: http://localhost:8080/students