Open In App

Appointment Scheduling System in Spring Boot

Last Updated : 20 Jun, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

The Appointment Scheduling System includes operations such as sending your appointment request to the admin. By providing the required details for each appointment request, a random string with the prefix "RQ" is created for tracing your appointment. In this article, we explain the Appointment Scheduling System in Spring Boot. In this web application, you can send appointment requests to the admin by providing user details and other necessary information to confirm the appointment.

This application also provides alert messages based on the appointment status, such as booked or pending, depending on the application's status.

Application Functionality:

  • Create User Account: The User can create their account by providing user details like username, email, and password
  • User Login: The User can log in by using the user credentials email and password.
  • Book Appointment: The End User can request for appointment by providing the required details.
  • Admin Login: The Admin can log in using user credentials email and password.
  • View all appointments as Admin: As admin we can able seen all the requested appointments data in the form of table
  • Search Appointment: By using Appointment Request Id we can track our application by using search feature
  • Random Appointment Request ID generation: For every appointment request we created a unique ID for tracing the appointment request. Here we use RD as prefix the suffix is 5 digit number which is random number.
  • Appointment Categories: Here we provide a feature to show how many appointments are booked and how many are in pending.

Below we provide required information with related examples.

Prerequisites:

To understand this Appointment Scheduling System in Spring Boot, you need basic knowledge of below technologies:

  • Spring Boot
  • Thymeleaf
  • MongoDB
  • Other Spring MVC Patterns
  • Bootstrap Framework

The Spring Boot is used for creating web applications with MVC pattern, Thymeleaf is used for generating dynamic HTML content in the web pages as well and the main purpose is integrating the HTML pages with Spring framework, and MongoDB is used for Data Storage.

Appointment Data

In this Appointment Scheduling System, we collected end user Appointment data with different fields like below we mention those fields.

  • User Name
  • Email
  • Phone
  • Address
  • Appointment Id
    • It is Random Id with prefix RQXXXXX
  • Service Type
    • Interview
    • Professional
    • Career Coaching
    • Others
  • Appointment Date
  • Appointment Duration
    • 30 min
    • 45 min
    • 60 min
    • 120 min
  • Status
    • Booked
    • Pending

The Appointment ID is Dynamically Created with prefix RQ with followed by five digits. In the Appointment Scheduling System, we have used the Bootstrap framework for responsive web designing and used models. The Bootstrap Model is Dynamic html Content, when clicking on the button dynamically the Model is opened.

Example Appointment ID:
RQ15154

User Data:

For creating user account we need user details. Below we mention them.

  • username
  • email
  • password

User Data:

  • username
  • email
  • password

Project Steps:

  • Create a Spring Stater Project
  • create packages for controller, POJO, repository in main application package.
  • Now Implement the Controller layer code, after that POJO class and other one interface also we need to implement.
  • Once completed the back-end functionalities, then develop the Front-End web pages.
  • After that Integrate both Back-End and Front-End by using Thymeleaf.
  • After that Run the entire project as Spring Boot App

Dependencies

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

Note: These Project Dependencies are available in build.gradle file once project is created. For this Project, we have used these Dependencies.

Project Folder Structure


Folder Structure


Now we will explain the coding part in different layers, such as the Controller layer, Repository, POJO classes, and other components. First, we start with the actual requirement, which is to perform some operations on user appointment details. Before performing operations on user details, we need employee details. So, we gather some details and then declare these fields in a POJO class to perform setter and getter operations for each field.

Database Connection

spring.application.name=AppointmentSchedulingSystem

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=appdb

spring.thymeleaf.mode=LEGACYHTML5

# thymeleaf configuration
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

Model Layer

The Employee.java comes under Model Layer which is used to controller the data flow in the application using these pojo classes in this project.

User.java

This Domain class is used for creating user as well as longing the user.

Java
package com.app;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "users")
public class User {
    @Id
    private String id;
    private String username;
    private String email;
    private String password;
}


Admin.java

This Domain class is used for creating admin login.

Java
package com.app;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "admins")
public class Admin {
    @Id
    private String id;
    private String username;
    private String email;
    private String password;
}


Appointment.java

Appointment.java is the class which contains all the details of Appointment Scheduling and setters and getters methods for every field in the Appointment java class as well as parameterized constructor and one default constructor we used in this POJO for different operations like data insertion and data update and data delete and others. And one dependency is available in spring boot that is lombok.

Java
package com.app;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "appointmentdata")
public class Appointment {
    @Id
    private String id;
    
    private String userName;
    private String email;
    private String phone;
    private String address;
    private String appointmentId;
    private String serviceType;
    private String appointmentDate;
    private String appointmentDuration;
    private String status;
}


View Layer

Generally the HTML, JSP, and other front-end technologies are comes under View layer in Spring MVC. For this Appointment Scheduling System in Spring Boot we used HTML as a View for displaying the Data to end users with the help of Thymeleaf. In this HTML page, we created four Dynamic forms for handling the Application from front-end. every page performs a unique operation based on its use.

home.html:

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn-icons-png.flaticon.com/512/3301/3301556.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>Appointment system</title>
</head>

<style>
    nav {
        background-color: rgb(5, 182, 5);
    }

    .navbar-brand {
        font-weight: bold;
        color: white !important;
    }

    .head1,
    .fa {
        color: rgb(5, 182, 5);
        font-weight: bold;
    }

    form {
        border-radius: 4px !important;
        max-width: 1200px;
        height: auto;
        margin: auto;
        border: 1px solid rgb(5, 182, 5) !important;
    }

    label {
        text-align: left !important;
        color: black;
        font-weight: 500;
        margin-bottom: 5px;
    }

    .btn {
        background-color: rgb(5, 182, 5) !important;
        font-weight: 600;
    }

    #dashboard_link,
    #appointment_status_link {

        text-align: center;
        color: rgb(5, 182, 5) !important;
        background-color: white !important;
    }
</style>

<body>
    <nav class="navbar navbar-expand-sm navbar-light">
        <div class="container">
            <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                Appointment System</a>
            <div class="ml-auto">
                <a th:href="@{/admin/login}" class="btn" type="button" id="dashboard_link"><i
                        class="fa fa-user-circle-o" aria-hidden="true"></i> Admin</a>&nbsp;&nbsp;
                <a th:href="@{/user/login}" class="btn" type="button" id="appointment_status_link"><i
                        class="fa fa-users" aria-hidden="true"></i> User</a>&nbsp;&nbsp;
                <a th:href="@{/search}" class="btn" type="button" id="appointment_status_link"><i
                        class="fa fa-search" aria-hidden="true"></i> Search</a>
            </div>
        </div>
    </nav>


    <main>
        <div class="container">
            <h1 class="text text-center p-5" style="font-weight: bold; color: rgb(5, 182, 5);">Book Your Appointment</h1>
        </div>
    </main>


</body>

</html>


Output:

Below is the Home screen of our Appointment Scheduling System.

Home Screen


User Registration

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn.pixabay.com/photo/2017/06/10/07/22/news-2389226_960_720.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>Appointment System</title>
</head>

<style>
    nav,
    #login_btn {
        background-color: rgb(5, 182, 5);
    }

    .navbar-brand {
        font-weight: bold;
        color: white !important;

    }

    form {
        border-radius: 4px !important;
        box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px 0px, rgba(0, 0, 0, 0.1) 0px 0px 1px 0px;
        max-width: 390px;
        height: auto;
        margin: auto;
    }
</style>

<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-light">
            <div class="container">
                <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                    Appointment System</a>
                <div class="ml-auto">
                    <a th:href="@{/}" class="btn" type="button" id="dashboard_link" style="color: white;"><i class="fa fa-home"
                            aria-hidden="true"></i> Home</a>&nbsp;&nbsp;
                </div>
            </div>
        </nav>
    </header>

    <main>
        <div class="container p-5">
            <div class="d-flex justify-content-center">

                <form th:action="@{/user/create}" method="post" class="form-control p-4">
                    <center><i class="fa fa-newspaper-o fa-4x" aria-hidden="true"></i></center>
                    <h5 class="text text-center" style="color: rgb(5, 182, 5); font-weight: bolder;">Create User Account
                    </h5>
                    <div th:if="${success}" class="alert alert-success alert-dismissible fade show" role="alert">
                        <strong><span th:text="${success}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>

                    <div th:if="${exist}" class="alert alert-warning alert-dismissible fade show" role="alert">
                        <strong><span th:text="${exist}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>

                    <div th:if="${error}" class="alert alert-danger alert-dismissible fade show" role="alert">
                        <strong><span th:text="${error}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>

                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-user-o" aria-hidden="true"></i> User Name</label> <input
                            type="text" id="name" name="name" class="form-control" required>
                    </div>
                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-envelope" aria-hidden="true"></i> Email</label> <input
                            type="text" id="email" name="email" class="form-control" required>
                    </div>

                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-lock" aria-hidden="true"></i> Password</label>
                        <input type="text" id="password" name="password" class="form-control" required>
                    </div>
                    <button class="btn mt-2 mb-2 text-white" id="login_btn" style="font-weight: 700;">Create
                        Account</button>
                    <br>
                    <h6 class="text text-center text-bold mt-4">I have an account <a th:href="@{/user/login}">Login</a>
                    </h6>
                </form>
            </div>
        </div>
    </main>
</body>

</html>


Output:

Below is the output screen of User Registration, where a user can register himself by filling Name, email id, and password.

User Registration


User Login

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn.pixabay.com/photo/2017/06/10/07/22/news-2389226_960_720.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>News Reader App</title>
</head>

<style>
    nav,
    #login_btn {
        background-color: rgb(5, 182, 5);
    }

    .navbar-brand {
        font-weight: bold;
        color: white !important;

    }

    form {
        border-radius: 4px !important;
        box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px 0px, rgba(0, 0, 0, 0.1) 0px 0px 1px 0px;
        max-width: 390px;
        height: auto;
        margin: auto;
    }
</style>

<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-light">
            <div class="container">
                <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                    Appointment System</a>
                <div class="ml-auto">
                    <a th:href="@{/}" class="btn" type="button" id="dashboard_link"
                        style="color: white; font-weight: 600;"><i class="fa fa-home" aria-hidden="true"
                            style="color: white;"></i> Home</a>&nbsp;&nbsp;
                </div>
            </div>
        </nav>
    </header>

    <main>
        <div class="container p-5">
            <div class="d-flex justify-content-center">

                <form th:action="@{/user/login}" method="post" class="form-control p-4">
                    <center><i class="fa fa-newspaper-o fa-4x" aria-hidden="true"
                            style="color: rgb(5, 182, 5); font-weight: bolder;"></i></center>
                    <h5 class="text text-center" style="color: rgb(5, 182, 5); font-weight: bolder;">User Account</h5>
                    
                    <div th:if="${error}" class="alert alert-warning alert-dismissible fade show" role="alert">
                        <strong><span th:text="${error}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>
                    
                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-envelope" aria-hidden="true"></i> Email</label> <input
                            type="text" id="email" name="email" class="form-control" required>
                    </div>

                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-lock" aria-hidden="true"></i> Password</label>
                        <input type="text" id="password" name="password" class="form-control" required>
                    </div>
                    <button class="btn mt-2 mb-2 text-white" id="login_btn" style="font-weight: 700;">login</button>
                    <br>
                    <h6 class="text text-center text-bold mt-4">I don't have an account <a
                            th:href="@{/user/create}">Create Account</a></h6>
                </form>
            </div>
        </div>
    </main>
</body>

</html>


Output:

User can log in by providing email id and password as we can see below:

User Login


appointment.html:

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn-icons-png.flaticon.com/512/3301/3301556.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>Appointment system</title>
</head>

<style>
    nav {
        background-color: rgb(5, 182, 5);
    }

    .navbar-brand {
        font-weight: bold;
        color: white !important;
    }

    .head1,
    .fa {
        color: rgb(5, 182, 5);
        font-weight: bold;
    }

    form {
        border-radius: 4px !important;
        max-width: 1200px;
        height: auto;
        margin: auto;
        border: 1px solid rgb(5, 182, 5) !important;
    }

    label {
        text-align: left !important;
        color: black;
        font-weight: 500;
        margin-bottom: 5px;
    }

    .btn {
        background-color: rgb(5, 182, 5) !important;
        font-weight: 600;
    }

    #dashboard_link,
    #appointment_status_link {
        
        text-align: center;
        color: rgb(5, 182, 5) !important;
        background-color: white !important;
    }
</style>

<body>
    <nav class="navbar navbar-expand-sm navbar-light">
        <div class="container">
            <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                Appointment System</a>
            <div class="ml-auto">
                <a th:href="@{/user/login}" class="btn" type="button" id="dashboard_link"><i class="fa fa-sign-out" aria-hidden="true"></i> logout</a>&nbsp;&nbsp;
            </div>
        </div>
    </nav>


    <main>
        <div class="container p-3 mt-3">
        <h2 class="text p-2 text-center">Book Your Appointment</h2>
            <div class="d-flex justify-content-center">
            
                <form th:action="@{/appointment}" method="post" class="form-control p-4 mt-4">

                    <div th:if="${success}" class="alert alert-success alert-dismissible fade show" role="alert">
                        <strong><span th:text="${success}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>

                    <div th:if="${error}" class="alert alert-danger alert-dismissible fade show" role="alert">
                        <strong><span th:text="${error}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>

                    <div class="row">
                        <div class="col-sm-6">
                            <div class="mb-3">
                                <label for=""><i class="fa fa-user"></i> User Name</label>
                                <input type="text" name="userName" class="form-control" id="" required>
                            </div>
                            <div class="mb-3">
                                <label for=""><i class="fa fa-envelope"></i> Email Address</label>
                                <input type="text" name="email" class="form-control" id="" required>
                            </div>
                            <div class="mb-3">
                                <label for=""><i class="fa fa-phone"></i> Phone Number</label>
                                <input type="text" name="phone" class="form-control" id="" required>
                            </div>
                            <div class="mb-3">
                                <label for="">Address</label>
                                <textarea name="address" id="" cols="30" rows="1" class="form-control" required></textarea>
                            </div>
                        </div>
                        <div class="col-sm-6">
                            
                            <div class="mb-3">
                                <label for="">ServiceType</label>
                                <select id="role" class="form-control form-select" name="serviceType" required>
                            <option>select service</option>
                            <option value="interview">Interview</option>
                            <option value="professional">Professional</option>
                            <option value="Career Coaching">Career Coaching</option>
                            <option value="others">Others</option>
                        </select>
                            </div>
                            <div class="mb-3">
                                <label for=""><i class="fa fa-clock-o"></i> Appointment Date</label>
                                <input type="date" name="appointmentDate" class="form-control" id="" required>
                            </div>

                            <div class="mb-3">
                                <label for="">Required Time</label>
                            <select id="role" class="form-control form-select" name="appointmentDuration" required>
                            <option>select duration</option>
                            <option value="30">30 min</option>
                            <option value="45">45 min</option>
                            <option value="60">60 min</option>
                            <option value="120">2 hours</option>
                        </select>
                            </div>
                            <div class="mb-3">
                                <label for=""><i class="fa fa-check"></i> Status</label>
                                <input type="text" name="status" class="form-control"  id="status">
                            </div>
                        </div>
                    </div>

                    <div class="row p-2 mt-2 mb-3">
                        <button class="btn text-light" type="submit">Book Appointment</button>
                    </div>
                </form>
            </div>
        </div>
    </main>

<script>
        // Define the possible statuses
        const statuses = ["booked", "pending"];

        // Function to get a random status
        function getRandomStatus() {
            const randomIndex = Math.floor(Math.random() * statuses.length);
            return statuses[randomIndex];
        }

        // Set the random status to the input field
        document.getElementById('status').value = getRandomStatus();
    </script>
</body>

</html>


Output:

Below is the window where users can book their appointment by filling all the details.

Appointment Booking Screen


Admin Login:

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn.pixabay.com/photo/2017/06/10/07/22/news-2389226_960_720.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>News Reader App</title>
</head>

<style>
    nav, #login_btn {
        background-color: rgb(5, 182, 5);
    }
    .navbar-brand{
        font-weight: bold;
        color: white !important;

    }
    form {
        border-radius: 4px !important;
        box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px 0px, rgba(0, 0, 0, 0.1) 0px 0px 1px 0px;
        max-width: 390px;
        height: auto;
        margin: auto;
    }
        
</style>

<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-light">
        <div class="container">
            <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                Appointment System</a>
            <div class="ml-auto">
                <a th:href="@{/}" class="btn" type="button" id="dashboard_link" style="color: white;"><i class="fa fa-home"
                        aria-hidden="true"></i> Home</a>&nbsp;&nbsp;
            </div>
        </div>
    </nav>
    </header>

    <main>
        <div class="container p-5">
            <div class="d-flex justify-content-center">
                
                <form th:action="@{/admin/login}" method="post" class="form-control p-4">
                    <center><i class="fa fa-newspaper-o fa-4x" aria-hidden="true" style="color: rgb(5, 182, 5); font-weight: bolder;"></i></center>
                    <h5 class="text text-center" style="color: rgb(5, 182, 5); font-weight: bolder;">Admin Account</h5>
                    <div th:if="${error}" class="alert alert-warning alert-dismissible fade show" role="alert">
                        <strong><span th:text="${error}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>
                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-envelope" aria-hidden="true"></i> Email</label> <input
                            type="text" id="email" name="email" class="form-control" required>
                    </div>

                    <div class="mb-2 mt-4">
                        <label for="email"><i class="fa fa-lock" aria-hidden="true"></i> Password</label>
                        <input type="text" id="password" name="password" class="form-control" required>
                    </div>
                    <button class="btn mt-2 mb-2 text-white" id="login_btn" style="font-weight: 700;">login</button>
                    
                </form>
            </div>
        </div>
    </main>
</body>

</html>


Output:

Below is the window of Admin login, where admin of the system can login by providing his/her email id and password.

Admin login


dashboard.html

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
    <link rel="shortcut icon" href="https://cdn-icons-png.flaticon.com/512/3301/3301556.png">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <meta charset="UTF-8">
    <title>Appointment system</title>
</head>

<style>
    nav,thead {
        background-color: rgb(5, 182, 5);
    }

    .navbar-brand {
        font-weight: bold;
        color: white !important;
    }

    .head1,
    .fa {
        color: rgb(5, 182, 5);
        font-weight: bold;
    }

    form {
        border-radius: 4px !important;
        max-width: 1000px;
        height: auto;
        margin: auto;
        border: 1px solid rgb(5, 182, 5) !important;
    }

    label {
        text-align: left !important;
        color: black;
        font-weight: 500;
        margin-bottom: 5px;
    }

    .btn {
        background-color: rgb(5, 182, 5) !important;
        font-weight: 600;
    }

    #dashboard_link {
        text-align: center;
        color: rgb(5, 182, 5) !important;
        background-color: white !important;
    }
</style>

<body>
    <nav class="navbar navbar-expand-sm navbar-light">
        <div class="container">
            <a class="navbar-brand" href="#"><i class="fa fa-files-o" aria-hidden="true" style="color: white;"></i>
                Appointment System</a>
            <div class="ml-auto">
                <a th:href="@{/admin/login}" class="btn" type="button" id="dashboard_link"><i class="fa fa-sign-out" aria-hidden="true"></i> logout</a>&nbsp;&nbsp;
            </div>
        </div>
    </nav>


    <main>
        <div class="container p-3 mt-3">
            <div class="analysis mt-5 mb-4 p-5" style="background-color: rgb(235, 241, 235);">
                <div class="row row-cols-1 row-cols-md-3 g-4">
                    <div class="col">
                        <div class="card bg-dark">
                            <div class="card-body text-center text-light">
                                <h5 style="color: white;"><i class="fa fa-folder text-light"></i> Total Appointment</h5>
                                <h2 class="text text-center text-light" th:text="${totalAppointments}"></h2>
                            </div>
                        </div>
                    </div>
                    <div class="col">
                        <div class="card bg-primary">
                            <div class="card-body text-center text-light">
                                <h5 style="color: white;"><i class="fa fa-check text-light"></i> Total Booked</h5>
                                <h2 class="text text-center text-light" th:text="${totalBooked}"></h2>
                            </div>
                        </div>
                    </div>
                    <div class="col">
                        <div class="card bg-warning">
                            <div class="card-body text-center text-light">
                                <h5 style="color: white;"><i class="fa fa-clock-o text-light"></i> Total Pendings</h5>
                                <h2 class="text text-center text-light" th:text="${totalPending}"></h2>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <br>
        <div class="container">
            <div class="table-responsive">
                <table class="table table-bordered">
                    <thead class="text text-light">
                        <th>SI.NO</th>
                        <th>User Name</th>
                        <th>Email</th>
                        <th>Phone</th>
                        <th>Address</th>
                        <th>Appointment ID</th>
                        <th>ServiceType</th>
                        <th>Appointment Date</th>
                        <th>Required Time</th>
                        <th>Status</th>
                    </thead>
                    <tbody>
                        <tr th:each="appointment, stat : ${appointments}">
                            <td th:text="${stat.count}"></td>
                            <td th:text="${appointment.userName}"></td>
                            <td th:text="${appointment.email}"></td>
                            <td th:text="${appointment.phone}"></td>
                            <td th:text="${appointment.address}"></td>
                            <td th:text="${appointment.appointmentId}"></td>
                            <td th:text="${appointment.serviceType}"></td>
                            <td th:text="${appointment.appointmentDate}"></td>
                            <td th:text="${appointment.appointmentDuration}"></td>
                            <td th:text="${appointment.status}"></td>
                        </tr>
                        <tr th:if="${appointments.size() == 0}">
                            <td colspan="11" class="text-center text-danger"><h6>No Data Available</h6></td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>

    </main>

</body>

</html>


Output:

Below is the appointment dashboard window, where we can see the total appointments, total booked appointments, and total number of pending appointments.

Appointment dashboard

search.html:

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
<link
    href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    rel="stylesheet">
<link rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<link rel="shortcut icon"
    href="https://cdn-icons-png.flaticon.com/512/3301/3301556.png">
<script
    src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<meta charset="UTF-8">
<title>Appointment system</title>
</head>

<style>
nav {
    background-color: rgb(5, 182, 5);
}

.navbar-brand {
    font-weight: bold;
    color: white !important;
}

.head1, .fa {
    color: rgb(5, 182, 5);
    font-weight: bold;
}

form {
    border-radius: 4px !important;
    max-width: 1000px;
    height: auto;
    margin: auto;
    border: 1px solid rgb(5, 182, 5) !important;
}

label {
    text-align: left !important;
    color: black;
    font-weight: 500;
    margin-bottom: 5px;
}

.btn {
    background-color: rgb(5, 182, 5) !important;
    font-weight: 600;
}

#dashboard_link {
    text-align: center;
    color: rgb(5, 182, 5) !important;
    background-color: white !important;
}
</style>

<body>
    <nav class="navbar navbar-expand-sm navbar-light">
        <div class="container">
            <a class="navbar-brand" href="#"><i class="fa fa-files-o"
                aria-hidden="true" style="color: white;"></i> Appointment System</a>
            <div class="ml-auto">
                <a th:href="@{/}" class="btn" type="button" id="dashboard_link"><i
                    class="fa fa-home" aria-hidden="true"></i> Home</a>&nbsp;&nbsp;
            </div>
        </div>
    </nav>


    <main>
        <div class="container p-3 mt-3">
            <div class="d-flex justify-content-center">
                <form th:action="@{/search}" method="post"
                    class="form-control p-3 mt-3">

                    <div th:if="${error}"
                        class="alert alert-danger alert-dismissible fade show"
                        role="alert">
                        <strong><span th:text="${error}"></span></strong>
                        <button type="button" class="btn-close" data-bs-dismiss="alert"
                            aria-label="Close"></button>
                    </div>

                    <div class="mb-3">
                        <label for="appointmentId" class="mb-2">Appointment ID</label> <input
                            type="text" name="appointmentId" class="form-control"
                            id="appointmentId" required>
                    </div>

                    <div class="row p-2 mt-2 mb-3">
                        <button class="btn text-light" type="submit">Search
                            Appointment</button>
                    </div>
                </form>
            </div>
            <br>
            <div class="table-responsive" th:if="${appointment != null}">
                <table class="table table-bordered mt-5">
                    <thead>
                        <tr>
                            <th>Appointment ID</th>
                            <th>Service Type</th>
                            <th>Appointment Date</th>
                            <th>Duration</th>
                            <th>Status</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr th:if="${appointment != null}">
                            <td th:text="${appointment.appointmentId}"></td>
                            <td th:text="${appointment.serviceType}"></td>
                            <td th:text="${appointment.appointmentDate}"></td>
                            <td th:text="${appointment.appointmentDuration}"></td>
                            <td th:text="${appointment.status}"></td>
                        </tr>
                        
                    </tbody>
                </table>
            </div>

        </div>
    </main>
</body>

</html>


Output:

Below is the window, where we can search the appointment details by providing the Appointment Id.

8


Control Layer

The Controller layer is created using the @Controller annotation in Spring Boot. The Controller class is used for processing incoming API requests, preparing the model, and returning the view to be rendered as a response. In this Controller class, we create the entire project logic. We will explain everything in this layer by dividing it into small pieces.

UserRepo.java:

Java
package com.app;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Repository;

@Repository
@EnableMongoRepositories
public interface UserRepo extends MongoRepository<User, String> {

    String findByEmail(String email);

    User findByEmailAndPassword(String email, String password);

}


AdminRepo.java:

Java
package com.app;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Repository;

@Repository
@EnableMongoRepositories
public interface AdminRepo extends MongoRepository<Admin, String> {

    Admin findByEmailAndPassword(String email, String password);

}


AppointmentRepo.java

In this project, we created one Mongo Repository for performing CRUD operations. The @Repository annotation is used for creating the Mongo Repository. It is possible to perform all CRUD operations using a Java interface. This interface extends MongoRepository.

Java
package com.app;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AppointmentRepo extends MongoRepository<Appointment, String>{

    long countByStatus(String status);

    Appointment findByAppointmentId(String appointmentId);

}


In the above code, we created an interface named AppointmentRepo that extends MongoRepository. We used MongoDB, which is why we used MongoRepository. For other databases, the repository implementation would be different. One more thing to note is that the MongoRepository takes two arguments: the first one is the name of the POJO class on which the operations are performed, and the second one is the datatype of the ID in the POJO class. In our Employee POJO, we declared the ID as a String datatype because the employee ID contains both letters and digits. This AppointmentRepo interface is used for inserting, deleting, updating, and retrieving data.

AppointmentService.java:

Here we created a service class by using @Service annotation for developing business logic like save appoint data and generate a unique String value for every request.

Java
package com.app;

import java.util.List;
import java.util.Random;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AppointmentService {

    @Autowired
    private AppointmentRepo repo;

    @Autowired
    private UserRepo userRepo;

    @Autowired
    private AdminRepo adminRepo;

    /**
     * Creates a new user account.
     * @param user The user object containing user details.
     * @return true if the user account is successfully created, false otherwise.
     */
    public boolean createUserAccount(User user) {
        if (userRepo.save(user) != null) {
            return true;
        } else
            return false;
    }

    /**
     * Finds a user by their email.
     * @param email The email of the user to find.
     * @return true if the user is found.
     */
    public boolean findByUserEmail(String email) {
        userRepo.findByEmail(email);
        return true;
    }

    /**
     * Authenticates a user based on email and password.
     * @param email The email of the user.
     * @param password The password of the user.
     * @return true if the email and password match a user, false otherwise.
     */
    public boolean userLogin(String email, String password) {
        return userRepo.findByEmailAndPassword(email, password) != null;
    }

    /**
     * Authenticates an admin based on email and password.
     * @param email The email of the admin.
     * @param password The password of the admin.
     * @return true if the email and password match an admin, false otherwise.
     */
    public boolean adminLogin(String email, String password) {
        return adminRepo.findByEmailAndPassword(email, password) != null;
    }

    /**
     * Saves an appointment.
     * @param appointment The appointment object to save.
     * @return true if the appointment is successfully saved.
     */
    public boolean saveData(Appointment appointment) {
        appointment.setAppointmentId(generateRandomString());
        repo.save(appointment);
        return true;
    }

    /**
     * Retrieves all appointments.
     * @return A list of all appointments.
     */
    public List<Appointment> findAllAppointments() {
        return repo.findAll();
    }

    /**
     * Generates a random string for appointment ID.
     * @return A random string prefixed with "RQ" followed by 5 random digits.
     */
    public static String generateRandomString() {
        final String FIXED_PART = "RQ";
        final int RANDOM_PART_LENGTH = 5;
        StringBuilder sb = new StringBuilder(FIXED_PART);
        Random random = new Random();

        for (int i = 0; i < RANDOM_PART_LENGTH; i++) {
            int digit = random.nextInt(10);
            sb.append(digit);
        }

        return sb.toString();
    }
}


AppointmentController.java

The Controller layer is created using the @Controller annotation in Spring Boot. The Controller class is used for processing incoming API requests, preparing the Model, and returning the view to be rendered as a response. In this Controller class, we define the API endpoints for accessing the application service.

Java
package com.app;

import java.util.List;

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.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class AppointmentController {

    @Autowired
    private AppointmentService service;

    @Autowired
    private AppointmentRepo repo;

    /**
     * Handles GET requests for the home page.
     * @param model The model to pass attributes to the view.
     * @return The name of the home view.
     */
    @GetMapping("/")
    public String getIndexPage(Model model) {
        return "home";
    }

    /**
     * Handles GET requests for the appointment page.
     * @param model The model to pass attributes to the view.
     * @return The name of the appointment view.
     */
    @GetMapping("/appointment")
    public String getAppointmentPage(Model model) {
        return "appointment";
    }

    /**
     * Handles GET requests for the dashboard page.
     * @param model The model to pass attributes to the view.
     * @return The name of the dashboard view.
     */
    @GetMapping("/dashboard")
    public String getDashboardPage(Model model) {
        List<Appointment> appointments = service.findAllAppointments();
        model.addAttribute("appointments", appointments);
        model.addAttribute("totalAppointments", repo.count());
        model.addAttribute("totalBooked", repo.countByStatus("booked"));
        model.addAttribute("totalPending", repo.countByStatus("pending"));
        return "dashboard";
    }

    /**
     * Handles GET requests for the user registration page.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return The name of the register view.
     */
    @GetMapping("/user/create")
    public String getUserCreate(Model model, @ModelAttribute User user) {
        return "register";
    }

    /**
     * Handles POST requests for user registration.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return The name of the register view.
     */
    @PostMapping("/user/create")
    public String getPostUser(Model model, @ModelAttribute User user) {
        boolean result = service.findByUserEmail(user.getEmail());
        if (result) {
            model.addAttribute("exist", "This " + user.getEmail() + " Already Exist");
        } else if (service.createUserAccount(user)) {
            model.addAttribute("success", "Your User Account created");
        } else {
            model.addAttribute("error", "Your User Account creationed Failed");
        }
        return "register";
    }

    /**
     * Handles GET requests for the user login page.
     * @return The name of the user login view.
     */
    @GetMapping("/user/login")
    public String getUserLogin() {
        return "userlogin";
    }

    /**
     * Handles POST requests for user login.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return A redirection to the appointment page if login is successful, otherwise the user login view.
     */
    @PostMapping("/user/login")
    public String postUserLogin(Model model, @ModelAttribute User user) {
        boolean loginstatus = service.userLogin(user.getEmail(), user.getPassword());
        if (loginstatus) {
            return "redirect:/appointment";
        } else {
            model.addAttribute("error", "Login Failed");
            return "userlogin";
        }
    }

    /**
     * Handles GET requests for the admin login page.
     * @param model The model to pass attributes to the view.
     * @return The name of the admin login view.
     */
    @GetMapping("/admin/login")
    public String getAdminLogin(Model model) {
        return "adminlogin";
    }

    /**
     * Handles POST requests for admin login.
     * @param model The model to pass attributes to the view.
     * @param admin The admin model attribute.
     * @return A redirection to the dashboard page if login is successful, otherwise the admin login view.
     */
    @PostMapping("/admin/login")
    public String postAdminLogin(Model model, @ModelAttribute Admin admin) {
        boolean loginstatus = service.adminLogin(admin.getEmail(), admin.getPassword());
        if (loginstatus) {
            return "redirect:/dashboard";
        } else {
            model.addAttribute("error", "Login Failed");
            return "adminlogin";
        }
    }

    /**
     * Handles GET requests for the search page.
     * @param model The model to pass attributes to the view.
     * @return The name of the search view.
     */
    @GetMapping("/search")
    public String getStatusPage(Model model) {
        model.addAttribute("appointment", new Appointment());
        return "search";
    }

    /**
     * Handles POST requests for searching appointments by ID.
     * @param appointmentId The ID of the appointment to search.
     * @param model The model to pass attributes to the view.
     * @return The name of the search view with search results.
     */
    @PostMapping("/search")
    public String searchAppointment(@RequestParam("appointmentId") String appointmentId, Model model) {
        Appointment appointmentResult = repo.findByAppointmentId(appointmentId);

        if (appointmentResult != null) {
            model.addAttribute("appointment", appointmentResult);
        } else {
            model.addAttribute("error", "Appointment not found");
        }
        return "search";
    }

    /**
     * Handles POST requests for creating an appointment.
     * @param model The model to pass attributes to the view.
     * @param appointment The appointment model attribute.
     * @return The name of the appointment view with success or error message.
     */
    @PostMapping("/appointment")
    public String postIndexPage(Model model, @ModelAttribute Appointment appointment) {
        if (service.saveData(appointment)) {
            model.addAttribute("success", "Your Appointment Request ID : " + appointment.getAppointmentId());
        } else {
            model.addAttribute("error", "Unable Book your Appointment due to Error");
        }
        return "appointment";
    }
}


APIs Information

Display HTML Page:

This API is used for display the default index page.

http://localhost:8080/
@GetMapping("/")
    public String getIndexPage(Model model) {
        return "index";
    }

Output:

Index Page


Create User Account

http://localhost:8080/user/create
/**
     * Handles GET requests for the user registration page.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return The name of the register view.
     */
    @GetMapping("/user/create")
    public String getUserCreate(Model model, @ModelAttribute User user) {
        return "register";
    }
    /**
     * Handles POST requests for user registration.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return The name of the register view.
     */
    @PostMapping("/user/create")
    public String getPostUser(Model model, @ModelAttribute User user) {
        boolean result = service.findByUserEmail(user.getEmail());
        if (result) {
            model.addAttribute("exist", "This " + user.getEmail() + " Already Exist");
        } else if (service.createUserAccount(user)) {
            model.addAttribute("success", "Your User Account created");
        } else {
            model.addAttribute("error", "Your User Account creationed Failed");
        }
        return "register";
    }

Output:

Create user account


If User Already exist then we will get pop up like below,

User already exist


User Login

http://localhost:8080/user/login
/**
     * Handles GET requests for the user login page.
     * @return The name of the user login view.
     */
    @GetMapping("/user/login")
    public String getUserLogin() {
        return "userlogin";
    }
/**
     * Handles POST requests for user login.
     * @param model The model to pass attributes to the view.
     * @param user The user model attribute.
     * @return A redirection to the appointment page if login is successful, otherwise the user login view.
     */
    @PostMapping("/user/login")
    public String postUserLogin(Model model, @ModelAttribute User user) {
        boolean loginstatus = service.userLogin(user.getEmail(), user.getPassword());
        if (loginstatus) {
            return "redirect:/appointment";
        } else {
            model.addAttribute("error", "Login Failed");
            return "userlogin";
        }
    }

Output:

User Login


Admin Login

http://localhost:8080/admin/login
/**
     * Handles GET requests for the admin login page.
     * @param model The model to pass attributes to the view.
     * @return The name of the admin login view.
     */
    @GetMapping("/admin/login")
    public String getAdminLogin(Model model) {
        return "adminlogin";
    }
/**
     * Handles POST requests for admin login.
     * @param model The model to pass attributes to the view.
     * @param admin The admin model attribute.
     * @return A redirection to the dashboard page if login is successful, otherwise the admin login view.
     */
    @PostMapping("/admin/login")
    public String postAdminLogin(Model model, @ModelAttribute Admin admin) {
        boolean loginstatus = service.adminLogin(admin.getEmail(), admin.getPassword());
        if (loginstatus) {
            return "redirect:/dashboard";
        } else {
            model.addAttribute("error", "Login Failed");
            return "adminlogin";
        }
    }

Output:

Admin Login


Create Appointment Request

This API is used for save the Appointment data and Once data is saved successfully then we get one conformation alert message while errors also we got same alert with different message.

http://localhost:8080/appointment
@PostMapping("/appointment")
    public String postIndexPage(Model model, @ModelAttribute Appointment appointment) {
        if (service.saveData(appointment)) {
            model.addAttribute("success", "Your Appointment Request ID : " + appointment.getAppointmentId());
        } else {
            model.addAttribute("error", "Unable Book your Appointment due to Error");
        }
        return "appointment";
    }

Output:

Appointment Details


Appointment Request ID:

Appointment request id


Dashboard

This API is used for display the all information of appointment db and It will provide statistics of appointment and it is GET type of mapping.

http://localhost:8080/dashboard
@GetMapping("/dashboard")
    public String getDashboardPage(Model model) {
        List<Appointment> appointments = repo.findAll();
        model.addAttribute("appointments", appointments);
        model.addAttribute("totalAppointments", repo.count());
        model.addAttribute("totalBooked", repo.countByStatus("booked"));
        model.addAttribute("totalPending", repo.countByStatus("pending"));
        return "dashboard";
    }


Output:

Dashboard


Search Appointment:

This API is used for display the search HTML page to End user. And It is GET mapping

http://localhost:8080/dashboard
@GetMapping("/search")
    public String getStatusPage(Model model) {
        model.addAttribute("appointment", new Appointment());
        return "search";
    }


Output:

Search an Appointment


This API is used for search a appointment request by using Appointment Request ID. If it is exist display the related information otherwise It shows an alert message which indicates Request Id not exist.

@PostMapping("/search")
    public String searchAppointment(@RequestParam("appointmentId") String appointmentId, Model model) {
        Appointment appointmentResult = repo.findByAppointmentId(appointmentId);
        
        if (appointmentResult != null) {
            model.addAttribute("appointment", appointmentResult);
        } else {
            model.addAttribute("error", "Appointment not found");
            
        }
        return "search";
    }


Output:

Search with Appointment Id


Download the Project:

To download the entire project, here we have attached the project GitHub link - Appointment Scheduling System in Spring Boot



Next Article

Similar Reads