Spring Boot Real-Time Project Development using Spring MVC + Spring Security + Thymeleaf and MySQL Database
In this tutorial, we will build an Employee Management System project from scratch using Spring Boot, Spring MVC, Spring Security, Thymeleaf, and MySQL database.
Spring Boot is an opinionated framework that helps developers build stand-alone and production-grade Spring-based applications quickly and easily.
Employee Management System Project
- List Employee Feature
- Add Employee Feature
- Update Employee Feature
- Delete Employee Feature
- Pagination Feature
- Sorting Feature
- Login Feature
- Registration Feature
- Logout Feature
GitHub link: https://github.com/RameshMF/employee-management-webapp
Tools and technologies used:
- Java 8+
- Spring Boot
- Spring Data JPA ( Hibernate)
- Spring Security
- MySQL
- Eclipse STS
- Maven
- Tomcat
- Thymeleaf
Let's create a Spring boot application step by step to build Employee Management System Project.
1. Create Spring Boot Project
Spring Boot provides a web tool called Spring Initializer to bootstrap an application quickly. Just go to https://start.spring.io/ and generate a new spring boot project.
Use the below details in the Spring boot creation:
Project Name: employee-management-webapp
Project Type: Maven
Choose dependencies: Spring Web, Spring Data JPA, MySQL Driver, Spring Security, Thymeleaf, Dev Tools
Package name: net.javaguides.springboot
2. Maven Dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>employee-management-webapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>employee-management-webapp</name>
<description>Demo project for Spring Boot Thymeleaf and Hibernate </description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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-springsecurity5</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</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Configure MySQL Database
Spring Boot tries to auto-configure a DataSource if spring-data-jpa dependency is in the classpath by reading the database configuration from the application.properties file.
So, we just have to add the configuration, and Spring Boot will take care of the rest.
Open the application.properties file and add the following properties to it.
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# 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 & spring.datasource.password properties as per your MySQL installation.
In the above properties file, the last two properties are for Hibernate. Spring Boot uses Hibernate as the default JPA implementation.
The property spring.jpa.hibernate.ddl-auto is used for database initialization. I’ve used the value “update” for this property.
4. Create Models
4.1 Model - Employee Class
package net.javaguides.springboot.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@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;
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;
}
}
4.2 Model - User Class
package net.javaguides.springboot.model;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.JoinColumn;
@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;
public User() {
}
public User(String firstName, String lastName, String email, String password, Collection<Role> roles) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.roles = roles;
}
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;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Collection<Role> getRoles() {
return roles;
}
public void setRoles(Collection<Role> roles) {
this.roles = roles;
}
}
4.2 Model - Role Class
package net.javaguides.springboot.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Role() {
}
public Role(String name) {
super();
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5. Create Repository or DAO Layer
5.1 EmployeeRepository
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
5.2 UserRepository
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.model.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long>{
User findByEmail(String email);
}
6. Create Service Layer
6.1 Service Interface - EmployeeService
Let's create an EmployeeService interface inside the service package with the following contents:
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);
}
6.2 Service Interface Implementation - EmployeeServiceImpl
Let's create an EmployeeServiceImpl class inside the service package with the following contents:
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);
}
}
6.3 Service Interface - UserService
Let's create an UserService interface inside the service package with the following contents:
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);
}
6.3 Service Interface Implementation - UserServiceImpl
Let's create an UserServiceImpl class inside the service package with the following contents:
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());
}
}
7. Create DTO - UserRegistrationDto
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;
}
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;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
8. Spring Security Configuration
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.authentication.dao.DaoAuthenticationProvider;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import net.javaguides.springboot.service.UserService;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
}
}
9. Create Controller Layer
9.1 EmployeeController
package net.javaguides.springboot.controller;
import java.util.List;
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;
@Controller
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
// display list of employees
@GetMapping("/")
public String viewHomePage(Model model) {
return findPaginated(1, "firstName", "asc", model);
}
@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";
}
@PostMapping("/saveEmployee")
public String saveEmployee(@ModelAttribute("employee") Employee employee) {
// save employee to database
employeeService.saveEmployee(employee);
return "redirect:/";
}
@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";
}
@GetMapping("/deleteEmployee/{id}")
public String deleteEmployee(@PathVariable (value = "id") long id) {
// call delete employee method
this.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 MainController
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";
}
/*
* @GetMapping("/") public String home() { return "index"; }
*/
}
9.3 UserRegistrationController
package net.javaguides.springboot.controller;
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 {
private UserService userService;
public UserRegistrationController(UserService userService) {
super();
this.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";
}
}
10. View Layer
resources/templates/index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
</head>
<body>
<!-- create navigation bar ( header) -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Employee Management System</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li sec:authorize="isAuthenticated()"><a th:href="@{/logout}">Logout</a></li>
</ul>
</div>
</div>
</nav>
<br>
<br>
<div class="container my-2">
<h1>Employees List</h1>
<a th:href = "@{/showNewEmployeeForm}" class="btn btn-primary btn-sm mb-3"> Add Employee </a>
<table border="1" class = "table table-striped table-responsive-md">
<thead>
<tr>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=firstName&sortDir=' + ${reverseSortDir}}">
Employee First Name</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=lastName&sortDir=' + ${reverseSortDir}}">
Employee Last Name</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=email&sortDir=' + ${reverseSortDir}}">
Employee Email</a>
</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="@{/showFormForUpdate/{id}(id=${employee.id})}" class="btn btn-primary">Update</a>
<a th:href="@{/deleteEmployee/{id}(id=${employee.id})}" class="btn btn-danger">Delete</a>
</td>
</tr>
</tbody>
</table>
<div th:if = "${totalPages > 1}">
<div class = "row col-sm-10">
<div class = "col-sm-2">
Total Rows: [[${totalItems}]]
</div>
<div class = "col-sm-1">
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
<a th:if="${currentPage != i}" th:href="@{'/page/' + ${i}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">[[${i}]]</a>
<span th:unless="${currentPage != i}">[[${i}]]</span>
</span>
</div>
<div class = "col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${currentPage + 1}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Next</a>
<span th:unless="${currentPage < totalPages}">Next</span>
</div>
<div class="col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Last</a>
<span th:unless="${currentPage < totalPages}">Last</span>
</div>
</div>
</div>
</div>
</body>
</html>
resources/templates/new_employee.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Employee Management System</h1>
<hr>
<h2>Save Employee</h2>
<form action="#" th:action="@{/saveEmployee}" th:object="${employee}"
method="POST">
<input type="text" th:field="*{firstName}"
placeholder="Employee First Name" class="form-control mb-4 col-4">
<input type="text" th:field="*{lastName}"
placeholder="Employee Last Name" class="form-control mb-4 col-4">
<input type="text" th:field="*{email}"
placeholder="Employee Email" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Save Employee</button>
</form>
<hr>
<a th:href = "@{/}"> Back to Employee List</a>
</div>
</body>
</html>
resources/templates/update_employee.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Employee Management System</h1>
<hr>
<h2>Update Employee</h2>
<form action="#" th:action="@{/saveEmployee}" th:object="${employee}"
method="POST">
<!-- Add hidden form field to handle update -->
<input type="hidden" th:field="*{id}" />
<input type="text" th:field="*{firstName}" class="form-control mb-4 col-4">
<input type="text" th:field="*{lastName}" class="form-control mb-4 col-4">
<input type="text" th:field="*{email}" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Update Employee</button>
</form>
<hr>
<a th:href = "@{/}"> Back to Employee List</a>
</div>
</body>
</html>
resources/templates/registration.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Registration</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
</head>
<body>
<!-- create navigation bar ( header) -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Employee Management System</a>
</div>
</div>
</nav>
<br>
<br>
<!-- Create HTML registration form -->
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<!-- success message -->
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our awesome app!</div>
</div>
<h1>Registration</h1>
<form th:action="@{/registration}" method="post" th:object="${user}">
<div class="form-group">
<label class="control-label" for="firstName"> First Name </label>
<input id="firstName" class="form-control" th:field="*{firstName}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="lastName"> Last Name </label> <input
id="lastName" class="form-control" th:field="*{lastName}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="email"> Email </label> <input
id="email" class="form-control" th:field="*{email}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="password"> Password </label> <input
id="password" class="form-control" type="password"
th:field="*{password}" required autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
resources/templates/login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Registration and Login App</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
</head>
<body>
<!-- create navigation bar ( header) -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Employee Management System</a>
</div>
</div>
</nav>
<br>
<br>
<div class = "container">
<div class = "row">
<div class = "col-md-6 col-md-offset-3">
<h1> Sign-in </h1>
<form th:action="@{/login}" method="post">
<!-- error message -->
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid username or
password.</div>
</div>
<!-- logout message -->
<div th:if="${param.logout}">
<div class="alert alert-info">You have been logged out.</div>
</div>
<div class = "form-group">
<label for ="username"> Username </label> :
<input type="text" class = "form-control" id ="username" name = "username"
placeholder="Enter Email ID" autofocus="autofocus">
</div>
<div class="form-group">
<label for="password">Password</label>: <input type="password"
id="password" name="password" class="form-control"
placeholder="Enter Password" />
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit" name="login-submit" id="login-submit"
class="form-control btn btn-primary" value="Log In" />
</div>
</div>
</div>
</form>
<div class="form-group">
<span>New user? <a href="/" th:href="@{/registration}">Register
here</a></span>
</div>
</div>
</div>
</div>
</body>
</html>
11. Run Spring Boot Application
We’ve successfully built our employee management system application. Let's run our spring boot application and test it.
Just go to the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
The application will start at Spring Boot’s default tomcat port 8080.
Comments
Post a Comment