Spring Boot Tutorial - Build Employee Management Project from Scratch using Spring Boot + Spring Security + Thymeleaf and MySQL Database
Overview
The Employee Management System project will implement the following features:
- List Employees
- Add Employee
- Update Employee
- Delete Employee
- Pagination
- Sorting
- User Login
- User Registration
- User Logout
Tools and Technologies Used
- Java 17+
- Spring Boot 3
- Spring Data JPA (Hibernate)
- Spring Security 6
- MySQL
- Eclipse STS
- Maven
- Tomcat
- Thymeleaf
Step 1: Create Spring Boot Project
Spring Boot provides a web tool called Spring Initializer to bootstrap an application quickly. Follow these steps:
Go to Spring Initializer
Visit https://start.spring.io/.
Use the following details:
- Project Name:
employee-management-webapp
- Project Type:
Maven
- Dependencies:
Spring Web
,Spring Data JPA
,MySQL Driver
,Spring Security
,Thymeleaf
- Package name:
net.javaguides.springboot
Step 2: Add Maven Dependencies
Here is the complete pom.xml
file for your reference:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</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.com</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
Step 3: Configure MySQL Database
Spring Boot tries to auto-configure a DataSource if the spring-boot-starter-data-jpa
dependency is in the classpath by reading the database configuration from the application.properties
file.
Configure application.properties
Open the application.properties
file and add the following properties:
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=root
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
You will need to create a database named demo
in MySQL, and change the spring.datasource.username
and spring.datasource.password
properties as per your MySQL installation.
Spring Boot uses Hibernate as the default JPA implementation. The property spring.jpa.hibernate.ddl-auto
is used for database initialization. We’ve used the value update
for this property.
Step 4: Create Models
Let's create models or entities for our Employee Management System application.
Create the Employee
Class
Create an Employee
class inside the model
package:
package net.javaguides.springboot.model;
import jakarta.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
// Getters and Setters
}
Create the User
Class
Create a User
class inside the model
package:
package net.javaguides.springboot.model;
import java.util.Collection;
import jakarta.persistence.*;
@Entity
@Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = "email"))
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private String email;
private String password;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "role_id", referencedColumnName = "id"))
private Collection<Role> roles;
// Getters and Setters
}
Create the Role
Class
Create a Role
class inside the model
package:
package net.javaguides.springboot.model;
import jakarta.persistence.*;
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
Step 5: Create Repository Layer
We will create JPA repositories to access data from the database.
Create EmployeeRepository
Create an EmployeeRepository
interface inside the repository
package:
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import net.javaguides.springboot.model.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Create UserRepository
Create a UserRepository
interface inside the repository
package:
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import net.javaguides.springboot.model.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
Step 6: Create Service Layer
We will implement a service layer.
Create EmployeeService
Interface
Create an EmployeeService
interface inside the service
package:
package net.javaguides.springboot.service;
import java.util.List;
import org.springframework.data.domain.Page;
import net.javaguides.springboot.model.Employee;
public interface EmployeeService {
List<Employee> getAllEmployees();
void saveEmployee(Employee employee);
Employee getEmployeeById(long id);
void deleteEmployeeById(long id);
Page<Employee> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
Create EmployeeServiceImpl
Class
Create an EmployeeServiceImpl
class inside the service
package:
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
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@Override
public void saveEmployee(Employee employee) {
this.employeeRepository.save(employee);
}
@Override
public Employee getEmployeeById(long id) {
Optional<Employee> optional = employeeRepository.findById(id);
Employee employee = null;
if (optional.isPresent()) {
employee = optional.get();
} else {
throw new RuntimeException(" Employee not found for id :: " + id);
}
return employee;
}
@Override
public void deleteEmployeeById(long id) {
this.employeeRepository.deleteById(id);
}
@Override
public Page<Employee> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
return this.employeeRepository.findAll(pageable);
}
}
Create UserService
Interface
Create a UserService
interface inside the service
package:
package net.javaguides.springboot.service;
import org.springframework.security.core.userdetails.UserDetailsService;
import net.javaguides.springboot.dto.UserRegistrationDto;
import net.javaguides.springboot.model.User;
public interface UserService extends UserDetailsService {
User save(UserRegistrationDto registrationDto);
}
Create UserServiceImpl
Class
Create a UserServiceImpl
class inside the service
package:
package net.javaguides.springboot.service;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.dto.UserRegistrationDto;
import net.javaguides.springboot.model.Role;
import net.javaguides.springboot.model.User;
import net.javaguides.springboot.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
public UserServiceImpl(UserRepository userRepository) {
super();
this.userRepository = userRepository;
}
@Override
public User save(UserRegistrationDto registrationDto) {
User user = new User(registrationDto.getFirstName(),
registrationDto.getLastName(), registrationDto.getEmail(),
passwordEncoder.encode(registrationDto.getPassword()), Arrays.asList(new Role("ROLE_USER")));
return userRepository.save(user);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByEmail(username);
if (user == null) {
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), mapRolesToAuthorities(user.getRoles()));
}
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles){
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());
}
}
Step 7: Create DTO
Create UserRegistrationDto
Class
Create a UserRegistrationDto
class inside the dto
package:
package net.javaguides.springboot.dto;
public class UserRegistrationDto {
private String firstName;
private String lastName;
private String email;
private String password;
public UserRegistrationDto() {
}
public UserRegistrationDto(String firstName, String lastName, String email, String password) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
// Getters and Setters
}
Step 8: Spring Security Configuration
Create SecurityConfiguration
Class
Create a SecurityConfiguration
class inside the config
package:
package net.javaguides.springboot.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/registration**", "/js/**", "/css/**", "/img/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
Let's understand above Spring Security code, we defined a SecurityConfiguration
class for setting up security in a Spring Boot application using Spring Security 6.3. Let's break down each part of the code:
Package and Imports
package net.javaguides.springboot.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
- Package Declaration: Declares the package for the configuration class.
- Imports: Imports the necessary Spring Security and Spring Framework classes and interfaces.
Class and Annotations
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
- @Configuration: Indicates that this class contains Spring configuration.
- @EnableWebSecurity: Enables Spring Security's web security support and provides Spring MVC integration.
Fields
@Autowired
private UserDetailsService userDetailsService;
- userDetailsService: A service that provides the
UserDetails
for authentication. It is injected by Spring using the@Autowired
annotation.
Beans
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- BCryptPasswordEncoder: A bean that provides a password encoder using the BCrypt hashing function, which is a strong and secure way to store passwords.
Security Filter Chain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/registration**", "/js/**", "/css/**", "/img/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
- SecurityFilterChain: Defines the security filter chain.
- HttpSecurity: Allows configuring web-based security for specific http requests.
- authorizeHttpRequests: Configures authorization for HTTP requests.
- requestMatchers: Specifies the URL patterns that should be permitted without authentication.
- anyRequest().authenticated(): Requires authentication for any other requests.
- formLogin: Configures form-based authentication.
- loginPage("/login"): Specifies the custom login page URL.
- permitAll(): Allows access to the login page for all users.
- logout: Configures logout functionality.
- logoutUrl("/logout"): Specifies the logout URL.
- logoutSuccessUrl("/login?logout"): Redirects to the login page with a logout message after logout.
- permitAll(): Allows access to the logout functionality for all users.
- authorizeHttpRequests: Configures authorization for HTTP requests.
Global Authentication Configuration
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
- configureGlobal: Configures the global authentication manager.
- userDetailsService: Sets the custom
UserDetailsService
for authentication. - passwordEncoder: Sets the
BCryptPasswordEncoder
for encoding passwords.
- userDetailsService: Sets the custom
Step 9: Create Controller Layer
Let's create the controller layer to handle web requests.
9.1 Create EmployeeController
Class
Create the EmployeeController
class inside the controller
package:
package net.javaguides.springboot.controller;
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;
import java.util.List;
@Controller
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/")
public String viewHomePage(Model model) {
return findPaginated(1, "firstName", "asc", model);
}
@GetMapping("/showNewEmployeeForm")
public String showNewEmployeeForm(Model model) {
Employee employee = new Employee();
model.addAttribute("employee", employee);
return "new_employee";
}
@PostMapping("/saveEmployee")
public String saveEmployee(@ModelAttribute("employee") Employee employee) {
employeeService.saveEmployee(employee);
return "redirect:/";
}
@GetMapping("/showFormForUpdate/{id}")
public String showFormForUpdate(@PathVariable(value = "id") long id, Model model) {
Employee employee = employeeService.getEmployeeById(id);
model.addAttribute("employee", employee);
return "update_employee";
}
@GetMapping("/deleteEmployee/{id}")
public String deleteEmployee(@PathVariable(value = "id") long id) {
employeeService.deleteEmployeeById(id);
return "redirect:/";
}
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable(value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 5;
Page<Employee> page = employeeService.findPaginated(pageNo, pageSize, sortField, sortDir);
List<Employee> listEmployees = page.getContent();
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("listEmployees", listEmployees);
return "index";
}
}
9.2 Create UserRegistrationController
Class
Create the UserRegistrationController
class inside the controller
package:
package net.javaguides.springboot.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import net.javaguides.springboot.dto.UserRegistrationDto;
import net.javaguides.springboot.service.UserService;
@Controller
@RequestMapping("/registration")
public class UserRegistrationController {
@Autowired
private UserService userService;
@ModelAttribute("user")
public UserRegistrationDto userRegistrationDto() {
return new UserRegistrationDto();
}
@GetMapping
public String showRegistrationForm() {
return "registration";
}
@PostMapping
public String registerUserAccount(@ModelAttribute("user") UserRegistrationDto registrationDto) {
userService.save(registrationDto);
return "redirect:/registration?success";
}
}
9.3 Create MainController
Class
Create the MainController
class inside the controller
package:
package net.javaguides.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
@GetMapping("/login")
public String login() {
return "login";
}
}
Step 10: Create Thymeleaf Templates
10.1 Create index.html
Create an index.html
file inside the src/main/resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h2>Employee Management System</h2>
<div th:if="${employees != null}">
<a class="btn btn-primary mb-3" th:href="@{/showNewEmployeeForm}">Add Employee</a>
<table class="table table-bordered">
<thead>
<tr>
<th th:click="|@{/page/1(sortField='firstName',sortDir=${reverseSortDir})}|">First Name</th>
<th th:click="|@{/page/1(sortField='lastName',sortDir=${reverseSortDir})}|">Last Name</th>
<th th:click="|@{/page/1(sortField='email',sortDir=${reverseSortDir})}|">Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="employee : ${listEmployees}">
<td th:text="${employee.firstName}">First Name</td>
<td th:text="${employee.lastName}">Last Name</td>
<td th:text="${employee.email}">Email</td>
<td>
<a th:href="@{/showFormForUpdate/{id}(id=${employee.id})}">Edit</a> |
<a th:href="@{/deleteEmployee/{id}(id=${employee.id})}">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<ul class="pagination">
<li th:if="${currentPage > 1}">
<a class="page-link" th:href="@{/page/{pageNo}(pageNo=${currentPage - 1})}">Previous</a>
</li>
<li th:each="i : ${#numbers.sequence(1, totalPages)}"
th:classappend="${i == currentPage} ? 'active'">
<a class="page-link" th:href="@{/page/{pageNo}(pageNo=${i})}" th:text="${i}">1</a>
</li>
<li th:if="${currentPage < totalPages}">
<a class="page-link" th:href="@{/page/{pageNo}(pageNo=${currentPage + 1})}">Next</a>
</li>
</ul>
</div>
</div>
</body>
</html>
10.2 Create new_employee.html
Create a new_employee.html
file inside the src/main/resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h2>Add Employee</h2>
<form th:action="@{/saveEmployee}" th:object="${employee}" method="post">
<div class="form-group">
<label>First Name</label>
<input type="text" class="form-control" th:field="*{firstName}" placeholder="First Name"/>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" th:field="*{email}" placeholder="Email"/>
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</body>
</html>
10.3 Create update_employee.html
Create an update_employee.html
file inside the src/main/resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h2>Update Employee</h2>
<form th:action="@{/saveEmployee}" th:object="${employee}" method="post">
<div class="form-group">
<label>First Name</label>
<input type="text" class="form-control" th:field="*{firstName}" placeholder="First Name"/>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" th:field="*{email}" placeholder="Email"/>
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</body>
</html>
10.4 Create registration.html
Create a registration.html
file inside the src/main/resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>User Registration</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h2>User Registration</h2>
<form th:action="@{/registration}" th:object="${user}" method="post">
<div class="form-group">
<label>First Name</label>
<input type="text" class="form-control" th:field="*{firstName}" placeholder="First Name"/>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" th:field="*{email}" placeholder="Email"/>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" th:field="*{password}" placeholder="Password"/>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</body>
</html>
10.5 Create login.html
Create a login.html
file inside the src/main/resources/templates
directory:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Login</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h2>Login</h2>
<form th:action="@{/login}" method="post">
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid username or password.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-info">You have been logged out.</div>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" name="username" placeholder="Email" required autofocus/>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="Password" required/>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<div>
<span>New user? <a th:href="@{/registration}">Register here</a></span>
</div>
</div>
</body>
</html>
Step 11: Run the Spring Boot Application
We’ve successfully built our employee management system application. Let's run our Spring Boot application and test it.
Navigate to the root directory of the application and run the following command:
$ mvn spring-boot:run
The application will start at Spring Boot’s default Tomcat port 8080
.
Step 12: YouTube Video Series
You can develop this project from scratch using line-by-line coding from my YouTube videos.
Employee Management Module
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 1
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 2
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 3
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 4
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 5
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 6
- Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 7
Registration and Login Module
- Registration and Login with Spring Boot and Spring Security - PART 1
- Registration and Login with Spring Boot and Spring Security - PART 2
- Registration and Login with Spring Boot and Spring Security - PART 3
- Registration and Login with Spring Boot and Spring Security - PART 4
- Registration and Login with Spring Boot and Spring Security - PART 5
- Registration and Login with Spring Boot and Spring Security - PART 6
- Registration and Login with Spring Boot and Spring Security - PART 7
- Registration and Login with Spring Boot and Spring Security - PART 8
Conclusion
This tutorial demonstrated how to create a complete Employee Management System using Spring Boot 3, Spring MVC, Spring Security 6, Thymeleaf, and MySQL. We covered everything from setting up the Spring Boot project, configuring Spring Security, creating the service and repository layers, and building the Thymeleaf templates. By following this guide, you can build a robust and secure employee management application.
Comments
Post a Comment
Leave Comment