Date - 23/01/25
1. Important Concepts Explained
A. Annotations
Annotations provide metadata to tell Spring Boot how to manage different classes and methods.
Annotation Purpose
@SpringBootApplication Marks the main class that starts the Spring Boot
application. It combines @Configuration,
@EnableAutoConfiguration, and
@ComponentScan.
@Controller Tells Spring that the class handles HTTP requests and
returns views (web pages).
@RequestMapping("/url") Maps URLs to specific methods in a controller.
@ModelAttribute Automatically binds form data to a Java object.
@Autowired Automatically injects dependencies (like services,
repositories) into a class.
@Service Marks the class as a Service Layer that contains
business logic.
@Component Registers the class as a Spring-managed component
(e.g., for sending emails).
@Entity Marks the class as representing a database table.
@Table(name = Specifies the exact database table name
"registrations") (registrations).
@Id Marks the field as the primary key of the table.
@GeneratedValue(strategy Automatically generates the primary key for new
= records.
GenerationType.IDENTITY)
B. Variables
Type Definition Example in Code
Reference A variable that refers to an registrationService,
Variable object in memory. emailService,
registrationRepository.
Local Declared inside a method, exists Registration registration = new
Variable only during the method Registration(); inside a method.
execution.
Static Belongs to the class itself, Not explicitly used in your code but like
Variable shared by all objects of that public static int count;.
class.
Non-Static Belongs to an instance of the private String name; in
Variable class; each object has its own Registration class.
copy.
C. Methods
Type of Definition Example in Code
Method
Static Belongs to the class itself and public static void main(String[]
Method can be called without creating args) in the main class.
an object.
Non-Static Belongs to an object of the public void
Method class and needs an object to saveRegistration(Registration
be called. registration) in service.
Getter Returns the value of a private public String getName() in DTO and
Method variable. Entity classes.
Setter Updates the value of a private public void setName(String name)
Method variable. in DTO and Entity classes.
Custom User-defined methods to sendEmail(),
Methods perform specific tasks. saveRegistrationDetails().
2. Code Flow with Methods and Keywords Explained
A. application.properties
This config file holds database and email settings:
● Database Settings:
○ spring.datasource.url=jdbc:mysql://localhost:3306/oct_db_sts → Connects to
MySQL.
○ spring.datasource.username=root and spring.datasource.password=test → DB login
credentials.
● Email Settings:
○ spring.mail.host=smtp.gmail.com → Uses Gmail’s SMTP for sending emails.
○ spring.mail.username and spring.mail.password → Your Gmail credentials.
B. Main Class (WebdemoApplication.java)
@SpringBootApplication // Annotation: Marks this as the main Spring Boot application class.
public class WebdemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebdemoApplication.class, args); // Static method: Starts the app.
}
}
● Static Method: main() is a static method. It runs first when you start the app.
● Annotation (@SpringBootApplication): Tells Spring Boot to start with automatic configurations.
C. Controller Layer (RegistrationController.java)
Handles HTTP requests and sends responses (like web pages).
@Controller // Annotation: This class handles web requests.
public class RegistrationController {
@Autowired
private RegistrationService registrationService; // Reference Variable: Refers to service for saving data.
@Autowired
private EmailService emailService; // Reference Variable: Refers to the EmailService for sending emails.
@RequestMapping("/view")
public String viewRegistrationPage() {
return "registration"; // Returns the registration.jsp view when '/view' is visited.
}
@RequestMapping("/saveRegistration")
public String saveRegistrationDetails(@ModelAttribute RegistrationDto registrationDto, Model model) {
Registration registration = new Registration(); // Local Variable: Stores form data temporarily.
registration.setName(registrationDto.getName()); // Non-Static Method (Setter): Sets the name.
registration.setEmailId(registrationDto.getEmailId());
registration.setMobile(registrationDto.getMobile());
registrationService.saveRegistration(registration); // Calls the service layer to save data.
emailService.sendEmail(registrationDto.getEmailId(), "Welcome", "Welcome to our app!"); // Sends email.
model.addAttribute("msg", "Record is saved successfully!"); // Adds message to be shown on the view.
return "registration"; // Returns the same page after form submission.
}
}
● Methods:
○ viewRegistrationPage(): Returns the registration page when /view URL is accessed.
○ saveRegistrationDetails(): Saves the data and sends an email when the form is submitted.
D. DTO Layer (RegistrationDto.java)
Holds data from the form before it is processed.
public class RegistrationDto {
private String name; // Non-Static Variable: Each object has its own name.
private String emailId;
private String mobile;
// Getter Methods: To get the value of private variables.
public String getName() {
return name;
}
public String getEmailId() {
return emailId;
}
public String getMobile() {
return mobile;
}
// Setter Methods: To set/update the value of private variables.
public void setName(String name) {
this.name = name;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
● Getter Methods: getName(), getEmailId(), getMobile() → Retrieve data from private variables.
● Setter Methods: setName(), setEmailId(), setMobile() → Update private variables.
E. Entity Layer (Registration.java)
Represents a database table.
@Entity
@Table(name = "registrations")
public class Registration {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Primary key in the database.
private String name;
private String emailId;
private String mobile;
// Getter Methods
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getEmailId() {
return emailId;
}
public String getMobile() {
return mobile;
}
// Setter Methods
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
● Annotations:
○ @Entity: Represents a database table.
○ @Id and @GeneratedValue: Mark id as the primary key and auto-generate its value.
F. Repository Layer (RegistrationRepository.java)
Handles database operations like saving and fetching data.
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
// Inherits built-in methods for database operations:
// save(), findAll(), deleteById(), etc.
}
● Method Inheritance:
○ save(): Saves data into the database.
○ findAll(): Retrieves all records from the database.
○ deleteById(): Deletes a record by ID.
G. Service Layer (registrationService.java)
Contains business logic.
@Service
public class registrationService {
@Autowired
private RegistrationRepository registrationRepository; // Reference Variable: Refers to the repository for DB
operations.
public void saveRegistration(Registration registration) {
registrationRepository.save(registration); // Saves the data into the database.
}
public List<Registration> getRegistrations() {
return registrationRepository.findAll(); // Fetches all registration records.
}
}
● Methods:
○ saveRegistration(): Saves a new registration.
○ getRegistrations(): Fetches all registrations from the database.
H. Email Service (EmailService.java)
Handles sending emails.
@Component
public class EmailService {
@Autowired
private JavaMailSender javaMailSender; // Reference Variable: Used to send emails.
public void sendEmail(String to, String sub, String message) {
SimpleMailMessage s = new SimpleMailMessage(); // Local Variable: Stores email content.
s.setTo(to);
s.setSubject(sub);
s.setText(message);
javaMailSender.send(s); // Sends the email.
}
}
● Method (sendEmail):
○ Takes to (email address), sub (subject), and message as inputs.
○ Creates an email object (SimpleMailMessage) and sends the email.
3. Summary of All Concepts
Keyword Where Used Purpose
Annotations @Controller, @Service, @Entity, Instruct Spring how to manage
@Autowired classes and methods.
Reference registrationService, Refer to service, repository, or
Variable emailService, javaMailSender component objects.
Local Variable Registration registration = Temporary variables inside
new Registration(); methods.
Static Method public static void Runs without creating an object,
main(String[] args) starts the app.
Non-Static saveRegistration(), Belong to objects, used for
Method sendEmail() business logic.
Getter Methods getName(), getEmailId() Retrieve values of private fields.
Setter Methods setName(), setEmailId() Update values of private fields.
Explanation of JSP Code and Flow:
1. menu.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
</head>
<body>
<a href="view">Create Registration</a>
<a href="allRegistrations">All Registrations</a>
</body>
</html>
Explanation:
● This is a common navigation bar included in other JSP files.
● Links:
○ Create Registration: Redirects to /view, where the user can fill out the registration form.
○ All Registrations: Redirects to /allRegistrations, where the user can view all registered
entries.
2. Registration Form (registration.jsp)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
<%@ include file="menu.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Registration</title>
</head>
<body>
<h2>Enter the details...</h2>
<form action="saveRegistration" method="post">
<pre>
<input type="hidden" name="id" value="${registration.id}" />
ID: <input type="text" value="${registration.id}" readonly/>
Name: <input type="text" name="name" value="${registration.name != null ? registration.name : ''}"
required/>
Email: <input type="email" name="emailId" value="${registration.emailId != null ? registration.emailId : ''}"
required/>
Mobile: <input type="text" name="mobile" value="${registration.mobile != null ? registration.mobile : ''}"
required/>
<input type="submit" value="Save"/>
</pre>
</form>
<c:if test="${not empty msg}">
<div>${msg}</div>
</c:if>
</body>
</html>
Explanation:
● This form collects Name, Email, and Mobile details from the user.
● Flow:
1. When the user fills in the form and clicks Save, the data is sent via POST to the URL
/saveRegistration.
2. The RegistrationController handles this request and saves the data into the database.
3. On success or failure, a message (msg) is displayed if provided by the controller.
3. All Registrations (allRegistrations.jsp)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ include file="menu.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>All Registrations</title>
</head>
<body>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Mobile</th>
<th>Actions</th>
</tr>
<c:forEach var="registration" items="${registrations}">
<tr>
<td>${registration.id}</td>
<td>${registration.name}</td>
<td>${registration.emailId}</td>
<td>${registration.mobile}</td>
<td><a href="/deleteReg?id=${registration.id}">Delete</a> | <a
href="/getRegById?id=${registration.id}">Update</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
Explanation:
● Displays a list of all registrations in a table format.
● The list is populated using the ${registrations} object, passed from the controller.
● Actions:
○ Delete: Clicking Delete triggers a request to /deleteReg?id={registration.id}.
○ Update: Clicking Update redirects to /getRegById?id={registration.id} to pre-fill the
update form with existing data.
Flow:
1. When the user navigates to All Registrations, the RegistrationController retrieves all records using
the service and DAO layers.
2. The list of records (registrations) is sent to this JSP for display.
4. Update Registration (updateRegistration.jsp)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
<%@ include file="menu.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Update Registration</title>
</head>
<body>
<h2>Update Details</h2>
<form action="updateRegistration" method="post">
<input type="hidden" name="id" value="${registration.id}" /> <!-- ID is fixed and hidden -->
<pre>
ID: <input type="text" value="${registration.id}" readonly/>
Name: <input type="text" name="name" value="${registration.name}" />
Email: <input type="email" name="emailId" value="${registration.emailId}" />
Mobile: <input type="text" name="mobile" value="${registration.mobile}" />
<input type="submit" value="Update"/>
</pre>
</form>
<c:if test="${not empty msg}">
<div>${msg}</div>
</c:if>
</body>
</html>
Explanation:
● This form is pre-filled with existing data for a specific registration using the ${registration} object.
● Flow:
1. The user clicks Update from the All Registrations table, triggering the
/getRegById?id={registration.id} request.
2. The controller fetches the record by ID and passes it to this JSP.
3. After editing, when the user clicks Update, a POST request is sent to /updateRegistration.
4. The controller updates the record in the database.
Overall Flow Summary:
1. Create Registration:
○ Click Create Registration → Navigate to the registration form (/view).
○ Submit the form → POST to /saveRegistration.
○ Data is saved, and success or error message is displayed.
2. View All Registrations:
○ Click All Registrations → Fetch data from the database (/allRegistrations).
○ Display data in a table with Delete and Update options.
3. Delete Registration:
○ Click Delete → GET request to /deleteReg?id={registration.id}.
○ Record is deleted, and the table is refreshed.
4. Update Registration:
○ Click Update → GET request to /getRegById?id={registration.id}.
○ Pre-filled form is shown. After editing, submit → POST to /updateRegistration.
○ Record is updated, and the user is redirected to the list.
Date- 24/01/25
Spring Boot Registration API – Detailed Notes with
Flow Explanation
Overview
This project is a simple Spring Boot API for user registration management, allowing CRUD (Create, Read,
Update, Delete) operations via REST endpoints. It uses Spring Boot, JPA (Hibernate), and ModelMapper for
object conversion.
Flow of the Code (Step-by-Step Execution)
1. User makes a request (e.g., registration request via Postman).
2. The Controller (RegistrationController) receives the request and calls the Service Layer
(RegistrationService).
3. The Service Layer processes the request by interacting with the Repository
(RegistrationRepository) to fetch or store data in the Database.
4. The Entity (Registration) represents a table in the database.
5. The DTO (RegistrationDto) acts as a data transfer object between Controller and Service.
6. ModelMapper converts DTOs to Entities and vice versa.
7. The response is sent back to the Controller, which then returns the result to the client.
Key Components & Explanation
1️⃣ Controller Layer (RegistrationController)
📍 Handles HTTP Requests & Responses
● Uses @RestController → Marks the class as a REST API controller.
● Uses @RequestMapping("/api/v1/register") → Defines the base URL path.
@RestController
@RequestMapping("/api/v1/register")
public class RegistrationController {
📌 Why we use specific words?
● RegistrationDto → A Data Transfer Object (DTO) for transferring data between client & server.
● registrationService.createRegistration() → Calls the Service Layer to create a new
registration.
● Why not Apple, Orange, Papaya? 😂
○ These are domain-specific terms. "Registration" is meaningful in our context, while "Apple" is not.
2️⃣ Entity Layer (Registration)
📍 Represents Database Table
● Uses @Entity → Marks it as a database entity.
● Uses @Table(name = "register") → Maps it to a database table named register.
● Uses @Id and @GeneratedValue → Marks id as the primary key (auto-generated).
@Entity
@Table(name = "register")
public class Registration {
Fields Explanation
● private long id; → Unique identifier for each registration.
● private String name; → Stores user name.
● private String emailId; → Stores user email (must be unique).
● private String mobile; → Stores user mobile number (10 digits).
3️⃣ DTO Layer (RegistrationDto)
📍 Transfers Data Between Controller & Service
● Uses @Getter and @Setter (from Lombok) → Auto-generates getters & setters.
● Purpose:
○ Avoids exposing database entities directly in API responses.
○ Ensures decoupling between API and database structure.
@Getter
@Setter
public class RegistrationDto {
Getter & Setter Methods
public long getId() { return id; }
public void setId(long id) { this.id = id; }
● Why .getId()?
○ Retrieves id from the object.
○ Used when returning a response.
● Why .setId()?
○ Sets a new value for id (e.g., from user input).
4️⃣ Service Layer (RegistrationService)
📍 Contains Business Logic
● Uses @Service → Marks it as a service component.
● Uses RegistrationRepository to interact with the database.
@Service
public class RegistrationService {
Important Methods
Method Purpose
createRegistration(RegistrationDto Creates a new
registrationDto) registration.
deleteRegistration(long id) Deletes a registration by
ID.
updateRegistration(long id, RegistrationDto Updates registration
registrationDto) details.
getAllRegistrations() Fetches all registrations.
Why registrationService.updateRegistration(id, registrationDto)?
● registrationService → Calls the service layer.
● .updateRegistration(id, registrationDto) → Calls method to update registration.
● We use meaningful names like registrationService instead of random words like "banana" for clarity.
5️⃣ Repository Layer (RegistrationRepository)
📍 Handles Database Operations
● Extends JpaRepository (Spring Data JPA).
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
Purpose:
● Provides built-in methods like save(), findById(), and deleteById().
● Allows easy interaction with the database.
6️⃣ Model Mapping (ModelMapper)
📍 Converts DTO ↔ Entity
● Uses ModelMapper to map DTO to Entity and vice versa.
public Registration convertToEntity(RegistrationDto registrationDto) {
return modelMapper.map(registrationDto, Registration.class);
API Endpoints & Their Purpose
HTTP Method URL Description
POST /api/v1/register Creates a new registration.
DELETE /api/v1/register? Deletes a registration by ID.
id=3
PUT /api/v1/register/ Updates an existing
3 registration.
GET /api/v1/register Retrieves all registrations.
Understanding Important Keywords
Keyword Purpose
@RestController Marks the class as a REST API
controller.
@RequestMapping Defines the base URL path for all
endpoints.
@PostMapping Handles HTTP POST requests.
@DeleteMapping Handles HTTP DELETE requests.
@PutMapping Handles HTTP PUT requests.
@GetMapping Handles HTTP GET requests.
@Service Marks the class as a service layer.
@Entity Defines a class as a database entity.
@Table(name="register") Maps an entity to the register
table.
@Id Marks a field as the primary key.
@GeneratedValue(strategy = Auto-generates ID values.
GenerationType.IDENTITY)
@Column(name="email_id", Maps a field to a database column.
nullable=false, unique=true)
Static vs Non-Static Keywords
Type Example Explanation
Static public static void main() Shared across all instances.
Non-Static public void Unique to each object
updateRegistration() instance.
Final Notes (For Writing in Notebook)
1. Controller Layer
○ Handles API requests.
○ Uses @RestController and @RequestMapping.
2. Entity Layer
○ Represents a database table.
○ Uses @Entity, @Table, and JPA annotations.
3. DTO Layer
○ Transfers data between client & service.
○ Uses @Getter, @Setter.
4. Service Layer
○ Contains business logic.
○ Calls registrationRepository.save().
5. Repository Layer
○ Extends JpaRepository for database operations.
6. ModelMapper
○ Converts DTO ↔ Entity.
7. Keywords & Their Meanings
○ @PostMapping → Used for creating data.
○ @DeleteMapping → Used for deleting data.
○ @PutMapping → Used for updating data.
○ @GetMapping → Used for retrieving data.
Conclusion
This project follows MVC Architecture:
● Controller → Handles HTTP requests.
● Service → Contains business logic.
● Repository → Interacts with the database.
● Entity & DTO → Represent data structures.
Date–05/02/2025
Understanding the Code in Layman’s Terms
This code is for a Spring Boot REST API that manages user registrations. It allows users to create, update,
delete, and retrieve registrations in a database.
Breaking Down the Term "Registration"
The word Registration is used in multiple ways in the code. Let's analyze where and what it represents:
1. Entity Class (com.apidemo.entity.Registration)
○ In Registration.java, Registration is a class representing a database table.
○ It is an Entity (annotated with @Entity), meaning it is directly mapped to a table (register in the
database).
○ It has fields id, name, emailId, and mobile, which correspond to table columns.
2. DTO Class (com.apidemo.payload.RegistrationDto)
○ In RegistrationDto.java, RegistrationDto is a Data Transfer Object (DTO) used to
transfer data between client and server.
○ It has the same fields as the entity (id, name, emailId, mobile) but does not interact with the
database directly.
3. Service Layer (com.apidemo.service.RegistrationService)
○ RegistrationService is a service class that contains business logic.
○ It uses RegistrationRepository to interact with the database.
○ Methods like createRegistration(), deleteRegistration(), updateRegistration(),
and getAllRegistrations() operate on Registration entities.
○ It converts RegistrationDto to Registration (and vice versa) using ModelMapper.
4. Repository Layer (com.apidemo.repository.RegistrationRepository)
○ RegistrationRepository is an interface extending JpaRepository, which means it
automatically provides methods to interact with the database.
○ It works with the Registration entity and performs CRUD operations.
5. Controller Layer (com.apidemo.controller.RegistrationController)
○ RegistrationController is a REST API controller that handles HTTP requests.
○ It defines API endpoints for operations like creating, updating, deleting, and fetching registrations.
○ Example:
■ @PostMapping → Handles POST requests to create a new registration.
■ @DeleteMapping → Handles DELETE requests to remove a registration.
■ @PutMapping → Handles PUT requests to update a registration.
■ @GetMapping → Handles GET requests to fetch all registrations.
What Are the Other Important Words in the Code?
Here are some other key terms and what they mean:
Word Where It’s Used What It Means
@RestController RegistrationController Marks the class as a
.java REST API controller.
@RequestMapping("/api/v1/reg RegistrationController Defines the base
ister") .java URL for all
endpoints.
@PostMapping createRegistration() Maps HTTP POST
requests (used for
creating new
registrations).
@DeleteMapping deleteRegistration() Maps HTTP DELETE
requests (used for
deleting a
registration).
@PutMapping("{id}") updateRegistration() Maps HTTP PUT
requests (used for
updating a
registration).
@GetMapping getAllRegistrations() Maps HTTP GET
requests (used for
retrieving all
registrations).
@Autowired RegistrationService in Injects an instance
RegistrationController of
.java RegistrationSer
vice automatically.
@Entity Registration.java Marks the class as a
database entity (a
table in the
database).
@Table(name = "register") Registration.java Specifies the table
name (register).
@Id Registration.java Marks id as the
Primary Key.
@GeneratedValue(strategy = Registration.java Auto-generates
GenerationType.IDENTITY) unique IDs for each
registration.
@Column(name = "email_id", Registration.java Specifies column
unique = true, nullable = properties (unique,
false) not null, etc.).
JpaRepository RegistrationRepository Provides built-in
.java database operations
(like save(),
findById(),
deleteById()).
Optional<Registration> updateRegistration() inHelps avoid null
RegistrationService.ja pointer exceptions
va when fetching data.
ModelMapper convertToEntity(), Converts
convertToDto() RegistrationDto
to Registration
and vice versa.
@Service RegistrationService.ja Marks the class as a
va service layer
component.
@Configuration Config.java Marks the class as a
Spring configuration
file.
@Bean Config.java Defines a
Spring-managed
bean (for creating a
ModelMapper
instance).
How the API Works Step by Step
1. Creating a Registration (POST Request)
● URL: POST http://localhost:8080/api/v1/register
● The client (e.g., a frontend app) sends a request with user details (name, email, mobile).
● The RegistrationController receives the request and calls
registrationService.createRegistration().
● The RegistrationService converts the DTO to an entity and saves it to the database using
registrationRepository.save().
● A success message with the generated ID is returned.
2. Retrieving All Registrations (GET Request)
● URL: GET http://localhost:8080/api/v1/register
● The API fetches all stored registrations using registrationService.getAllRegistrations().
● It returns a list of registrations as JSON.
3. Updating a Registration (PUT Request)
● URL: PUT http://localhost:8080/api/v1/register/{id}
● The client sends a request with updated details (name, email, mobile).
● The API finds the registration by ID (findById()), updates the details, and saves the changes.
● A success message is returned.
4. Deleting a Registration (DELETE Request)
● URL: DELETE http://localhost:8080/api/v1/register?id={id}
● The API removes the registration from the database using deleteById(id).
● A success message is returned.
Conclusion
● Registration is primarily an entity class representing a database table.
● It is also used in the DTO (RegistrationDto) for transferring data and in the service and controller layers.
● The API allows CRUD operations (Create, Read, Update, Delete) using RegistrationRepository.
● ModelMapper is used for converting between Registration and RegistrationDto.
● Spring Boot manages dependency injection (@Autowired), database interactions (JpaRepository),
and request handling (@RestController).
Here’s your Spring Boot REST API code with detailed comments to explain each part:
1. Entity Class (Registration.java)
package com.apidemo.entity;
import jakarta.persistence.*;
import lombok.Data;
@Data // Lombok annotation to generate getters, setters, and constructors
@Entity // Marks this class as a database entity
@Table(name = "register") // Specifies the table name in the database
public class Registration {
@Id // Marks this field as the Primary Key
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generates unique ID values
private Long id; // Unique identifier for each registration
@Column(name = "name", nullable = false) // Defines column name and ensures it's not null
private String name;
@Column(name = "email_id", unique = true, nullable = false) // Email must be unique and not null
private String emailId;
@Column(name = "mobile", nullable = false) // Ensures mobile number is not null
private String mobile;
}
2. DTO Class (RegistrationDto.java)
package com.apidemo.payload;
import lombok.Data;
@Data // Lombok annotation to automatically generate getters and setters
public class RegistrationDto {
private Long id;
private String name;
private String emailId;
private String mobile;
3. Repository Interface (RegistrationRepository.java)
package com.apidemo.repository;
import com.apidemo.entity.Registration;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
// JpaRepository provides built-in CRUD operations, so no extra code is needed
4. Service Class (RegistrationService.java)
package com.apidemo.service;
import com.apidemo.entity.Registration;
import com.apidemo.payload.RegistrationDto;
import com.apidemo.repository.RegistrationRepository;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service // Marks this class as a service layer component
public class RegistrationService {
@Autowired
private RegistrationRepository registrationRepository; // Injects repository for database operations
@Autowired
private ModelMapper modelMapper; // Injects ModelMapper for entity-DTO conversion
// Method to create a new registration
public RegistrationDto createRegistration(RegistrationDto registrationDto) {
Registration registration = modelMapper.map(registrationDto, Registration.class); // Convert DTO to entity
Registration savedRegistration = registrationRepository.save(registration); // Save to database
return modelMapper.map(savedRegistration, RegistrationDto.class); // Convert entity back to DTO
// Method to retrieve all registrations
public List<RegistrationDto> getAllRegistrations() {
List<Registration> registrations = registrationRepository.findAll(); // Fetch all registrations
return registrations.stream()
.map(registration -> modelMapper.map(registration, RegistrationDto.class)) // Convert entities to DTOs
.collect(Collectors.toList());
// Method to update an existing registration
public RegistrationDto updateRegistration(Long id, RegistrationDto registrationDto) {
Optional<Registration> optionalRegistration = registrationRepository.findById(id); // Check if ID exists
if (optionalRegistration.isPresent()) {
Registration registration = optionalRegistration.get(); // Get existing record
registration.setName(registrationDto.getName());
registration.setEmailId(registrationDto.getEmailId());
registration.setMobile(registrationDto.getMobile());
Registration updatedRegistration = registrationRepository.save(registration); // Save updates
return modelMapper.map(updatedRegistration, RegistrationDto.class); // Convert to DTO
} else {
return null; // Return null if ID not found (error handling can be improved)
// Method to delete a registration by ID
public void deleteRegistration(Long id) {
registrationRepository.deleteById(id); // Deletes the record with the given ID
5. Controller Class (RegistrationController.java)
package com.apidemo.controller;
import com.apidemo.payload.RegistrationDto;
import com.apidemo.service.RegistrationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // Marks this class as a REST API controller
@RequestMapping("/api/v1/register") // Defines base URL for all endpoints
public class RegistrationController {
@Autowired
private RegistrationService registrationService; // Injects the service layer
// Endpoint to create a new registration
@PostMapping
public RegistrationDto createRegistration(@RequestBody RegistrationDto registrationDto) {
return registrationService.createRegistration(registrationDto);
// Endpoint to retrieve all registrations
@GetMapping
public List<RegistrationDto> getAllRegistrations() {
return registrationService.getAllRegistrations();
// Endpoint to update an existing registration
@PutMapping("/{id}") // URL parameter `{id}` is used to specify which record to update
public RegistrationDto updateRegistration(@PathVariable Long id, @RequestBody RegistrationDto
registrationDto) {
return registrationService.updateRegistration(id, registrationDto);
}
// Endpoint to delete a registration
@DeleteMapping
public void deleteRegistration(@RequestParam Long id) { // ID is passed as a query parameter
registrationService.deleteRegistration(id);
6. Configuration Class (Config.java)
package com.apidemo.config;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // Marks this class as a Spring Boot configuration file
public class Config {
@Bean // Defines a Spring-managed bean
public ModelMapper modelMapper() {
return new ModelMapper(); // Creates a ModelMapper instance
How This Works Together
1. The user sends an HTTP request (e.g., POST, GET, PUT, DELETE) to the API endpoints.
2. The RegistrationController processes the request and calls the appropriate service method.
3. The RegistrationService handles business logic and interacts with RegistrationRepository.
4. The RegistrationRepository communicates with the database using JPA methods.
5. ModelMapper converts between RegistrationDto (DTO) and Registration (Entity).
6. The response is sent back to the user in JSON format.
Example API Requests
1. Create a Registration (POST)
Request:
POST http://localhost:8080/api/v1/register
Content-Type: application/json
"name": "John Doe",
"emailId": "john@example.com",
"mobile": "1234567890"
Response:
"id": 1,
"name": "John Doe",
"emailId": "john@example.com",
"mobile": "1234567890"
2. Retrieve All Registrations (GET)
Request:
GET http://localhost:8080/api/v1/register
Response:
[
"id": 1,
"name": "John Doe",
"emailId": "john@example.com",
"mobile": "1234567890"
3. Update a Registration (PUT)
Request:
PUT http://localhost:8080/api/v1/register/1
Content-Type: application/json
"name": "John Updated",
"emailId": "johnupdated@example.com",
"mobile": "9876543210"
4. Delete a Registration (DELETE)
Request:
DELETE http://localhost:8080/api/v1/register?id=1
Date–05/02/2025
Here's a structured note based on your lecture transcript and the corrected code, explaining key concepts.
📌 Notes on DTOs, Response Handling & Spring
Boot Annotations
1️⃣ Why Do We Use DTOs Instead of Entities in Responses?
A. Data Transfer Objects (DTOs) vs. Entities
✔️ Entity represents the database structure and is directly mapped to a table.
✔️ DTO (Data Transfer Object) is used to customize the response sent to the client.
B. Why Not Return an Entity?
🚫 Entities expose the database structure, which is risky for security.
✅ DTOs allow customization, so we can combine data from multiple tables and modify it before sending it to
the client.
C. Example Use Case
● Suppose we have two tables: registration & subscription.
● If we need to fetch and combine data from both tables before returning it, we can create a custom DTO
instead of exposing raw database tables.
● This helps in displaying registered users along with their subscription details in one API response.
2️⃣ Returning Responses in Spring Boot
✔️ Spring Boot API responses include: 1️⃣ The Response DTO → Customizable, ensures security
2️⃣ HTTP Status Code → Success or error status
3️⃣ Response Headers → Extra metadata if needed
A. Example of Returning a Response DTO
@PostMapping
public ResponseEntity<RegistrationDto> createRegistration(@RequestBody RegistrationDto registrationDto) {
RegistrationDto registration = registrationService.createRegistration(registrationDto);
return ResponseEntity.status(HttpStatus.CREATED).body(registration);
🔹 ResponseEntity<RegistrationDto> ensures DTO is returned, not entity.
🔹 HttpStatus.CREATED (201) is used for successful resource creation.
3️⃣ Important Spring Boot Annotations
A. @RequestBody
✅ Used in controller methods to map JSON request body to a Java object.
✅ Example:
@PostMapping
public ResponseEntity<RegistrationDto> createRegistration(@RequestBody RegistrationDto registrationDto) { ... }
B. @RestController vs @Controller
Annotation Purpose
@Controller Used for MVC applications, returns views (HTML, JSP, etc.)
@RestControl Used for REST APIs, returns JSON responses
ler
✔️ @RestController = @Controller + @ResponseBody
4️⃣ Java 8 Feature Used: Stream API
✔️ Converting List of Entities to DTOs in One Line
public List<RegistrationDto> getAllRegistrations() {
return registrationRepository.findAll()
.stream()
.map(this::convertToDto)
.collect(Collectors.toList());
✅ Streams make it easier to process lists in Java 8+.
✅ We map each entity to a DTO and collect results into a list.
5️⃣ Dependency Injection & @Bean
A. What is @Bean?
✔️ When we annotate a method with @Bean, it registers that method's return object as a Spring-managed bean.
✔️ Example:
@Configuration
public class Config {
@Bean
public ModelMapper getModelMapper() {
return new ModelMapper();
📌 Purpose → This ensures that ModelMapper is available throughout the project.
Here’s the code with comments explaining each part, followed by a layman's explanation of what the code does.
1. Entity Class (Registration.java)
package com.apidemo.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
// Lombok annotations to automatically generate getter and setter methods
@Getter
@Setter
@Entity // Marks this class as a JPA Entity, meaning it maps to a database table
@Table(name = "register") // Specifies the table name in the database
public class Registration {
@Id // Marks this field as the primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generates a unique ID for each record
private long id;
@Column(name = "name", nullable = false) // Maps this field to the "name" column, making it required (not null)
private String name;
@Column(name = "email_id", nullable = false, unique = true) // Maps to "email_id" column, enforces uniqueness
private String emailId;
@Column(name = "mobile", nullable = false, unique = true, length = 10) // Maps to "mobile" column, unique and
10 characters long
private String mobile;
Explanation (Layman's Terms)
● This class represents a "Registration" table in the database.
● Each object of this class is like a row in the database.
● The @Entity annotation tells Spring Boot that this is a database table.
● The @Table(name = "register") sets the actual table name as "register".
● The @Id and @GeneratedValue(strategy = GenerationType.IDENTITY) create a unique ID
automatically.
● Each registration has a name, email, and mobile number, and the email & mobile must be unique.
2. DTO Class (RegistrationDto.java)
package com.apidemo.payload;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
// Lombok annotations to generate getter and setter methods automatically
@Getter
@Setter
public class RegistrationDto {
private long id;
private String name;
private String emailId;
private String mobile;
// Getters and Setters for each field
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;
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
public String getMobile() {
return mobile;
public void setMobile(String mobile) {
this.mobile = mobile;
Explanation (Layman's Terms)
● This RegistrationDto class is a DTO (Data Transfer Object).
● Why do we need this?
○ The Registration class is directly linked to the database.
○ We should not expose the database structure directly in the API response.
○ Instead, we convert the Registration entity into a RegistrationDto before sending data to the
user.
● The DTO contains only the necessary fields (id, name, email, mobile) and avoids exposing sensitive
data.
3. Main Application Class (ApidemoApplication.java)
package com.apidemo;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // This annotation tells Spring Boot to start the application
public class ApidemoApplication {
public static void main(String[] args) {
SpringApplication.run(ApidemoApplication.class, args); // Starts the application
// Bean to create an instance of ModelMapper
public ModelMapper modelMapper() {
return new ModelMapper();
Explanation (Layman's Terms)
● This is the starting point of the Spring Boot application.
● The @SpringBootApplication annotation tells Spring Boot to set up everything automatically.
● The main() method runs the application.
● ModelMapper modelMapper() is used to convert Registration (Entity) to RegistrationDto (DTO)
and vice versa.
4. Configuration Class (Config.java)
package com.apidemo.config;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // Marks this as a configuration class
public class Config {
@Bean // Creates a ModelMapper bean that can be used throughout the project
public ModelMapper getModelMapper() {
return new ModelMapper();
}
Explanation (Layman's Terms)
● This class configures dependencies needed for the application.
● The @Configuration annotation tells Spring Boot that this class contains bean definitions.
● The @Bean annotation creates an instance of ModelMapper, which is used to map data between DTOs
and Entities.
Key Takeaways
● Entity (Registration.java) → Represents a table in the database.
● DTO (RegistrationDto.java) → A separate class used for API responses, protecting database
structure.
● Main Application (ApidemoApplication.java) → Entry point of the application.
● Configuration (Config.java) → Defines beans (dependencies like ModelMapper) used in the project.
📌 Conclusion
✔️ Use DTOs instead of Entities in responses to avoid security risks.
✔️ Spring Boot annotations like @RestController, @Bean, @RequestBody help manage APIs efficiently.
✔️ Stream API & Java 8 features simplify object mapping between DTOs & Entities.
Date-06/02/2025
Notes on Exception Handling in Spring Boot – Layman’s Terms
Introduction
In this session, we are learning about exception handling in our Spring Boot project. We will add more features
and understand why we need custom exception classes.
1. Creating a Method to Find a Registration by ID
● We will write a method getRegistrationById(Long id) that searches for a record using an ID number.
● If the record exists, it will return the registration details.
● If the record is not found, it should throw an exception instead of returning null.
2. Creating a Custom Exception Class
● Inside the exceptions folder, we create a custom exception class called
ResourceNotFoundException.
● This class extends RuntimeException, making it an unchecked exception (which means we don't need
to handle it explicitly).
Code:
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
3. Throwing an Exception if the ID is Not Found
● We use the findById() method from the repository to look for a record.
● If found, it returns the registration object.
● If not found, it throws the custom exception using orElseThrow().
Code:
public Registration getRegistrationById(Long id) {
return registrationRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Registration record not found for ID: " + id));
💡 Here, orElseThrow() is a Java 8 feature that throws an exception if the record is missing.
4. Creating an API Endpoint in the Controller
● We add a method in the controller to handle GET requests.
● If the record is found, it returns the data.
● If not, it throws an exception, which Spring will handle automatically.
Code:
@GetMapping("/{id}")
public ResponseEntity<RegistrationDto> getRegistration(@PathVariable Long id) {
RegistrationDto registration = registrationService.getRegistrationById(id);
return new ResponseEntity<>(registration, HttpStatus.OK);
}
5. Handling Exceptions Gracefully
● Instead of showing a raw error message, we can customize the response when an exception occurs.
● We use @ExceptionHandler to catch exceptions and return a proper error message.
Code for Global Exception Handling:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
💡 Now, when a user requests a non-existent record, they will see:
👉 "Registration record not found for ID: 123" instead of a confusing system error.
6. Fixing Compatibility Issues
● The project had dependency and plugin issues, causing errors during compilation.
● The instructor suggests removing the problematic plugin from pom.xml and reloading the project.
● Key takeaway: Be careful when updating dependencies, as some may break existing features.
Summary
✅ We created a custom exception class.
✅ Used orElseThrow() to handle missing records.
✅ Built an API to fetch registration details.
✅ Implemented global exception handling for better error messages.
✅ Troubleshot dependency issues in Spring Boot.
🔹 Next Steps: More discussion on Maven (mvn) plugins and DevOps-related topics in future classes.
Date - 08/02/25
Understanding the Code: RESTful API using Java (Spring Boot)
This project is a Registration API where users can register with their name, email, and mobile number. It follows
the CRUD operations (Create, Read, Update, Delete) using Spring Boot, JPA, and a database.
1. What is a RESTful API?
An API (Application Programming Interface) allows different applications to talk to each other. A RESTful API
follows specific rules for communication using HTTP requests like:
● POST → Create a new registration
● GET → Fetch all or specific registrations
● PUT → Update an existing registration
● DELETE → Remove a registration
Example:
Imagine a hotel registration system where guests enter their details. This API does the same but digitally—handling
user registrations in an application.
2. Project Structure & Components
Each part of the project plays a specific role:
(A) Configuration File (Config.java)
● Registers a ModelMapper Bean which helps in converting objects (like Entity ↔ DTO).
(B) Controller (RegistrationController.java)
This is where we define our API endpoints (URLs for interaction). It handles different HTTP requests:
● @PostMapping → Adds a new user
● @GetMapping → Retrieves registered users
● @PutMapping → Updates a user’s details
● @DeleteMapping → Deletes a user
Example URL:
● http://localhost:8080/api/v1/register → For adding a new registration
● http://localhost:8080/api/v1/register/3 → For updating user ID 3
● http://localhost:8080/api/v1/register/byId?id=2 → Fetch details of user ID 2
It uses ResponseEntity to send responses like success or failure.
(C) Entity (Registration.java)
● Defines the database table where user details will be stored.
● Uses @Entity and @Table(name="register") to define the table.
● Fields like id, name, emailId, and mobile are created as columns.
(D) Repository (RegistrationRepository.java)
● Extends JpaRepository → Provides built-in functions like save(), findById(), deleteById() to interact with
the database.
● No need to write SQL queries manually!
(E) Service (RegistrationService.java)
This is where business logic is written. It contains:
● Methods to save, update, delete, and fetch registrations.
● Uses ModelMapper to convert Entity → DTO (so we don’t expose database models directly).
● Handles pagination (fetching results in batches) and sorting.
Example:
● pageNo=0&pageSize=3&sortBy=name&sortDir=asc → Fetch first 3 users, sorted by name in
ascending order.
(F) Exception Handling (ExceptionHandling.java)
● If a record is not found, it throws a ResourceNotFound exception with a message like "Record Not
Found".
● A generic exception handler catches all other errors and returns a proper response.
(G) DTO (RegistrationDto.java)
● A DTO (Data Transfer Object) is used to avoid exposing database details directly.
● It only contains necessary fields (id, name, emailId, mobile) for data transfer.
3. Running & Testing the API
1. Start the application using IntelliJ or mvn spring-boot:run.
2. Test API calls using Postman:
○ POST: Send user data to http://localhost:8080/api/v1/register
○ GET: Fetch users from http://localhost:8080/api/v1/register
○ PUT: Update user details
○ DELETE: Remove a user
4. Summary
● This Spring Boot API manages user registrations.
● Controller handles requests, Service processes logic, Repository interacts with the database.
● Postman is used to test API calls without creating a frontend.
● Exception handling ensures proper error messages.
Sure! Let’s go step by step and break down each part of the Spring Boot REST API code in simple terms just like
your sir would explain.
📌 1. Project Structure
In a Spring Boot REST API, we divide the code into different layers:
● Controller → Handles HTTP requests (GET, POST, PUT, DELETE)
● Service → Business logic (actual processing of data)
● Repository → Communicates with the database
● Entity → Defines the structure of the database table
● DTO → Used to transfer data without exposing database details
● Exception Handling → Manages errors properly
📌 2. Code Explanation
(A) Registration.java (Entity Class)
This represents the database table where user data will be stored.
@Entity
@Table(name = "register")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Registration {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Primary key (auto-increment)
@NotEmpty(message = "Name is required")
private String name; // User's Name
@NotEmpty(message = "Email is required")
@Email(message = "Invalid email format")
private String emailId; // User's Email
@NotEmpty(message = "Mobile number is required")
private String mobile; // User's Mobile Number
💡 What’s happening here?
● @Entity → Marks this class as a database table.
● @Table(name = "register") → Names the table "register" in the database.
● @Id & @GeneratedValue(strategy = GenerationType.IDENTITY) → Auto-generate unique IDs
for each user.
● @NotEmpty & @Email → Validates user input (so empty values or invalid emails aren’t accepted).
● Lombok annotations (@Data, @NoArgsConstructor, @AllArgsConstructor) → Reduces
boilerplate code by automatically generating getters, setters, constructors, etc.
(B) RegistrationRepository.java (Repository Layer)
This is responsible for database operations like saving, retrieving, updating, and deleting users.
@Repository
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
Optional<Registration> findByEmailId(String emailId);
💡 What’s happening here?
● extends JpaRepository<Registration, Long> → Automatically provides methods like:
○ save() → Add new user
○ findById() → Get user by ID
○ findAll() → Get all users
○ deleteById() → Delete user
● findByEmailId(String emailId) → Custom query to find users by email.
(C) RegistrationService.java (Service Layer)
This processes the data before sending it to the database or controller.
@Service
@RequiredArgsConstructor
public class RegistrationService {
private final RegistrationRepository registrationRepository;
private final ModelMapper modelMapper;
public RegistrationDto createRegistration(RegistrationDto registrationDto) {
Registration registration = modelMapper.map(registrationDto, Registration.class);
Registration savedRegistration = registrationRepository.save(registration);
return modelMapper.map(savedRegistration, RegistrationDto.class);
💡 What’s happening here?
● @Service → Marks this as a Service Layer (where business logic is written).
● RegistrationRepository registrationRepository → Calls database methods.
● ModelMapper modelMapper → Converts between DTO and Entity.
● createRegistration() → Converts DTO → Entity, saves it, and converts back to DTO.
(D) RegistrationController.java (Controller Layer)
This handles API endpoints (URLs) where users send their requests.
@RestController
@RequestMapping("/api/v1/register")
@RequiredArgsConstructor
public class RegistrationController {
private final RegistrationService registrationService;
@PostMapping
public ResponseEntity<RegistrationDto> createRegistration(@Valid @RequestBody RegistrationDto
registrationDto) {
return new ResponseEntity<>(registrationService.createRegistration(registrationDto), HttpStatus.CREATED);
💡 What’s happening here?
● @RestController → Marks this as an API Controller.
● @RequestMapping("/api/v1/register") → Defines base URL.
● @PostMapping → Handles POST requests (adds new users).
● @Valid @RequestBody RegistrationDto registrationDto →
○ @RequestBody → Accepts JSON input from Postman or frontend.
○ @Valid → Ensures valid input (like email format).
● ResponseEntity<>(..., HttpStatus.CREATED) → Returns API response with status 201
(Created).
(E) ExceptionHandling.java (Custom Error Handling)
If something goes wrong, this class manages errors gracefully.
@RestControllerAdvice
public class ExceptionHandling {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
💡 What’s happening here?
● @RestControllerAdvice → Global exception handler for the API.
● @ExceptionHandler(ResourceNotFoundException.class) → Catches "Record Not Found"
errors.
(F) RegistrationDto.java (DTO - Data Transfer Object)
Used to transfer only necessary data (not exposing entire database structure).
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RegistrationDto {
private Long id;
private String name;
private String emailId;
private String mobile;
💡 Why use DTO?
● Prevents exposing database structure directly.
● Only required fields are sent to the frontend.
● Helps in data transformation (Entity ↔ DTO).
📌 3. How This Works in Real Life (Example Scenario)
Imagine you are using Postman or a frontend (React/Angular):
Step 1: Add a New User (POST Request)
URL: http://localhost:8080/api/v1/register
Request Body (JSON Format in Postman):
"name": "John Doe",
"emailId": "johndoe@gmail.com",
"mobile": "9876543210"
✅ Response (201 Created)
{
"id": 1,
"name": "John Doe",
"emailId": "johndoe@gmail.com",
"mobile": "9876543210"
}
Step 2: Get All Users (GET Request)
URL: http://localhost:8080/api/v1/register
✅ Response (200 OK)
"id": 1,
"name": "John Doe",
"emailId": "johndoe@gmail.com",
"mobile": "9876543210"
Step 3: Update User (PUT Request)
URL: http://localhost:8080/api/v1/register/1
Request Body:
"name": "John Updated",
"emailId": "johnupdated@gmail.com",
"mobile": "9876543210"
✅ Response: "User updated successfully"
Step 4: Delete User (DELETE Request)
URL: http://localhost:8080/api/v1/register/1
✅ Response: "User deleted successfully"
📌 4. Summary
● Spring Boot API follows Controller → Service → Repository → Database structure.
● DTO helps in secure data transfer (not exposing full database).
● Postman helps in testing API calls before integrating with the frontend.
● Exception handling ensures smooth error messages.
DATE -10/02
Here's a simplified explanation of your code, incorporating the lecture's explanation in layman's terms:
Understanding Pagination and Sorting in the Code
Imagine you have a huge list of registered users in a database, and you want to display them on a website. If we
show all the records at once, the page will load very slowly. Instead, we display a limited number of records per
page, like 10 users per page. This is called pagination.
Similarly, if you want to organize the list by name, email, or date of registration, this is called sorting.
Now, let’s break down the code step by step.
1. Configuration Class
@Configuration
public class Config {
@Bean
public ModelMapper getModelMapper() {
return new ModelMapper();
● What it does: This configuration file creates a ModelMapper bean, which helps in converting
Registration (database entity) to RegistrationDto (data transfer object) and vice versa.
2. Entity Class (Database Table Representation)
@Entity
@Table(name = "register")
public class Registration {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String emailId;
private String mobile;
● What it does:
○ Defines the register table in the database.
○ Each registration has an id, name, emailId, and mobile.
○ The id is auto-generated.
3. Controller Class (Handles API Requests)
@RestController
@RequestMapping("/api/v1/register")
public class RegistrationController {
@Autowired
private RegistrationService registrationService;
@PostMapping
public ResponseEntity<RegistrationDto> createRegistration(@RequestBody RegistrationDto registrationDto) {
RegistrationDto registration = registrationService.createRegistration(registrationDto);
return ResponseEntity.status(HttpStatus.CREATED).body(registration);
● What it does:
○ The @RestController allows this class to handle HTTP requests.
○ @PostMapping is used to add a new registration.
○ The request body contains registration details (name, email, etc.).
○ The response returns a 201 Created status.
4. Service Layer (Business Logic)
@Service
public class RegistrationService {
private RegistrationRepository registrationRepository;
private ModelMapper modelMapper;
public RegistrationService(RegistrationRepository registrationRepository, ModelMapper modelMapper) {
this.registrationRepository = registrationRepository;
this.modelMapper = modelMapper;
public RegistrationDto createRegistration(RegistrationDto registrationDto) {
Registration registration = convertToEntity(registrationDto);
Registration savedRegistration = registrationRepository.save(registration);
return convertToDto(savedRegistration);
● What it does:
○ Handles logic for saving a new registration.
○ Uses ModelMapper to convert between Registration (entity) and RegistrationDto (DTO).
5. Pagination and Sorting in getAllRegistrations
@GetMapping
public ResponseEntity<List<RegistrationDto>> getAllRegistrations(
@RequestParam(name = "pageNo", defaultValue = "0") int pageNo,
@RequestParam(name = "pageSize", defaultValue = "3") int pageSize,
@RequestParam(name = "sortBy", defaultValue = "id") String sortBy,
@RequestParam(name = "sortDir", defaultValue = "asc") String sortDir
){
List<RegistrationDto> registrations = registrationService.getAllRegistrations(pageNo, pageSize, sortBy, sortDir);
return new ResponseEntity<>(registrations, HttpStatus.OK);
● What it does:
○ Accepts pagination parameters:
■ pageNo: Which page to display (default is page 0).
■ pageSize: Number of records per page (default is 3).
■ sortBy: Field to sort by (default is id).
■ sortDir: Sorting order (asc for ascending, desc for descending).
○ Calls the service layer to fetch data accordingly.
6. Implementation of Pagination in Service Layer
public List<RegistrationDto> getAllRegistrations(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort = sortDir.equals("asc") ? Sort.by(Sort.Order.asc(sortBy)) : Sort.by(Sort.Order.desc(sortBy));
Pageable page = PageRequest.of(pageNo, pageSize, sort);
Page<Registration> all = registrationRepository.findAll(page);
return all.getContent().stream()
.map(reg -> modelMapper.map(reg, RegistrationDto.class))
.collect(Collectors.toList());
● What it does:
○ Uses PageRequest to fetch records page by page.
○ Sorts the data dynamically based on user input.
7. Exception Handling
@ControllerAdvice
public class ExceptionHandling {
@ExceptionHandler(ResourceNotFound.class)
public ResponseEntity<ErrorDetails> handleResourceNotFound(ResourceNotFound ex, WebRequest request) {
ErrorDetails error = new ErrorDetails(ex.getMessage(), new Date(), request.getDescription(true));
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
● What it does:
○ Catches errors and returns meaningful messages instead of crashing the application.
Conclusion
● The code is designed to manage user registrations using a RESTful API.
● Pagination ensures that the data is displayed page by page instead of loading all records at once.
● Sorting allows users to arrange records by any field dynamically.
● DTO (Data Transfer Object) is used to send only relevant data instead of exposing the database structure.
● Exception Handling ensures smooth error management.
This follows the approach explained in the lecture, where the concept of pagination and sorting was discussed in
terms of handling large amounts of data efficiently.
DATE - 11/02
Lecture Notes: Sorting and Pagination in Java (Spring Boot)
Pagination Recap & Moving to Sorting
● The previous session covered pagination.
● This session focuses on sorting data in ascending and descending order.
Sorting Implementation in Spring Boot
● The goal is to sort records in ascending or descending order.
● By default, records are sorted in ascending order (ASC).
Steps to Implement Sorting
1. Modify the Controller:
○ Add parameters sortBy and sortDir to allow dynamic sorting.
○ Default sorting direction is set to ASC.
2. Generate a Sort Object Based on Direction:
Sort sort = sortDir.equals("ASC") ? Sort.by(sortBy).ascending() : Sort.by(sortBy).descending();
○ Uses a ternary operator to decide sorting order.
○ If sortDir is "ASC", it sorts in ascending order.
○ Otherwise, it sorts in descending order.
Understanding the Ternary Operator in Java
● A shortcut for writing if-else conditions.
Syntax:
variable = (condition) ? value_if_true : value_if_false;
Example:
String val = (x > 10) ? "x is greater" : "x is not greater";
○ If x > 10, "x is greater" is stored in val.
○ Otherwise, "x is not greater" is stored in val.
Application in Sorting Logic:
Sort sort = sortDir.equals("ASC") ? Sort.by(sortBy).ascending() : Sort.by(sortBy).descending();
○ If sortDir is "ASC", records are sorted in ascending order.
○ Otherwise, records are sorted in descending order.
Testing Sorting with Postman
To test sorting, use query parameters:
?sortBy=name&sortDir=ASC
○ Sorts records by name in ascending order.
?sortBy=mobileNumber&sortDir=DESC
○ Sorts records by mobile number in descending order.
Additional Pagination Information
● Fetch additional details for better frontend integration:
○ Page number: page.getNumber()
○ Page size: page.getSize()
○ Total pages: page.getTotalPages()
○ Total elements: page.getTotalElements()
○ Is first page: page.isFirst()
○ Is last page: page.isLast()
Example Debugging Outputs:
Page Number: 0
Page Size: 5
Total Pages: 2
Total Elements: 6
Is First Page: true
Is Last Page: false
Summary
● Implemented sorting using query parameters (sortBy and sortDir).
● Used the ternary operator to toggle sorting direction.
● Demonstrated debugging and testing in Postman.
● Fetched additional pagination details for frontend clarity.
Date - 13/05
What is Spring Validation?
Spring Validation is a way to check if the data you're sending to your application is correct before saving it to the
database. For example, if you have a form where users enter their name, email, and age, you want to make sure
the name isn't left blank, the email is in the right format, and the age is a reasonable number. Spring
Validation helps you do this.
How to Add Validation to Your Project
1. Add the Validation Dependency:
○ First, you need to add a library (dependency) to your project that allows you to use validation
features. This is done in the pom.xml file, which is like a settings file for your project.
○ You can get this dependency from a tool called Spring Initializer. You select Java, Maven (a build
tool), and then add the "Validation" dependency. This will give you a piece of code to paste into
your pom.xml file.
2. Use Annotations for Validation:
○ Once the dependency is added, you can use special tags (annotations) to validate your data.
These annotations are like rules that you apply to your data fields.
○ For example, if you want to make sure a field isn’t left empty, you can use the @NotNull or
@NotEmpty annotations.
Common Validation Annotations
Here are some of the most common annotations and what they do:
1. @NotNull:
○ Ensures that a field is not null. For example, if you have a field for a user's name, it cannot be left
blank.
2. @Size:
○ Checks the length of a string. For example, you can say a username must be between 5 and 20
characters long. If someone enters a username with 3 characters, it will show an error.
3. @NotEmpty:
○ Ensures that a field is not null and not empty. For example, if you have a field for an email, it
cannot be left blank or just contain spaces.
4. @NotBlank:
○ Similar to @NotEmpty, but it also checks that the field doesn’t contain only whitespace (like spaces
or tabs).
5. @Min and @Max:
○ Used for numbers. For example, you can say that the age of a user must be at least 18
(@Min(18)) and no more than 100 (@Max(100)).
6. @Email:
○ Checks if the email entered is in a valid format. For example, it should have an "@" symbol and a
domain like ".com".
7. @Pattern:
○ Allows you to create custom rules using regular expressions. For example, you can say that a
username can only contain letters and numbers.
8. @Future and @Past:
○ Used for dates. @Future ensures that a date is in the future (like a flight booking date), while
@Past ensures that a date is in the past (like a date of birth).
9. @AssertTrue and @AssertFalse:
○ Used for boolean values. For example, you can use @AssertTrue to ensure that a user has
agreed to the terms and conditions.
How to Apply Validation in Your Code
1. Add Annotations to Your Data Fields:
○ In your code, you apply these annotations to the fields in your data model (often called a DTO or
Entity). For example, if you have a field for a user's name, you can add @NotNull and
@Size(min=2, max=10) to ensure the name is not null and is between 2 and 10 characters
long.
2. Use @Valid in Your Controller:
○ In your controller (the part of your code that handles requests), you use the @Valid annotation to
tell Spring to validate the data before processing it. If the data is invalid, Spring will
automatically return an error message.
3. Handle Validation Errors:
○ If there are validation errors, you can capture them using a special object called BindingResult.
This object will contain all the error messages, which you can then send back to the user.
Why Backend Validation is Important
● Frontend Validation is Not Enough:
○ When you validate data on the frontend (like in a web form), users can easily bypass these
checks by editing the HTML code in their browser. For example, they can remove the validation
rules and submit invalid data.
● Backend Validation is Secure:
○ Backend validation happens on the server, where users can't tamper with the code. This makes
it much harder for someone to submit invalid data.
Example in Code
Let’s say you have a registration form where users enter their name, email, and age. Here’s how you might set
up the validation:
public class UserRegistrationDTO {
@NotNull(message = "Name cannot be null")
@Size(min = 2, max = 10, message = "Name should be between 2 and 10 characters")
private String name;
@Email(message = "Invalid email address")
private String email;
@Min(value = 18, message = "Age should be at least 18")
@Max(value = 100, message = "Age should not be more than 100")
private int age;
// Getters and Setters
In your controller, you would use @Valid to validate the data:
@PostMapping("/register")
public ResponseEntity<?> registerUser(@Valid @RequestBody UserRegistrationDTO user, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().body(result.getAllErrors());
// Save the user to the database
return ResponseEntity.ok("User registered successfully");
}
Summary
● Spring Validation helps you check if the data entered by users is correct before saving it to the
database.
● You add a validation dependency to your project and use annotations like @NotNull, @Size, @Email,
etc., to define rules for your data fields.
● You use @Valid in your controller to trigger validation and handle errors using BindingResult.
—-------------------------------------------------------------------------------------------------------------------------------------------------------
Date - 14/02
Spring Boot Security - Car Portal Project
1. Setting Up the Project
● Open IntelliJ IDEA
● Stop the server (if running)
● Visit Spring Initializr and create a new project
● Configure:
○ Project Name: car-portal
○ Dependencies:
■ Spring Data JPA
■ Spring Web
■ Spring Boot DevTools
■ MySQL Driver
■ Lombok (not used here due to system issues)
● Generate the project, extract files, and open in IntelliJ
2. Creating Project Structure
Inside com.carportal, create packages:
● controller → Handles API requests
● entity → Database models
● exception → Custom error handling
● config → Configuration files
● security → Security-related classes
● payload → Data transfer objects (DTOs)
3. Understanding Spring Security
Spring Security includes:
1. Authentication - Logging in and out
2. Authorization - Granting access based on roles
○ Example:
■ A bank manager can access admin features
■ A customer can only access personal account features
4. Creating the User Entity (JPA Model)
Inside entity package, create User.java:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private String mobile;
private String password;
// Generate Getters and Setters
● @Entity marks it as a database table
● @Id defines the primary key
● @GeneratedValue sets up auto-increment
5. Creating Authentication Controller
Inside controller, create AuthController.java:
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
@PostMapping("/signup")
public ResponseEntity<String> createUser(@RequestBody User user) {
return ResponseEntity.status(HttpStatus.CREATED).body("User created");
}
● @RestController → Handles HTTP requests
● @RequestMapping("/api/v1/auth") → API versioning
● @PostMapping("/signup") → User registration endpoint
6. Creating Repository Layer
Inside repository, create UserRepository.java:
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
Optional<User> findByMobile(String mobile);
Optional<User> findByUsername(String username);
● JpaRepository<User, Long> → Allows CRUD operations
● Finder methods → Help fetch users by email, mobile, or username
7. Handling Duplicate Users (Validation Before Signup)
Modify AuthController.java:
@Autowired
private UserRepository userRepository;
@PostMapping("/signup")
public ResponseEntity<String> createUser(@RequestBody User user) {
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Email ID already exists");
if (userRepository.findByMobile(user.getMobile()).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Mobile number already exists");
if (userRepository.findByUsername(user.getUsername()).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Username already exists");
}
userRepository.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully");
● Checks for existing users by email, mobile, or username
● Returns an error if a duplicate exists
● Saves the new user if no duplicate found
8. Next Steps
● Encrypt Passwords before saving
● Create Login API for user authentication
● Implement Role-Based Access Control (RBAC)
Date - 17/02
Lecture Explanation: Encrypting Passwords in a Spring Boot Car Portal Project
In today's class, we will focus on encrypting passwords and saving them securely in the database. This is a
crucial step in ensuring the security of user data, especially in production environments. Let’s break down the
lecture into a structured explanation.
1. Why Encrypt Passwords?
● Problem: Storing passwords in plain text in the database is a bad practice. If someone gains access to the
database, they can easily see all user passwords.
● Solution: Encrypt the password before saving it. Encryption converts the original password into a scrambled
text that cannot be understood by anyone who looks at it. Even if someone accesses the database, they
won’t be able to decipher the original password.
2. Steps to Encrypt Passwords
We will use Spring Security to encrypt passwords. Here’s how we’ll do it:
Step 1: Add Spring Security Dependency
● To use Spring Security, we need to add its dependency in the pom.xml file.
The dependency looks like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
●
Step 2: Configure Spring Security
● We need to create a configuration class to define security rules.
● In the SecurityConfig class, we disable CSRF (Cross-Site Request Forgery) and CORS (Cross-Origin
Resource Sharing) for simplicity during development.
Here’s the code:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable();
http.authorizeHttpRequests().anyRequest().permitAll();
return http.build();
● csrf().disable(): Disables Cross-Site Request Forgery (CSRF) protection (used for simplicity in
this example).
● cors().disable(): Disables Cross-Origin Resource Sharing (CORS) restrictions.
● anyRequest().permitAll(): Allows all requests without requiring authentication.
Step 3: Encrypt the Password
● We use the BCrypt algorithm to encrypt passwords. BCrypt is a strong hashing algorithm that is widely used
for password encryption.
In the AuthController, we encrypt the password before saving it to the database:
@PostMapping
public ResponseEntity<String> createUser(@RequestBody User user) {
// Check if email, mobile, or username already exists
Optional<User> opEmail = userRepository.findByEmail(user.getEmail());
if (opEmail.isPresent()) {
return new ResponseEntity<>("Email id exists", HttpStatus.INTERNAL_SERVER_ERROR);
Optional<User> opMobile = userRepository.findByMobile(user.getMobile());
if (opMobile.isPresent()) {
return new ResponseEntity<>("Mobile number exists", HttpStatus.INTERNAL_SERVER_ERROR);
Optional<User> opUsername = userRepository.findByUsername(user.getUsername());
if (opUsername.isPresent()) {
return new ResponseEntity<>("Username exists", HttpStatus.INTERNAL_SERVER_ERROR);
// Encrypt the password
String hashpw = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(12));
user.setPassword(hashpw);
// Save the user
userRepository.save(user);
return new ResponseEntity<>("User Created", HttpStatus.CREATED);
●
○ BCrypt.hashpw(): Encrypts the password.
○ BCrypt.gensalt(12): Generates a salt with a strength of 12 (higher means more secure but
slower).
Step 4: Verify the Encrypted Password
When a user logs in, we can verify the password using BCrypt.checkpw():
boolean isPasswordMatch = BCrypt.checkpw(plainPassword, hashedPassword);
●
○ plainPassword: The password entered by the user.
○ hashedPassword: The encrypted password stored in the database.
3. Understanding the Code
Let’s go through the key components of the code:
User Entity
● The User class represents the user entity with fields like id, username, email, mobile, and password.
● The password field is encrypted before being saved to the database.
UserRepository
● The UserRepository interface extends JpaRepository and provides methods to find users by email,
mobile, and username.
AuthController
● The AuthController handles user creation and password encryption.
● It checks if the email, mobile, or username already exists in the database.
● If not, it encrypts the password and saves the user.
Main Application
● The CarportalApplication class is the entry point of the Spring Boot application.
4. Testing the Application
1. Start the Application
● Run the CarportalApplication class to start the Spring Boot application.
● The Tomcat server will start, and the database tables will be created.
2. Create a User
● Use Postman to send a POST request to the /api/v1/auth endpoint.
Provide the user details in the request body:
{
"username": "ali",
"email": "ali@gmail.com",
"mobile": "962626293",
"password": "testing"
●
● The password will be encrypted and saved in the database.
3. Check the Database
● Open the database and verify that the password is stored in an encrypted format.
5. Additional Security Measures
● CSRF Protection: In production, enable CSRF protection to prevent cross-site request forgery attacks.
● CORS Configuration: Configure CORS properly to allow only trusted domains to access your API.
● Password Strength: Use a higher salt strength (e.g., 12) for better security, but be mindful of performance.
7. Common Interview Questions
1. What does http.csrf().disable() do?
○ Disables CSRF protection for APIs (used when clients like Postman access endpoints).
2. Why use BCrypt over MD5/SHA-256?
○ BCrypt is slow by design, making brute-force attacks harder. MD5/SHA are fast and insecure for
passwords.
3. What is the purpose of SecurityFilterChain?
○ Configures which endpoints are public/private and sets up authentication rules.
Conclusion
In this lecture, we learned how to:
1. Encrypt passwords using BCrypt.
2. Save encrypted passwords in the database.
3. Configure Spring Security for basic authentication.
4. Test the application using Postman.
By encrypting passwords, we ensure that user data remains secure even if the database is compromised. In the
next class, we’ll explore more advanced security features like JWT (JSON Web Tokens) for authentication.
Date - 18
Topic: Implementing Login Functionality in Spring Boot
1. Objective:
We are building a login system where a user can log in using their username and password. The system will
verify the credentials and return a response indicating whether the login was successful or not.
2. Steps to Implement Login:
1. Create a Login Endpoint:
○ We will create an API endpoint (/login) that accepts a username and password.
○ The username and password will be sent in the request body as a LoginDto (Data Transfer
Object).
2. Verify the Credentials:
○ The system will check if the username exists in the database.
○ If the username exists, it will compare the raw password (provided by the user) with the encrypted
password stored in the database.
3. Return a Response:
○ If the credentials are valid, the system will return a success response.
○ If the credentials are invalid, the system will return an error response.
3. Code Implementation:
Step 1: Create the LoginDto Class
● This class will hold the username and password sent by the user in the request body.
public class LoginDto {
private String username;
private String password;
// Getters and Setters
Step 2: Create the AuthController
● This controller will handle the login request.
● It will call the AuthService to verify the credentials.
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
private AuthService authService;
public AuthController(AuthService authService) {
this.authService = authService;
@PostMapping("/login")
public ResponseEntity<String> verifyLogin(@RequestBody LoginDto dto) {
boolean status = authService.authenticate(dto);
if (status) {
return new ResponseEntity<>("Verified", HttpStatus.OK);
} else {
return new ResponseEntity<>("Invalid", HttpStatus.OK);
}
Step 3: Create the AuthService
● This service will handle the business logic for verifying the credentials.
● It will use the UserRepository to fetch the user details from the database.
● It will compare the raw password with the encrypted password using BCrypt.
@Service
public class AuthService {
private UserRepository userRepository;
public AuthService(UserRepository userRepository) {
this.userRepository = userRepository;
public boolean authenticate(LoginDto dto) {
Optional<User> opUser = userRepository.findByUsername(dto.getUsername());
if (opUser.isPresent()) {
User user = opUser.get();
return BCrypt.checkpw(dto.getPassword(), user.getPassword());
return false;
Step 4: Create the UserRepository
● This repository will interact with the database to fetch user details.
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Step 5: Create the User Entity
● This entity represents the user table in the database.
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// Getters and Setters
4. Testing the Login Endpoint:
● Use Postman to test the /login endpoint.
● Send a POST request to http://localhost:8080/api/v1/auth/login with the following JSON
body:
"username": "Mike",
"password": "testing"
● If the credentials are correct, the response will be "Verified".
● If the credentials are incorrect, the response will be "Invalid".
5. Security Configuration:
● We need to configure Spring Security to allow access to the /login endpoint.
● Disable CSRF and CORS for simplicity (not recommended for production).
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable();
http.authorizeHttpRequests().anyRequest().permitAll();
return http.build();
6. Next Steps:
● JWT Token Integration: After verifying the credentials, we will generate a JWT token for authenticated
users.
● Role-Based Authentication: We will introduce roles (e.g., ADMIN, USER) and restrict access to certain
endpoints based on roles.
● OTP-Based Login: We will implement login using OTP (One-Time Password) for enhanced security.
Additional Explanation: Key Points from the Lecture
1. Understanding Login Implementation
Public Method in Controller:
The verifyLogin() method is declared as public and returns a ResponseEntity<String>. This allows it to
handle HTTP responses (e.g., success/failure messages and status codes).
Example:
@PostMapping("/login")
public ResponseEntity<String> verifyLogin(@RequestBody LoginDto dto) { ... }
●
2. Accepting Username and Password
● Two Methods for Credentials:
Query Parameters:
@RequestParam String username, @RequestParam String password
Example URL:
/login?username=Mike&password=testing
1.
Request Body (DTO):
Preferred for security and structure. The LoginDto class encapsulates credentials.
Example Request Body:
{ "username": "Mike", "password": "testing" }
2.
3. Generating Getters and Setters
● Why Getters/Setters?:
Required for encapsulation (accessing private fields like username and password in LoginDto).
IntelliJ Shortcut:
Right-click → Generate → Getters and Setters automates code generation.
Example for LoginDto:
public class LoginDto {
private String username;
private String password;
// Auto-generated getters/setters
●
4. Using @PostMapping Annotation
● Why POST?:
Sensitive data (passwords) should not be exposed in URLs (as with GET).
● Avoid Ambiguity:
If two methods use @PostMapping("/login"), Spring throws an error. Ensure unique endpoint paths.
5. Creating the Service Layer
● Role of AuthService:
Separates business logic (authentication) from the controller.
Annotations:
@Service marks the class as a Spring-managed service component.
@Service
public class AuthService { ... }
●
6. Verifying Username and Password
● Authentication Workflow:
1. Fetch User: Use userRepository.findByUsername(dto.getUsername()).
2. Check Existence: If Optional<User> is empty, return false.
3. Compare Passwords: Use BCrypt.checkpw(rawPassword, hashedPassword).
7. Accessing the Database
Repository Layer:
The UserRepository interface extends JpaRepository for CRUD operations.
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
●
● Why Optional?:
Safely handles cases where the user may not exist (avoids NullPointerException).
8. Handling Optional User Retrieval
Check User Presence:
Optional<User> opUser = userRepository.findByUsername(dto.getUsername());
if (opUser.isPresent()) {
User user = opUser.get();
// Proceed with password check
} else {
return false;
●
9. Comparing Hashed Passwords
● Security Note:
Never store raw passwords. Use hashing algorithms like BCrypt.
● How BCrypt Works:
The checkpw() method hashes the raw password and compares it with the stored hash.
10. Returning Authentication Status
● Boolean Result:
AuthService returns true (valid credentials) or false (invalid).
11. Calling the Service in Controller
Controller-Service Interaction:
The controller delegates authentication to AuthService and returns HTTP responses.
boolean status = authService.authenticate(dto);
return status ? ResponseEntity.ok("Verified") : ResponseEntity.ok("Invalid");
●
12. Testing with Postman
● Steps:
1. Set the HTTP method to POST.
2. URL: http://localhost:8080/api/v1/auth/login.
Body (JSON):
{ "username": "Mike", "password": "testing" }
3.
4. Send the request and check the response (Verified or Invalid).
13. Handling Common Errors
● Port Conflicts:
If the server fails to start, check if port 8080 is already in use.
● Invalid Credentials:
Returns "Invalid" but uses HttpStatus.OK (200). Consider using HttpStatus.UNAUTHORIZED
(401) for clarity.
14. JWT Token Integration (Upcoming)
● Purpose of JWT:
After successful login, generate a token to authenticate subsequent requests.
● Flow:
1. User logs in → Server returns a JWT.
2. User sends JWT in the header for protected routes.
15. Next Topics
● Role-Based Authorization:
Restrict access to endpoints based on roles (e.g., ADMIN, USER).
● OTP-Based Login:
Allow login via a one-time password sent to email/mobile.
Key Takeaways
● DTOs encapsulate data transfer between layers.
● Service Layer handles core logic (e.g., authentication).
● BCrypt ensures secure password storage and comparison.
● Optional safely handles database query results.
Date - 19 + 20
Simplified Explanation of JWT Tokens in Java Spring Boot
1. What is a JWT Token?
● A JWT token is a compact, URL-safe way to securely transmit information between two parties
(e.g., a client and a server).
● It is commonly used for authentication and authorization in web applications.
● JWT tokens are stateless, meaning the server does not store any user session information.
2. Why Do We Need JWT Tokens?
● Problem with Traditional Sessions:
○ In traditional session-based authentication, the server stores user session data (e.g.,
username, session ID) in a database or memory.
○ This approach becomes inefficient when there are thousands or millions of users, as it
creates a performance overhead (e.g., querying the database for every request).
○ It also makes the server stateful, meaning it has to maintain user session data.
● Solution (JWT Tokens):
○ JWT tokens allow the server to remain stateless.
○ The server generates a token after the user logs in and sends it to the client.
○ The client includes this token in every subsequent request.
○ The server verifies the token without needing to store any session data.
3. How JWT Tokens Work
1. User Login:
○ The client sends a request with a username and password to the server.
○ The server verifies the credentials and generates a JWT token.
○ The token is sent back to the client (e.g., browser or Postman).
2. Subsequent Requests:
○ The client includes the JWT token in the Authorization header of every request.
○ The server verifies the token's validity (e.g., checks the signature, expiry time, and user
details).
○ If the token is valid, the server processes the request and sends a response.
3. Token Expiry:
○ JWT tokens can have an expiry time (e.g., 5 minutes, 1 hour, etc.).
○ If the token expires, the user must log in again to get a new token.
4. Structure of a JWT Token
A JWT token consists of three parts, separated by dots (.):
1. Header:
○ Contains metadata about the token, such as:
■ Type of token (e.g., JWT).
■ Algorithm used for signing the token (e.g., HS256).
○ Example:
{
"alg": "HS256",
"typ": "JWT"
2. Payload:
○ Contains the actual data (claims) about the user, such as:
■ Username.
■ Expiry time of the token.
■ Issuer (who generated the token).
○ Example:
{
"username": "john_doe",
"exp": 1672444800,
"iss": "my_app"
3. Signature:
○ A cryptographic signature that ensures the token's integrity.
○ It is created by combining the header, payload, and a secret key (known only to the server).
○ Example:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret_key)
5. Advantages of JWT Tokens
1. Stateless Communication:
○ The server does not need to store user session data, reducing overhead and improving
scalability.
2. Expiry Time:
○ Tokens can be set to expire after a specific time (e.g., 5 minutes, 24 hours).
3. Security:
○ Tokens are encrypted and signed, making them secure.
4. Third-Party Integration:
○ JWT tokens can be used to securely integrate third-party APIs (e.g., AWS, Twilio).
6. Practical Use Cases
● Securing APIs:
○ JWT tokens act as an alternative login mechanism, ensuring only authenticated users can
access protected resources.
○ Example: Angular applications sending JWT tokens with API requests.
● Third-Party Authentication:
○ JWT tokens are used to authenticate with external services (e.g., AWS, Zoom, Twilio).
7. Code Implementation
Here’s how JWT tokens are implemented in a Spring Boot application:
1. Add JWT Dependency:
Add the auth0 JWT library to your pom.xml:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
○
2. JWT Service Class:
Create a service to generate and verify tokens:
@Service
public class JWTService {
@Value("${jwt.key}") // Secret key from properties file
private String algorithmKey;
@Value("${jwt.expiry-time}") // Expiry time in milliseconds
private int expiry;
private Algorithm algorithm;
@PostConstruct
public void init() {
algorithm = Algorithm.HMAC256(algorithmKey); // Initialize algorithm
}
public String generateToken(String username) {
return JWT.create()
.withClaim("name", username) // Add username to payload
.withExpiresAt(new Date(System.currentTimeMillis() + expiry)) // Set expiry
.withIssuer("carportal.com") // Set issuer
.sign(algorithm); // Sign the token
○
3. Authentication Service:
Verify user credentials and generate a token:
@Service
public class AuthService {
private UserRepository userRepository;
private JWTService jwtService;
public AuthService(UserRepository userRepository, JWTService jwtService) {
this.userRepository = userRepository;
this.jwtService = jwtService;
public String authenticate(LoginDto dto) {
Optional<User> user = userRepository.findByUsername(dto.getUsername());
if (user.isPresent() && BCrypt.checkpw(dto.getPassword(), user.get().getPassword())) {
return jwtService.generateToken(user.get().getUsername()); // Generate token
return null; // Invalid credentials
○
4. Controller:
Handle login requests and return the token:
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
private AuthService authService;
public AuthController(AuthService authService) {
this.authService = authService;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginDto dto) {
String token = authService.authenticate(dto);
if (token != null) {
return ResponseEntity.ok(token); // Return token
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
○
8. Testing with Postman
1. Send a login request with username and password.
2. If valid, the server returns a JWT token.
3. Use the token in subsequent requests by adding it to the Authorization header:
○ Header: Authorization: Bearer <token>
9. Debugging JWT Tokens
● Use tools like jwt.io to decode and verify tokens.
● Paste the token into the debugger to view its header, payload, and verify the signature.
10. Key Takeaways
● JWT tokens enable stateless, secure, and scalable authentication.
● They consist of header, payload, and signature.
● Tokens can have an expiry time and are encrypted for security.
● JWT tokens are widely used in modern web applications for API security and third-party
integrations.
Date - 25/02 and 26/02
Alright, let's go line by line, just like a live explanation from your sir!
🔹 JWTFilter.java (JWT Authentication Filter)
📌 First, we have this class JWTFilter, which extends OncePerRequestFilter
This ensures that the filter runs only once per request.
@Component
public class JWTFilter extends OncePerRequestFilter {
● @Component → This registers the filter as a Spring Bean.
● Extends OncePerRequestFilter → So this filter runs once per HTTP request.
📌 Next, we inject JWTService to handle token operations.
private JWTService jwtService;
public JWTFilter(JWTService jwtService) {
this.jwtService = jwtService;
● We are injecting JWTService using constructor injection.
📌 Now, inside doFilterInternal(), we extract the token from the header.
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String jwtToken = token.substring(7, token.length());
String username = jwtService.getUsername(jwtToken);
System.out.println(username);
● We get the Authorization header.
● If it starts with "Bearer ", we remove "Bearer " and extract the JWT token.
● Then, we use jwtService.getUsername(jwtToken) to extract the username from the token.
● System.out.println(username); → Just printing to check if it's working.
Finally, we continue the request by calling:
filterChain.doFilter(request, response);
🔹 SecurityConfig.java (Spring Security Configuration)
📌 Now, here in the SecurityConfig class, we define security settings.
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
● @Configuration → Marks this as a Spring configuration class.
● @Bean method securityFilterChain() → This is where we configure Spring Security.
📌 Now, here we are disabling CSRF and CORS.
http.csrf().disable().cors().disable();
● .csrf().disable(); → CSRF protection is turned off (because we're using JWT, not cookies).
● .cors().disable(); → CORS (Cross-Origin Resource Sharing) is disabled for now.
📌 Then, we allow all requests without authentication.
http.authorizeHttpRequests().anyRequest().permitAll();
● .authorizeHttpRequests().anyRequest().permitAll();
→ Right now, we are allowing all requests without authentication.
→ If we want to protect APIs, we will modify this later.
Finally, we build and return the security filter chain:
return http.build();
🔹 AuthController.java (User Authentication Controller)
📌 Now, this is our authentication controller.
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
● @RestController → Defines this as a REST API controller.
● @RequestMapping("/api/v1/auth") → All authentication-related APIs will have this base URL.
📌 Signup method: Creating a new user.
@PostMapping("/signup")
public ResponseEntity<String> createUser(@RequestBody User user) {
● @PostMapping("/signup") → This handles the signup request.
● @RequestBody User user → The user details will be received as JSON.
📌 Now, checking if email, mobile, or username already exists.
Optional<User> opEmail = userRepository.findByEmail(user.getEmail());
if (opEmail.isPresent()) {
return new ResponseEntity<>("Email id exists", HttpStatus.INTERNAL_SERVER_ERROR);
● If the email already exists, return an error.
● Similarly, we check for mobile and username:
Optional<User> opMobile = userRepository.findByMobile(user.getMobile());
if (opMobile.isPresent()) {
return new ResponseEntity<>("Mobile number exists", HttpStatus.INTERNAL_SERVER_ERROR);
}
Optional<User> opUsername = userRepository.findByUsername(user.getUsername());
if (opUsername.isPresent()) {
return new ResponseEntity<>("Username exists", HttpStatus.INTERNAL_SERVER_ERROR);
📌 Now, we hash the password before saving.
String hashpw = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(12));
user.setPassword(hashpw);
userRepository.save(user);
return new ResponseEntity<>("User Created", HttpStatus.CREATED);
● BCrypt.hashpw() → Hashes the password before saving.
● Finally, we save the user and return "User Created".
📌 Login method: Verifying credentials and generating JWT.
@PostMapping("/login")
public ResponseEntity<String> verifyLogin(@RequestBody LoginDto dto) {
● Receives username and password in LoginDto.
📌 Now, authenticate the user using authService.authenticate(dto).
String jwtToken = authService.authenticate(dto);
if (jwtToken != null) {
return new ResponseEntity<>(jwtToken, HttpStatus.OK);
} else {
return new ResponseEntity<>("Invalid", HttpStatus.OK);
● If login is successful, return the JWT token.
● Otherwise, return "Invalid".
🔹 AuthService.java (Authentication Logic)
📌 Here in AuthService, we handle authentication.
Optional<User> opUser = userRepository.findByUsername(dto.getUsername());
● First, check if the username exists.
📌 Then, verify the password using BCrypt.
boolean status = BCrypt.checkpw(dto.getPassword(), user.getPassword());
● If the password matches, we generate a JWT token:
return jwtService.generateToken(user.getUsername());
🔹 JWTService.java (JWT Token Service)
📌 Now, this is where we generate and verify JWT tokens.
@Value("${jwt.key}")
private String algorithmKey;
@Value("${jwt.issuer}")
private String issuer;
@Value("${jwt.expiry-time}")
private int expiry;
● These values come from application.properties.
📌 Generating the JWT token.
public String generateToken(String username) {
return JWT.create()
.withClaim("name", username)
.withExpiresAt(new Date(System.currentTimeMillis() + expiry))
.withIssuer(issuer)
.sign(algorithm);
● Stores username inside the JWT (.withClaim("name", username)).
● Sets expiration time.
● Signs the token using HMAC256.
📌 Extracting username from JWT.
public String getUsername(String token) {
DecodedJWT decodedJwt = JWT.require(algorithm)
.withIssuer(issuer)
.build()
.verify(token);
return decodedJwt.getClaim("name").asString();
● Decodes and verifies the token.
● Extracts "name" (username) from JWT claims.
🔹 CarController.java (Test API)
📌 A simple API to check if everything is working.
@GetMapping
public String getMessage() {
return "Hello World!";
● If authentication is added later, only logged-in users can access this.
🔹 Main Application (CarportalApplication.java)
📌 This starts the Spring Boot application.
@SpringBootApplication
public class CarportalApplication {
public static void main(String[] args) {
SpringApplication.run(CarportalApplication.class, args);
● Boots up the entire application.
Date - 27/02
Structured Lecture Notes: JWT Authentication Flow in Spring Boot
1. Recap & Introduction
(Engaging the audience)
"Alright folks, let's pick up where we left off! Last time, we implemented token validation in our filter. Remember how
we extracted the username from valid tokens? Today, we'll complete the authentication flow by connecting this to
Spring Security's authorization system. Who's ready to see how all these pieces fit together?"
2. JWT Filter Deep Dive
(Code walkthrough with explanations)
Key Components:
@Component
public class JWTFilter extends OncePerRequestFilter {
// Constructor injection for dependencies
public JWTFilter(JWTService jwtService, UserRepository userRepository) {
// ... initializations ...
}
}
Step-by-Step Flow:
1. Token Extraction:
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String jwtToken = token.substring(7); // Remove "Bearer " prefix
(Explanation)
"Here's where we intercept every request. We check for the Authorization header and peel off the 'Bearer ' prefix to
get our raw JWT."
2. Username Extraction:
String username = jwtService.getUsername(jwtToken);
(Real-world analogy)
"Think of this like decoding a secret message. If the signature matches, we get the username – our golden ticket to
user details!"
3. Database Lookup:
Optional<User> opUser = userRepository.findByUsername(username);
(Best practice tip)
"Always check if the user actually exists! Tokens might be valid, but users could be deleted. Never trust data
blindly."
4. Authentication Token Creation:
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(user, null, null);
authToken.setDetails(new WebAuthenticationDetails(request));
(Conceptual explanation)
"We're creating Spring Security's version of a VIP pass here. The null parameters are for credentials and
authorities – we handle those elsewhere."
5. Security Context Setup:
SecurityContextHolder.getContext().setAuthentication(authToken);
(Critical importance)
"This is where magic happens! By setting this in the security context, we're telling Spring Security: 'Hey, this user is
legit! Let them through!'"
3. Security Configuration
(Interactive configuration breakdown)
SecurityFilterChain Configuration:
http.authorizeHttpRequests()
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/user/signup")
.permitAll()
.anyRequest().authenticated();
(Visual analogy)
"Imagine this as a bouncer at a club. These specific endpoints (/login, /signup) are on the guest list – no token
needed. Everything else? Show your JWT wristband or you're not getting in!"
Filter Chain Integration:
http.addFilterBefore(jwtFilter, AuthorizationFilter.class);
(Architecture insight)
"We're inserting our custom JWT filter early in the security pipeline. It's like installing a security checkpoint before
guests even reach the main door."
4. Endpoint Protection in Action
(Practical demonstration)
Protected Controller Example:
@RestController
@RequestMapping("/api/v1/car")
public class CarController {
@GetMapping
public String getMessage() {
return "Hello World!";
}
}
(Live testing scenario)
"Without a valid token, accessing /api/v1/car would give a 403 Forbidden. But with our JWT filter working,
authenticated users get the secret greeting!"
5. Entity & Service Layer Integration
(Database relationships explained)
User Entity Structure:
@Entity
public class User {
// ... fields with unique constraints ...
private String role; // Critical for authorization
}
(Security emphasis)
"Notice the role field? That's our next frontier! Currently set to ROLE_USER for all, but imagine extending this for
admin roles and granular permissions."
AuthService Workflow:
public String authenticate(LoginDto dto) {
// Password matching with BCrypt
boolean passwordMatch = BCrypt.checkpw(rawPassword, storedHash);
}
(Security best practice)
"Never store raw passwords! BCrypt's slow hashing makes brute-force attacks impractical. Even if someone
breaches our DB, passwords remain protected."
6. JWT Service Mechanics
(Cryptography explained simply)
Token Generation:
public String generateToken(String username) {
return JWT.create()
.withClaim("name", username)
.withExpiresAt(expiryDate)
.sign(algorithm);
}
(Token anatomy lesson)
"We're baking a security cookie here: username as the filling, expiration date as the 'best before' label, and the
algorithm signature as our tamper-proof seal."
Token Validation:
public String getUsername(String token) {
DecodedJWT decoded = JWT.require(algorithm)
.build()
.verify(token);
}
(Error handling note)
"If verification fails, this throws exceptions. In production, we'd want to catch those and return proper error
responses instead of 500s."
7. Putting It All Together
(End-to-end flow visualization)
1. User logs in → Gets JWT
2. Subsequent requests include JWT in header
3. JWT Filter validates token → Loads user details
4. Security Context updated → Access granted
5. Protected endpoints return data
(Real-world analogy)
"It's like getting a museum pass: Buy ticket (login) → Get wristband (JWT) → Show wristband at exhibits (protected
endpoints) → Enjoy access!"
8. Next Steps & Homework
(Engaging conclusion)
"Great job following along! For next time:
1. Experiment with adding roles to tokens
2. Try implementing token refresh functionality
3. Challenge: Add a logout mechanism that invalidates tokens
Stuck? Remember our three-step debugging mantra:
1. Check token in headers
2. Verify user exists in DB
3. Validate signature algorithm matches
Date - 28/02
Structured Lecture Notes: Implementing Role-Based
Authorization in Spring Boot
1. Introduction to Authorization
(Setting the stage)
"Alright team, we've mastered authentication – now let's tackle authorization! Imagine a club where VIPs get
backstage access while regular members don't. That's exactly what we're building today – role-based access
control using Spring Security!"
2. Database Schema Update
(Hands-on database modification)
User Entity Modification:
@Column(name = "role", nullable = false)
private String role;
Migration Explanation:
"We're adding a role column to our users table. This will store values like ROLE_USER or ROLE_OWNER.
Remember: Spring Security expects the ROLE_ prefix by default!"
Why the Prefix Matters:
"Spring Security uses this prefix internally for role checking. It's like a secret handshake – without ROLE_, the
security system won't recognize our roles!"
3. Enhanced JWT Filter
(Code deep dive with security concepts)
Updated Authentication Token Creation:
Collections.singleton(new SimpleGrantedAuthority(user.getRole()))
Breaking it down:
1. SimpleGrantedAuthority – Wraps our role string into a Spring Security-compatible authority object
2. Collections.singleton – Creates an immutable set containing a single element
3. Why Singleton? – Each user has one primary role in this implementation
Security Context Setup:
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
Real-world analogy:
"This is like issuing a security badge with specific access levels. Once set, Spring Security knows exactly what
areas this user can access!"
4. Security Configuration Updates
(Granular access control demonstration)
Endpoint Security Rules:
http.authorizeHttpRequests()
.requestMatchers("/api/v1/car").hasRole("USER")
.anyRequest().authenticated();
Visualizing Access Control:
● /api/v1/car → Exclusive VIP lounge for USER roles
● All other endpoints → Accessible to any authenticated user
● Public endpoints → Login and signup URLs
Common Pitfall Alert:
"Notice we use hasRole("USER") and not hasRole("ROLE_USER")? Spring automatically adds the prefix!
This tripped me up earlier – save yourself the headache!"
5. Multi-Role Signup Implementation
(Scalable user creation strategy)
Owner Signup Endpoint:
@PostMapping("/owner/signup")
public ResponseEntity<String> createOwner(@RequestBody User user) {
user.setRole("ROLE_OWNER");
// ... validation logic ...
Best Practice Discussion:
"Why create separate endpoints? It allows:"
1. Different validation rules per role
2. Clear API contract
3. Easy auditing of user types
Security Config Whitelisting:
.permitAll("/api/v1/auth/login", "/api/v1/auth/user/signup", "/api/v1/auth/owner/signup")
Security Reminder:
"Always remember to add new public endpoints here! A secure endpoint accidentally left public is like leaving your
house keys under the mat!"
6. Testing Workflow
(Live debugging session)
Step 1: User Signup
POST /api/v1/auth/user/signup
"username": "mike",
"password": "SecurePass123!",
"email": "mike@example.com",
"mobile": "1234567890"
}
Step 2: Owner Signup
POST /api/v1/auth/owner/signup
"username": "stalin",
"password": "OwnerPass456!",
"email": "stalin@example.com",
"mobile": "0987654321"
Database Verification:
"After signup, always check:"
1. Role column populated correctly
2. BCrypt password hashing
3. Unique constraints enforced
7. Role-Based Access Testing
(Practical demonstration with Postman)
Scenario 1: User Access
1. Login with user credentials → Get JWT
2. Access /api/v1/car → Success (200 OK)
Scenario 2: Owner Access
1. Login with owner credentials → Get JWT
2. Access /api/v1/car → Forbidden (403)
Teaching Moment:
"See how Spring automatically enforces our role rules? The owner's JWT might be valid, but without USER role,
they're locked out – perfect authorization in action!"
8. Advanced Configuration Options
(Professional development tips)
Multiple Role Access:
.requestMatchers("/admin").hasAnyRole("ADMIN", "SUPER_ADMIN")
Role Hierarchy:
"Want senior roles to inherit permissions? Configure a role hierarchy bean for cascading access rights!"
Custom Access Decision Voters:
"For complex rules, create custom voters that check business logic beyond simple role checks!"
9. Production-Ready Considerations
(From classroom to production)
1. Role Management: Implement role update endpoints with proper admin protection
2. Audit Logging: Track role changes and access attempts
3. Token Refresh: Implement token rotation for long-lived sessions
4. Rate Limiting: Protect signup/login endpoints from abuse
10. Homework & Challenges
(Encouraging exploration)
1. Implement Admin Dashboard → Create /admin endpoints accessible only to ROLE_ADMIN
2. Role Inheritance → Make OWNERs inherit USER privileges
3. JWT Role Claims → Store roles directly in tokens for faster validation
4. Test Coverage → Achieve 100% test coverage on security endpoints
Security Reminder:
"Remember: Security is never done! Always think like a hacker – how would you breach your own system?
Then fix those vulnerabilities!"
Code Quality Spotlight
(Industry-standard practices)
1. Immutable Collections: Using Collections.singleton() prevents accidental authority list
modification
2. Constructor Injection: Secure dependency management pattern
3. BCrypt Hashing: Industry-standard password protection
4. Separation of Concerns: Clear division between auth controller and security config
Final Thoughts
"Congratulations! You've now implemented professional-grade authorization. These patterns are used in
🎩✨
banking systems, healthcare platforms, and government applications. Next time you use an app with different
user tiers, remember – you know the magic behind the curtain!"
Date - 03/03
Here’s the final, perfectly structured lecture notes that merge both versions seamlessly, ensuring no
repetitions while keeping all key explanations intact.
Structured Lecture Notes: Mastering Maven for
Java Development
(Live Lecture Style with Conversational Tone)
1. Introduction to Maven
Lecturer: "Alright, everyone! Let’s kick things off with Maven. You’ve probably heard it’s a build automation tool, but
today we’ll go beyond that. Why? Because Maven is the backbone of Java project management!"
Key Takeaways
1. What is Maven?
○ Build Automation: Automates tasks like compiling code, running tests, packaging JARs.
○ Dependency Management: Downloads libraries (e.g., Spring, Hibernate) automatically.
○ Project Structure: Enforces standardized folder layouts via archetypes.
2. "Imagine you’re baking a cake. Maven is like your recipe book, mixer, and shopping list all in one!"
3. Maven vs. Ant vs. Gradle
○ Ant: Older, flexible but requires manual scripting.
○ Gradle: Modern, uses Groovy/Kotlin DSL. Faster but steeper learning curve.
○ Maven: Convention-over-configuration. Perfect for Java projects with its "batteries-included"
approach.
2. Maven’s Core Concepts
1. Project Structure & Archetypes
Lecturer: "Ever wondered why every Maven project looks the same? That’s archetypes at work!"
Standard Directory Layout:
my-project/
├── src/
│ ├── main/
│ │ ├── java/ # Source code
│ │ └── resources/ # Config files
│ └── test/ # Test code
└── pom.xml # Project configuration
● "No more chaos! Maven forces structure, so your teammate doesn’t put HTML files in the java/ folder!"
● Creating a Project:
○ In Eclipse/IntelliJ: File → New → Maven Project.
○ Choose an archetype (e.g., maven-archetype-quickstart for a simple Java app).
2. The POM File: Project Object Model
Lecturer: "The pom.xml is Maven’s brain. Let’s dissect it!"
<project>
<groupId>com.itexpdf</groupId> <!-- Reverse domain (unique identifier) -->
<artifactId>crm-app</artifactId> <!-- Project name -->
<version>1.0.0</version> <!-- Semantic versioning -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</project>
● groupId: Unique identifier (e.g., com.companyname).
● artifactId: Name of the JAR/WAR.
● Dependencies: Maven downloads these from Maven Central Repository automatically.
"Think of groupId as your project’s last name and artifactId as its first name!"
3. Maven Build Lifecycle
Lecturer: "Maven’s lifecycle is like a factory assembly line. Let’s see how it works!"
1. Clean: mvn clean
○ Deletes the target/ folder. "Out with the old, in with the new!"
2. Compile: mvn compile
○ Converts .java to .class files.
3. Test: mvn test
○ Runs JUnit tests using the Surefire Plugin.
4. Package: mvn package
○ Creates a JAR/WAR file in target/.
"Pro Tip: Run mvn clean install to clean, compile, test, and package in one command!"
4. Maven Setup Deep Dive
Step 1: Install & Configure Maven
JAVA_HOME = C:\Program Files\Java\jdk-21
MAVEN_HOME = C:\Tools\apache-maven-3.9.6
PATH += %JAVA_HOME%\bin;%MAVEN_HOME%\bin
Common Pitfall:
"Got 'mvn' is not recognized? Restart CMD after setting variables – environment refreshes don’t happen
magically!"
Step 2: Validate Installation
mvn -v
# Output:
Apache Maven 3.9.6
Java version: 21.0.2
"Congratulations! You’ve just joined the 87% of Java devs who use Maven daily (2023 Stack Overflow Survey)."
5. Plugins: Supercharging Maven
Surefire Plugin (JUnit Testing)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
Pro Tip: Use mvn test -Dtest=MyTestClass to run specific tests during debugging!
6. Maven in CI/CD Pipeline
Jenkins Integration Example
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn clean package'
"Interview Gold: When asked about CI/CD, highlight how Maven’s predictable lifecycle enables automated
deployments – music to hiring managers’ ears!"
7. Common Pitfalls & Solutions
Issue Fix
Dependency conflicts Use mvn dependency:tree
Slow downloads Configure mirror in
settings.xml
Test failures Use -DskipTests (temporary!)
8. Homework & Interview Prep
Hands-on Tasks
Create a Multi-Module Project:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
1.
Explore Effective POM:
mvn help:effective-pom
2.
Common Interview Questions
1. What’s the difference between groupId and artifactId?
○ groupId = organization (e.g., com.microsoft), artifactId = project name (e.g., azure-sdk).
2. How does Maven resolve dependencies?
○ Checks local repository (~/.m2), then downloads from Maven Central.
3. What’s a transitive dependency?
○ Libraries your dependencies depend on (e.g., Spring Boot pulls in Jackson, Tomcat).
4. How does Maven resolve dependency version conflicts?
○ Uses nearest definition in the dependency tree (closest to the project root wins).
Final Thought
🛠️💡
"Maven isn’t just a tool – it’s the Swiss Army knife that keeps 20 million Java projects (GitHub, 2024) building
smoothly. Master it, and you’ve mastered project scalability!"
Date - 04/03
Maven: Dependency Exclusion and Starter Dependencies
Recap of the Previous Lecture
Alright, guys, let’s get started! Yesterday, we talked about Maven and its lifecycle phases, including:
● clean
● compile
● test
● package
We also ran these phases practically in our project. But we didn’t discuss dependency exclusion, which is a very
important interview question. So, let’s dive into it now.
Understanding Dependency Exclusion in Maven
Imagine you have two libraries:
● Library B (child library)
● Library A (parent library)
Now, Library B depends on Library A. This means when we add Library B to our pom.xml, Maven
automatically downloads Library A as well. But what if we don’t actually need Library A in our project?
This happens because of transitive dependency.
What is a Transitive Dependency?
A transitive dependency is a library that is indirectly added to your project because it is required by another
dependency.
For example:
● If Library B depends on Library A, and you add Library B, then Library A also gets downloaded
automatically.
● This increases project size and build time, making compilation and packaging slower.
Example: Spring Context and Its Transitive Dependencies
Let’s say you add the Spring Context dependency in your pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
Spring Context itself has transitive dependencies like:
● Spring Core
● Spring Beans
● Spring AOP
● Spring Expression
● Spring JCL
When we add spring-context, all these dependencies get downloaded automatically.
How to Exclude Unwanted Dependencies?
Now, let’s say we don’t need Spring AOP. We can exclude it using the <exclusions> tag:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
● Now, Spring AOP will not be downloaded.
● This helps in optimizing project size and build time.
Starter Dependencies in Spring Boot
Now, let’s move on to another important topic: Starter Dependencies.
Difference Between Transitive and Starter Dependencies
● Transitive dependencies → Automatically downloaded because they are associated.
● Starter dependencies → A pre-packaged set of dependencies that simplifies configuration.
Analogy: Ordering Food in a Restaurant 🍽️
Think of this as ordering food in a hotel:
● Without Starter Dependencies → You order items one by one (soup, curry, roti, rice).
● With Starter Dependencies → You order a North Indian meal, and everything (roti, curry, rice, sweets)
comes as a package.
Starter dependencies bundle multiple required dependencies together, so we don’t have to add them manually.
Example: Hibernate in Spring Framework
Before Spring Boot, if you wanted to use Hibernate, you had to manually add:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.7.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!-- And many more dependencies... -->
This is too much work!
Solution: Using a Starter Dependency
With Spring Boot, we can simply use:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.6.4</version>
</dependency>
This automatically includes Hibernate, MySQL Connector, and all necessary dependencies.
Key Takeaways:
✅ Starter dependencies simplify configuration.
✅ No need to manually add multiple dependencies.
✅ Not necessarily transitive dependencies, but they are grouped together for ease of use.
2. Source Code Management: Why It Matters
(Lessons from Fidelity’s Insurance Project)
a. Team Collaboration Workflow
How Do Global Teams Work Together?
Imagine a software project where teams from different time zones contribute code. Without a structured approach,
managing changes, resolving conflicts, and ensuring code quality would be chaotic. This is where Git and GitHub
come in, enabling seamless collaboration.
graph LR
A[India Team] -->|Push Code| C[GitHub]
B[USA Team] -->|Pull Code| C
C -->|Single Source| D[Integrated Application]
Real-World Scenario (Fidelity’s Insurance Project):
● The India Team develops the login functionality using username & password.
● The USA Team enhances security by adding an OTP verification feature.
● They push their changes to GitHub, ensuring the latest version is always available.
● A new developer joins → Clones the repository → Fixes bugs while tracking previous changes.
💡 Key Takeaway: GitHub acts as a single source of truth, ensuring smooth integration without code conflicts.
b. Key Benefits of Git/GitHub
1. Code Integration Across Teams
"Merge contributions from 20+ developers across different time zones seamlessly!"
● Developers push their updates without overriding others’ work.
● Git automatically detects conflicts, allowing resolution before merging.
2. History Tracking & Accountability
Every change is logged, making it easy to track who modified what and why.
git blame MyFile.java # See who changed each line
git log --author="John" # Audit John’s contributions
💡 Use case: If a bug appears, developers can quickly trace the exact commit where the issue started.
3. Disaster Recovery & Rollback
What if the latest deployment crashes production? No worries! Git lets you roll back instantly.
git revert HEAD~1 # Undo the latest commit safely
💡 Use case: If a critical error is introduced, the team can restore the last stable version while debugging the
issue offline.
3. Corporate Use Case: Fidelity’s Title Insurance
The Challenge
● Fidelity had 5 buildings full of physical policy paperwork.
● They needed to digitize records while ensuring accuracy.
● Development teams in India and the USA worked asynchronously, requiring a structured source code
workflow.
The Solution: Version Control with Git
1. ClearCase (IBM’s Tool) – The Old Approach
● Used for tracking document verification workflows.
● Enabled parallel development of insurance modules without conflicts.
2. Git – The Modern Solution
● Developers pull the latest code, work on features in isolated branches, and push updates efficiently.
# Daily workflow for distributed teams:
git pull origin main # Get the latest version
git checkout -b feature/otp-login # Create a branch for OTP feature
git push --set-upstream origin feature/otp-login
🔥 Pro Tip:
Use git cherry-pick to selectively apply critical bug fixes from one branch to another without merging
unnecessary features.
4. Interview Prep: Top 3 Questions
1️⃣ Q: How do you resolve JAR hell in Maven?
A: "Use <exclusion> tags + mvn dependency:tree to identify conflicts."
2️⃣ Q: What’s the difference between git pull and git fetch?
A: "fetch retrieves changes without merging. pull = fetch + merge automatically."
3️⃣ Q: Why use starter dependencies in Spring Boot?
A: "They reduce POM bloat – one tag replaces 10+ manual dependencies!"
5. Hands-On Exercise: Spring Boot & Git
Task: Modify a Spring Boot App to Use Jetty Instead of Tomcat
💡 By default, Spring Boot uses Tomcat, but in some cases, Jetty might be preferred for better performance.
Steps to Configure Jetty:
1. Exclude Tomcat from spring-boot-starter-web
2. Add Jetty dependency manually
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
✅ Expected Outcome: The app should now run on Jetty instead of Tomcat when started.
Date - 05/03
Understanding Git Architecture with a Real-World
Example
Alright, today we’re going to discuss Git architecture. Fine? So let’s assume a scenario to help us understand this
better.
A Real-World Scenario: A Marketing Company Managing Photos
Imagine that I have 12,345 photos—a huge collection. Now, let’s say there’s a marketing company that works with
big brands like Parle-G, Colgate, etc. to do advertisements and branding.
Now, let’s assume Parle-G wants to hire a brand ambassador, say Amitabh Bachchan, for their next campaign.
What does the marketing company do?
1. Contact Amitabh Bachchan – They discuss commercials and finalize everything.
2. Photoshoot – They take multiple pictures of Amitabh for the campaign.
3. Selection Process – Out of all the photos clicked, they pick only a few for advertisements.
4. Distribution – These selected photos are then sent for:
○ Newspaper advertisements
○ Billboards
○ Product packaging
○ Online promotions
Now, let’s say Parle-G selects 5 photos. These 5 photos will be stored in multiple places:
● One copy will be stored in Google Drive (so that everyone can access it).
● Another copy will be stored on a hard disk (for backup).
● Some photos might be kept for future reference.
Now, why did I explain this? Because this is exactly how Git works!
Mapping This Concept to Git
Git follows a similar structure when managing code files. Let’s break it down:
1. Working Tree (Working Directory)
● Scenario: The marketing company has 12,345 raw photos of Amitabh Bachchan.
● Git Equivalent: This is your working directory—where all project files (photos) initially reside.
● Key Point: All files here are unorganized and unselected.
2. Staging Area
● Imagine we’re selecting only the best 5 photos for branding.
● Similarly, in Git, we stage only the required files before committing them.
● The staging area is where we prepare our changes before saving them permanently.
● Scenario: The company selects 5 photos to share with Parle-G for approval.
● Git Equivalent: The staging area (.git/index). Use git add to move files here.
● Command: git add photo1.jpg photo2.jpg
● Natural Expression: "Think of staging as your shortlist before final approval."
3. Local Repository
● Now, once we finalize the 5 selected photos, we store them safely in our local storage.
● In Git, this is equivalent to committing the staged files to our local repository.
● This ensures our selected files are saved properly before we share them with the team.
● Scenario: Parle-G approves 3 photos, stored securely on the company’s hard drive.
● Git Equivalent: The local repository (.git folder). Use git commit to save here.
● Command: git commit -m "Selected 3 photos for Parle-G campaign"
● Clarification: "Your local repo is like a personal vault—only you control it."
4. Remote Repository (GitHub, GitLab, Bitbucket)
● Finally, to make sure the marketing company and Parle-G can access the photos, we upload them to
Google Drive.
● In Git, we push our local commits to a remote repository (GitHub, Bitbucket, etc.) so that everyone in
the team can access them.
● Scenario: The approved photos are uploaded to Google Drive for wider access.
● Git Equivalent: Remote repositories (GitHub, GitLab). Use git push to upload.
● Command: git push origin main
● Analogy: "Google Drive ensures everyone gets the latest files, just like GitHub!"
Git Commands & Workflow
Now, let’s see how we actually do this using Git.
Step 1: Check Files in the Working Directory
git status
● This command lists all the files in the working tree.
● It tells us which files are untracked (not staged yet) and which are staged.
Step 2: Add Files to the Staging Area
git add <file_name>
or to add all files:
git add . # Stages all files
git add photo3.jpg # Stages a specific file
● This moves the files to the staging area, just like selecting the best photos for branding.
Step 3: Commit the Changes to Local Repository
git commit -m "Added selected photos for branding"
● This saves the files in the local repository, just like storing selected photos on a hard disk.
Step 4: Push the Changes to Remote Repository
git push origin main
● This uploads the committed changes to GitHub (or another remote repository), making them accessible to
the whole team.
Installing and Setting Up Git
Part 3: Setting Up Git & GitHub
1. Install Git:
● Download from git-scm.com.
● Pro Tip: Remove old versions via Control Panel first.
2. Configure Repositories:
Local Repo Setup:
git init # Initializes a local repo in your project folder
●
Link to Remote Repo (GitHub):
git remote add origin <GitHub-URL> # Connects local to remote
●
3. Cloning a Repository:
git clone <GitHub-URL> # Use this ONCE to copy a repo to your machine
Key Concepts Clarified
Public vs. Private Repos:
● Public: Anyone can view, but only collaborators can edit.
● Private: Restricted access (ideal for proprietary code).
Branches (Future Topic):
● "Imagine creating a copy of your project to test changes without affecting the main campaign. We’ll cover
this next!"
Common Pitfalls & Pro Tips
1. Credentials Management:
Use:
git config --global credential.helper store
● to save GitHub credentials securely.
● Reminder: Clean old credentials via Windows Credential Manager if stuck.
2. Best Practices:
● Commit messages should be descriptive (e.g., "Fixed image sizing bug").
● Use .gitignore to exclude temporary files (e.g., node_modules/, .env).
Conclusion & Homework
"Today, we mapped Git’s architecture to a marketing campaign workflow. Your homework:
1. Install Git and create a GitHub account.
2. Practice git add, commit, and push with a test project.
3. Explore GitHub’s interface—create a repo and clone it locally.
🚀
Any questions? Drop them in the chat! Tomorrow, we’ll tackle branches and pull requests. Keep
practicing—see you in the next session! "
Date - 06/03
Scenario: Removing an Accidentally Pushed File from GitHub
Problem:
Suppose you created files a.txt, b.txt, and c.txt in your project and pushed them to GitHub. Later, you realize
that a.txt was incomplete and should not have been pushed. Now, you need to remove it from the central
repository.
Practical: Removing a File
✅
This guide will cover:
✅
Creating files manually in G drive
✅
Initializing a Git repository
✅
Pushing files to GitHub
Removing an accidentally pushed file (a.txt)
Create a Repository on GitHub
1. Go to GitHub → Click on "+" → Select "New repository".
2. Enter a repository name: GitDemo.
3. Keep it Public.
4. Click "Create repository".
5. Copy the repository URL.
Step 1: Manually Create Files in G Drive
1. Open File Explorer and navigate to G:\ drive.
2. Create a new folder named GitDemo.
3. Inside GitDemo, create three text files:
○ a.txt → (Right-click → New → Text Document → Rename to a.txt)
○ b.txt → (Repeat the above steps)
○ c.txt → (Repeat the above steps)
4. Open a.txt and add some text (optional), e.g., "This is file A", and save it.
Step 2: Initialize Git in the Folder
1. Open Git Bash.
2. Navigate to the folder:
cd /g/GitDemo
3. Initialize Git:
git init
(This creates a hidden .git folder, making it a Git repository.)
Step 3: Add and Commit Files
1. Add all files to Git:
git add .
2. Commit the changes:
git commit -m "Initial commit - Added a.txt, b.txt, c.txt"
Step 4: Push Files to GitHub
1. Rename branch to main:
git branch -M main
Step 5: Link Local Repository to GitHub
1. Run the following command (replace with your actual GitHub repo URL):
git remote add origin https://github.com/your-username/GitDemo.git
2. Push files:
git push -u origin main
Now, a.txt, b.txt, and c.txt are on GitHub! ✅
Step 6: Realizing the Mistake
🚨 Oops! You accidentally pushed a.txt! You want to remove it from GitHub but keep working on it locally.
Step 7: Remove a.txt from GitHub but Keep Locally
1. Run:
git rm a.txt
(This removes the file from the working tree but it has not been deleted from the github.)
Step 8: Commit and Push the Changes
1. Commit:
git commit -m "Second commit"
2. Push the update to GitHub:
git push
✅ a.txt is now removed from GitHub
The explanation exactly how your instructor would in a live lecture. Picking up from where we left off, now we will:
✅ Edit b.txt directly on GitHub
✅ Understand why we use git pull instead of git clone
✅ Fetch the updated file using git pull
Step 9: Edit b.txt Directly on GitHub
1. Go to GitHub and open your repository GitDemo.
2. Click on the file b.txt.
3. Click the Edit (pencil) icon.
4. Commit message:
Updated b.txt with an extended description
5. Extended description:
updated the file
6. Click Commit changes.
✅ Now, b.txt is updated on GitHub, but our local repository still has the old version.
Step 10: Should We Use git clone Again?
🚨 No! Never use git clone again for an existing project!
● git clone is used only when you are downloading the project for the first time to your local computer.
● Since our local repository is already connected, we use git pull instead.
Step 11: Fetch the Update Using git pull
1. Open Git Bash.
2. Navigate to the project folder:
cd /g/GitDemo
3. Run:
git pull
What happens?
○ Git checks for updates on GitHub.
○ It finds that b.txt was modified.
○ It downloads only the changes and updates the local file.
Step 12: Verify the Update
1. Open b.txt in G:\GitDemo.
2. You will see the new line added:
Extended description: updated the file
✅ The local version of b.txt is now up to date with GitHub!
Step 13: Make Another Edit to b.txt on GitHub (Second Commit)
1. Go to GitHub and open your repository GitDemo.
2. Click on b.txt.
3. Click the Edit (pencil) icon.
4. Add two more lines at the end:
Added second line
Added third line
5. Scroll down, enter a commit message:
Added two more lines to b.txt
6. Click Commit changes.
✅ Now, b.txt has 3 new lines in total (first update + these two new lines).
Step 14: Run git pull Again
1. Open Git Bash.
Navigate to the project folder:
cd /g/GitDemo
2.
Run:
git pull
3.
What happens?
● Git downloads the changes.
Since we added two more lines, Git will show:
b.txt | 2++
●
○ 2++ means two lines were added to b.txt.
Step 15: Make a Third Edit (Removing One Line)
1. Go to GitHub and open b.txt.
2. Click the Edit (pencil) icon.
3. Remove one line (for example, delete Added third line).
Scroll down, enter a commit message:
Removed one line from b.txt
4.
5. Click Commit changes.
✅ Now, b.txt has one line removed.
Step 16: Run git pull Again
1. Go back to Git Bash.
Run:
git pull origin main
2.
What happens now?
● Git sees that one line was removed.
It updates b.txt and displays:
b.txt | 2+_
●
○ 2+_ means:
■ 2 lines were added previously (2+)
■ 1 line was removed (_)
Conclusion
● 📝 b.txt | 2++ means two lines were added.
● 📝 b.txt | 2+_ means two lines were added earlier, and one line was removed later.
● 🔄 git pull ensures that our local repository always matches the latest version on GitHub.
Step 17: Delete .git Folder and b.txt, c.txt from Local Repository
1. Open File Explorer and navigate to:
G:\GitDemo
2. Enable Hidden Items:
○ Click View (top menu).
○ Check Hidden items to see the .git folder.
○ Delete the .git folder.
3. Delete b.txt and c.txt.
4. Now, the local repository has no Git tracking and no files.
✅ The Git connection is removed from the local folder.
Step 18: Clone the Repository Again
1. Open Git Bash.
2. Move to the G: drive (if not already there):
cd /g
3. Run the clone command:
git clone <repository_url>
○ Replace <repository_url> with your actual GitHub repository URL.
Example:
git clone https://github.com/yourusername/GitDemo.git
○
What happens?
● This will download the repository into a new folder named GitDemo.
● The folder structure is restored with all files (b.txt, c.txt, etc.).
● Git automatically creates a new working tree inside GitDemo.
✅ Now, your local repository is freshly cloned and linked to GitHub.
Step 19: Change the Path to the New Working Tree in Git Bash for the
another pull
1. Navigate into the cloned repository:
cd GitDemo
2. Confirm that you are inside the working tree:
git status
If everything is correct, Git should show:
On branch main.
Your branch is up to date with 'origin/main'.
Run git pull to sync updates:
git pull origin main
○ If up to date, it shows: Already up to date.
✅ Your Git is now tracking the correct repository path.
Step 2: Creating a New Repository on GitHub
1. Click the "+" icon (top-right of GitHub) → Select "New repository".
2. Enter a repository name (e.g., spring-boot-git-demo).
3. Select "Public" (so anyone can see it).
4. Keep "Initialize this repository with a README" unchecked.
5. Click "Create repository".
Step 3: Creating a Spring Boot Project using Spring Initializr
1. Go to Spring Initializr (https://start.spring.io)
2. Select the following options:
○ Project: Maven
○ Language: Java
○ Spring Boot Version: Choose the latest stable version (e.g., 3.1.1)
○ Group: com.example
○ Artifact: spring-boot-git-demo
○ Name: spring-boot-git-demo
○ Description: "Spring Boot GitHub Integration"
○ Package Name: com.example.springbootgitdemo
○ Packaging: Jar
○ Java Version: 17 (or 11 if your system does not support 17)
3. Click "Add Dependencies" → Select:
○ Spring Web
4. Click "Generate" → Download the zip file.
5. Extract the downloaded zip file to a folder on your system.
Step 4: Open the Spring Boot Project in IntelliJ IDEA
1. Open IntelliJ IDEA.
2. Click "Open" → Navigate to the extracted folder → Select "pom.xml" → Click "Open as Project".
3. Wait for IntelliJ to index the project and download dependencies.
Step 5: Initialize Git in the Project
1. Open Terminal inside IntelliJ (or use Git Bash in the project directory).
Run:
git init
2.
○ This initializes an empty Git repository in your project folder.
Step 6: Add and Commit the Project Files
Run:
git add .
1.
○ This stages all files in the project.
Run:
git commit -m "Initial commit - Spring Boot project setup"
2.
○ This commits the files to the local repository.
Step 7: Connect the Local Repository to GitHub (From here not in lecture)
1. Copy the repository URL from GitHub. (Go to your newly created repo → Click the "Code" button → Copy
the HTTPS URL.)
In the terminal, run:
git remote add origin <repository_url>
Example:
git remote add origin https://github.com/your-username/spring-boot-git-demo.git
2.
○ This links your local Git repository to GitHub.
Step 8: Push the Project to GitHub
Run:
git branch -M main
1.
○ This renames the default branch to main.
Run:
git push -u origin main
2.
🎉 You should now see your project files there!
○ This pushes your local code to GitHub.
3. Go to your repository on GitHub and refresh the page.
Step 12: Removing Files from Git
A. Delete a file and commit the change
If you accidentally pushed a file and want to remove it from Git:
Delete the file manually in IntelliJ or using:
rm unwanted-file.txt
1.
Run:
git add .
git commit -m "Removed unwanted file"
git push origin main
2.
B. Remove a file from Git but keep it locally
If you want to stop tracking a file but keep it locally:
Run:
git rm --cached filename.txt
1.
Then commit the change:
git commit -m "Removed filename.txt from tracking"
git push origin main
Date - 07/03
Git Commands Inside IntelliJ IDEA – Step-by-Step Guide (Sir’s
Explanation with Examples)
Hello everyone, today we will learn how to use Git inside IntelliJ IDEA. Now, Git is a version control system that
helps us manage our code efficiently. We don’t want to lose our progress, right? So, let’s see step by step how we
can integrate Git with our Spring Boot project in IntelliJ.
1. Creating a Spring Boot Project
Sir’s Explanation
Before we work with Git, we need a project. We will create a simple Spring Boot project from Spring Initializr. You
must have seen how we create projects in Eclipse, but here we will use IntelliJ IDEA.
Example
Step 1: Open Spring Initializr
● Open Google Chrome (or any browser).
● Search for "Spring Initializr" and click the first link, or directly go to start.spring.io.
● Fill in the details:
○ Project Type: Maven
○ Language: Java
○ Spring Boot Version: Choose the latest stable version.
○ Group: com.example
○ Artifact: git_example_project
○ Dependencies: Add Spring Web
● Click Generate, and it will download a ZIP file.
Step 2: Open Project in IntelliJ
● Go to your Downloads folder.
● Extract the ZIP file.
● Open IntelliJ IDEA.
● Click Open and select the extracted folder.
● Open pom.xml and wait for IntelliJ to load dependencies.
2. Setting Up Git in IntelliJ IDEA
Sir’s Explanation
Now, we will set up Git inside IntelliJ. If you don’t configure Git, you won’t be able to track changes. Just like when
you save a file in MS Word, Git helps us track code changes.
Example
● Click Test to check if Git is installed.
○ If Git is not installed, download it from git-scm.com.
Login to GitHub from IntelliJ
● Go to File → Settings → Version Control → GitHub.
● Click Add Account → Log in via GitHub.
● Enter your GitHub username and password.
● Click Authorize IntelliJ IDEA.
3. Initializing a Git Repository
Sir’s Explanation
Now, let's initialize Git inside IntelliJ. This step is like opening a new diary to start writing our notes.
Example
Step 1: Create a Local Repository
● Go to Version Control → Create git repository (Enable Version Control Integration.)
Step 2: Add Files to Git
● Open Version Control at the bottom.
● You’ll see files in red (untracked state).
Run the command: git add . OR use GUI:
■ Right-click the project → Git → Add. (All the file becomes green)
4. Committing Changes
Sir’s Explanation
Commit means saving the changes in Git, just like when you press Ctrl + S in Notepad.
Example
1. Go to VCS → Commit.
2. Write a commit message:
First commit - Added project files
3. Click Commit.
5. Pushing Code to GitHub
Sir’s Explanation
Pushing means uploading your code to GitHub, just like when you upload a photo to Google Drive.
Example
Step 1: Create a GitHub Repository
● Go to GitHub and log in.
● Click New Repository.
● Name it git_example_project.
● Click Create Repository.
● Copy the repository URL.
Step 2: Connect Local to Remote
Go to the Project right click on it → Git → Push (Define the remote → paste the github URL there → Click on Ok →
Push Anyway) → Refresh the page
OR use Command:
1. Open IntelliJ Terminal and run:
git remote add origin <your-repo-url>
2. Verify:
git remote -v
Step 3: Push Code
Run:
git push -u origin main
● If prompted, enter your GitHub credentials.
6. Pulling Changes from GitHub
Sir’s Explanation
Pulling means fetching the latest code from GitHub after editing the code on github, just like when you refresh
a website. After commit the changes. →
Example
1. Go to VCS → Git → Pull.
2. Select origin/main and click Pull.(The latest code changes, i am able to see here.)
Date - 11/03/25
Git Branching and Workflow in a Project
Alright. So guys, last class, I covered the theory of branches. Fine? And today, we will quickly go through an
example of branches again.
Now, before we move ahead, let’s recall:
● Why do we create branches?
● What’s the purpose of a branch?
● Why should we create a branch?
This has already been covered in my previous lecture. Right?
In any project, for every dedicated task, a dedicated branch is created.
For example,
● If you want to fix a bug, you’ll create a bug fix branch.
● If you want to add a new feature, you’ll create a feature branch.
● If you’re working on research and development (R&D), you’ll create an R&D branch.
How Branching Works
Scenario: Bug Fixing
Let’s say Mike is working on a bug. The bug is tracked in JIRA with ID JIRA-3456 (Login Error).
Now, what will Mike do?
✅ Step 1: Mike will create another branch from the bug fix branch.
✅ Step 2: The new branch will be named something like:
📌 bugfix-JIRA-3456-login-error
✅ Step 3: Now, this new branch will contain a copy of the code from the bug fix branch.
📌 Note:
● Mike will clone the project from this branch.
● He will work on the bug and update the branch.
● Before leaving for the day, he must push the updated code.
● He will keep working on it until the bug is fixed.
After 3 days, Mike has fixed the bug. Now what happens?
✅ Step 4: He informs his team lead.
✅ Step 5: The team lead will review the code.
✅ Step 6: If everything is fine, the team lead will tell him to merge the branch.
Wait! Do we say "merge the branch" in companies? No!
● Instead, we use the term Pull Request (PR).
✅ Step 7: Mike will now create a PR (Pull Request).
✅ Step 8: The bug fix code is merged into the bug fix branch.
Now, the bug fix branch has the updated code, where the Login Error problem is resolved.
Similarly, if Stalin is working on a different bug, he will create his own branch.
If Adam is working on another bug, he will create his own branch.
👉 So, every developer will have their own personalized branch.
📌 Why do we create a separate branch for each developer?
● Because whatever code they are modifying, it should be isolated in their branch.
● Nobody else should directly touch that code.
Now, sometimes the team lead will create the branch.
Other times, the developer is asked to create their own branch from the bug fix branch.
📌 Important:
● If it's a new project, all these things happen in front of you.
● But if it's a maintenance project (project is already running for a long time), then you need to ask:
"Which branch should I clone?"
● If you’re asked to work on a bug fix, then clone the bug fix branch, create a new branch, work on it, and
merge it back.
Practical: Creating a GitHub Repository & Branches
✅ Step 1: Go to GitHub → Create a New Repository
✅ Step 2: Name it test3 → Click Create
✅ Step 3: Now, let’s push a project to GitHub.
Push Code to GitHub
1. Open Spring Initializr and create a project named test3.
2. Download the project and extract the files.
3. Move the project to a new folder in G Drive named test3.
4. Open Git Bash in the test3 folder to the working tree.
5. Run the following commands:
git init
git add .
git commit -m "First commit"
git remote add origin <GitHub Repository URL>
git push -u origin main
✅ Step 4: Go to GitHub and verify the project is pushed.
Creating Branches in GitHub
1. Go to the Branches tab.
2. Click on New Branch.
3. Name the branch bugfix and create it.
📌 What happens now?
● The bugfix branch gets created from main.
● It contains the same code as the main branch.
Similarly, create the following branches:
● features (for new features)
● hotfix (for urgent bug fixes in production)
● r&d (for research & development)
● release (for final project releases)
3. Bug Fixing Workflow Example
○ A defect (e.g., Jira-3456: Login Error) is assigned.
Create a branch from bug-fix:
git branch bugfix-Jira-3456-login-error bug-fix
○ To see how many branch is present - Run: git branch
○ To switch to - git switch bugfix-Jira-3456-login-error bug-fix
○
Work on the bug and push updates daily:
git add .
git commit -m "Fix login error bug"
git push (It will show to type the correct code as below )
git push –set-upstream origin bugfix-Jira-3456-login-error
○ Once done, raise a Pull Request (PR). → Compare and pull.
○ The team lead reviews, merges the branch, and updates bug-fix.(select the branch in which you
want to merge.) → click on “create a pull request.”
Interview Questions on Branching
❓ Q1: How many branches were there in your project?
✅
● It depends on the company, but generally, we have:
main
✅ bugfix
✅ features
✅ hotfix
✅ r&d
✅ release
❓ Q2: How many branches have you created at a given point of time?
● This depends on the tickets (tasks) assigned.
● If I was working on support, I might get 70 defects in a month.
● So, at any given time, I might have created one or two branches.
❓ Q3: What is a "ticket" in companies?
● In real-world projects, a bug or feature request is called a ticket.
● Example:
Bug ID: JIRA-3456, Login Error
This is called a ticket.
❓ Q4: How do you work on a bug fix?
1. Create a new branch from the bugfix branch.
2. Work on the bug in this branch.
3. Push the updated code every day before leaving.
4. Create a Pull Request (PR) once the bug is fixed.
5. Team Lead reviews the PR and merges it into the bugfix branch.
Difference Between Bugfix and Hotfix
📌 Bugfix Branch
● Used to fix defects found in development or testing.
● Customer is not affected yet.
📌 Hotfix Branch
● Used to fix critical defects in production.
● Customer is already using the application, and the bug is affecting business.
● Fixing hotfix bugs is a priority because the company is losing money.
Key Takeaways
1. Always work in your own branch.
2. Push code daily before leaving.
3. Create a PR before merging code.
4. Understand different branches and their purposes.
5. Be ready for interview questions on Git branching.
Date - 12/03
Git Conflict Explaination
What is a Git Conflict?
A Git conflict happens when two developers make changes to the same part of a file and try to push their changes
to Git. Since Git doesn't know which change to keep, it stops the process and asks the developers to manually
resolve the conflict.
How Does a Git Conflict Happen?
1. Developer 1 modifies a file and pushes it to Git.
2. Developer 2 also modifies the same file (same lines) and tries to push their changes.
3. Git detects that the same lines have been changed in both versions and blocks the push.
4. The developer must first pull the latest changes, resolve the conflict manually, and then push again.
Example of a Git Conflict
Step 1: Developer A edits file.txt and writes:
Name = "John"
●
○ Developer A pushes this change to Git.
Step 2: Developer B also edits file.txt at the same time and writes:
Name = "Mike"
●
○ Now, Developer B tries to push.
● Step 3: Git sees that the same line has been modified and throws a conflict error.
How to Resolve a Git Conflict?
1. Run git pull to get the latest changes.
2. Open the file that has a conflict. Git will mark the conflicting lines like this:
<<<<<<< HEAD
Name = "Mike"
=======
Name = "John"
>>>>>>> origin/main
3. Decide which version to keep (or merge both changes).
“git push” will not work , if you use “git pull” it will give conflict.
4. Save the file and run:
Git add . OR git add file.txt
git commit -m "Resolved conflict"
git pull OR git push
Types of Git Conflicts (and can be resolved by same above steps)
1. Merge Conflict: Happens when merging two branches with different changes in the same file.
2. Rebase Conflict: Happens when rebasing a branch that has changes conflicting with the main branch.
3. Pull Conflict: Happens when pulling changes that modify the same lines in your local files.
When files are different you can merge it without any conflict. Conflicts are when same file some lines are in
collision with other developer that you modified they modified conflict will occur. So standard rule is before
do a push , do a pull, after pull then push.
Date - 13/03
Git and GitHub - Deep Explanation with Examples
1. Understanding Git and GitHub
Git is a version control system (VCS) that helps developers track and manage changes in their source code.
GitHub, on the other hand, is a cloud-based hosting service for Git repositories, allowing collaboration and code
sharing among multiple developers.
Example:
Imagine you are developing a bus booking system. You need to keep track of changes, collaborate with a team,
and ensure that old versions of the project are not lost. Git helps you manage these changes, and GitHub allows
you to store and share them with others.
2. Important Git Commands and Concepts
a. Git Commit and Undoing Changes
When you make changes to your project, you commit them to Git. But what if you need to undo a commit?
Scenario:
You accidentally committed a file and now want to remove the last commit. There are different ways to do this:
When you push the code you will get the commit id, copy this ID. and run the command:
git revert ‘commit id’
One file will open up, just esc :wq then do ‘git push’.
After this the file get reverted. (git log - give you the status history of changes).
1. Soft Reset (git reset --soft HEAD~1)
This will undo the last commit but keep the changes in the staging area (index), green colour then that file is in
staging area.
git reset --soft HEAD~1 (1 for latest, 2 for second and so on…)
✔️ Changes are still present, ready to be committed again. (do the commit and proceed further command)
2. Mixed Reset (git reset --mixed HEAD~1)
This will undo the last commit and remove changes from the staging area but keep them in the working
directory.
git reset --mixed HEAD~1
✔️ Changes remain in your working directory but are not staged.
3. Hard Reset (git reset --hard HEAD~1)
This will completely remove the last commit, including the changes in the working directory.
git reset --hard HEAD~1
❌ Be careful! This will delete your changes permanently.
b. Git Forking
Forking is a GitHub-specific concept that allows you to copy someone else’s repository into your own account.
You can then make changes without affecting the original repository.
Example:
● Suppose you find an open-source payment gateway project on GitHub.
● You want to modify it for your own application.
● Instead of modifying the original code (which you may not have permission to do), you fork it and make
changes in your repository.
🔹 Steps to Fork a Repository:
1. Go to the GitHub repository you want to fork.
2. Click on the Fork button (top-right corner).
3. This creates a copy of the repository in your GitHub account.
4. Now you can modify the code without affecting the original repository.
c. Collaborators and Permissions on GitHub
In a professional setting, you may need to grant others permission to modify your repository.
🔹 How to Add a Collaborator:
1. Go to your GitHub repository.
2. Navigate to Settings → Manage Access.
3. Click Invite a Collaborator and enter their GitHub username.
4. They will receive an email invitation. Once accepted, they can push changes.
d. Git Pull vs Git Fetch
Both git pull and git fetch bring changes from the remote repository, but there is a key difference:
Command Action
git Downloads the latest changes from the remote repository without applying
fetch them.
git pull Downloads and applies the latest changes.
🔹 Example:
1. Your team pushes new code to GitHub.
2. You use git fetch to see what has changed but don’t modify your local files yet.
3. Once you review the changes, you apply them with git merge.
4. If you directly use git pull, Git will fetch and merge the changes automatically.
Date - 17 / 03
Git Pull vs Git Fetch – Understanding the Difference
So guys, some more small concepts in GitHub that are pending will be covered today because we should not leave
any gaps, both from a practical and interview point of view.
A very popular interview question that you will come across is:
👉 What is the difference between git pull and git fetch?
Interviewers love asking this question because it checks your understanding of Git architecture and how Git
retrieves code from a remote repository.
Before we begin, let's take a quick look at the Git architecture:
1️⃣ Working Directory (Working Tree) – This is where you edit files.
2️⃣ Staging Area – This is where changes are added before committing.
3️⃣ Local Repository – This is where committed changes are stored.
4️⃣ Remote Repository – This is the repository hosted on GitHub or another Git server.
1. What is git pull?
👉 git pull is used to fetch changes from the remote repository and automatically merge them into your
working directory.
How does it work?
1️⃣ If someone makes changes to the remote repository (e.g., adds a new file), you can use git pull to bring
those changes into your local repository.
2️⃣ The fetched changes will automatically merge with your local working directory.
Example of git pull in action
Step 1: Current local file state
Let’s say you have a file called test.txt in your local system, and it contains:
Hello, this is my local file.
Step 2: Changes made in remote repository
Now, another developer adds a new line in the GitHub repository:
Hello, this is my local file.
New update added by another developer.
Step 3: Running git pull
When you run:
git add .
git commit -m “1”
git pull origin main
✔ It fetches the changes from the remote repository
✔ It merges those changes automatically into your working directory
Final state of test.txt in your local system after git pull
Hello, this is my local file.
New update added by another developer.
🔴 Problem with git pull
When you do git pull, automatic merging happens, which may cause conflicts if multiple developers have
modified the same file.
👉 Example of a conflict:
● If you changed line 2 in your local file and
● Another developer changed line 2 in the remote repository
Then when you run git pull, a merge conflict will occur, and Git will ask you to resolve it manually.
2. What is git fetch?
👉 git fetch is used to download changes from the remote repository to the local repository, but it does not
merge them automatically.
How does it work?
1️⃣ git fetch only updates your local repository with the latest changes from the remote repository.
2️⃣ It does not update your working directory automatically.
3️⃣ You have to manually merge the changes by running git merge.
Example of git fetch in action
Step 1: Remote repository update
Another developer adds a new line to the remote file:
Hello, this is my local file.
New update added by another developer.
Another line added remotely.
Step 2: Running git fetch
Now, you run:
git fetch
✔ It downloads the latest changes from the remote repository but does not apply them to your working directory.
Step 3: Checking the status
You can check what new changes have been fetched using:
git log origin/main --oneline
This will show you the new commits that have been fetched.
Step 4: Manually merging the changes
If you are happy with the changes, you can merge them manually using:
git merge
This ensures that you can review the changes before merging into your working directory, which helps avoid
conflicts.
Summary: Key Differences Between git pull and git fetch
Feature git pull git fetch
Function Fetches and automatically merges Fetches changes but does not
merge automatically
Working Changes are applied immediately Changes are not applied
Directory immediately
Merge High chance of conflicts if changes No immediate conflicts since
Conflicts overlap merging is manual
Safety Risky, as it merges automatically Safer, as you review changes first
Use Case When you trust the changes and want When you want to review changes
them immediately before merging
When to Use git pull vs git fetch?
✔ Use git pull when you are working alone and just want to update your code quickly.
✔ Use git fetch when working in a team, to review changes before merging.
Real-World Scenario
Imagine you are working on a project, and a teammate pushes new changes to the GitHub repository.
● If you run git pull, the changes will be immediately merged into your local working directory.
● If you run git fetch, the changes will be downloaded, but you get a chance to review them first before
merging.
So, in a team-based project, git fetch is preferred as it prevents accidental overwrites and conflicts.
Example Code Execution: git pull vs git fetch
Step 1: Check the current status
git status
Step 2: Fetch remote changes (safe operation)
git fetch origin main
Step 3: Review fetched changes
git log origin/main --oneline
Step 4: Merge the changes manually (only if needed)
git merge origin/main
Step 5: Directly pull remote changes (risky operation)
git pull origin main
Git Stash (Detailed Explanation)
1. What is git stash?
Imagine you're working on a feature, modifying multiple files, but suddenly, you need to switch branches to fix a bug.
However, you don’t want to commit your half-finished changes yet. That’s where git stash helps.
git stash temporarily saves your uncommitted changes, allowing you to switch branches without losing progress.
Later, you can restore the stashed changes and continue working.
2. How git stash Works Internally
When you run git stash, Git does the following:
● Saves modified tracked files and staged files into a stash
● Creates a hidden commit that stores these changes
● Resets your working directory to match the last committed state
Note:
● Untracked (new) files are not stashed unless you use git stash -u.
● Ignored files are never stashed.
3. Common git stash Commands
Command Description
git stash Stashes modified and staged files (excluding untracked
files)
git stash -u Also stashes untracked files
git stash Shows the list of stashed changes
list
git stash Applies the latest stash and removes it from the stash list
pop
git stash Applies the latest stash but keeps it in the stash list
apply
git stash Deletes the latest stash
drop
git stash Removes all stashed changes
clear
4. Example Use Case
Let's say you are working on a new feature but need to switch branches for an urgent bug fix.
Step 1: Check the status
git status
It shows that file1.txt and file2.txt are modified but not committed.
Step 2: Stash the changes
git stash
Your working directory is now clean, and you can switch branches.
Step 3: Switch branches and fix the bug
git checkout bugfix-branch
# Fix the bug and commit it
git add .
git commit -m "Fixed a critical bug"
Step 4: Return and reapply the stash
1️⃣Using git stash apply (Keeps stash for future use)
git stash apply # Applies the stashed changes but keeps them in stash list
2️⃣ Using git stash pop (Removes stash after applying)1️
git checkout feature-branch
git stash pop # Applies the stashed changes and removes them from stash list
After git stash apply, the stash is still available in git stash list. If you're unsure whether you'll need the
changes again, apply is safer than pop.
5. When to Use git stash?
✅ When switching branches but wanting to save current progress
✅ Before pulling latest changes from the remote repo
✅ When needing a clean working directory for another task
Git Cherry-Pick
Git cherry-pick is used to apply a specific commit from one branch to another without merging the entire branch.
This is useful when you need only a particular change but don’t want other changes from a branch.
Scenario: Why Use Git Cherry-Pick?
Suppose you made 5 commits today in a feature branch, but you want to apply only the 3rd commit to another
branch without merging everything.
How Git Cherry-Pick Works
Find the commit hash of the commit you want to pick:
git log --oneline
Example output:
a1b2c3d Commit 5
e4f5g6h Commit 4
i7j8k9l Commit 3 ← (We need this)
m1n2o3p Commit 2
q4r5s6t Commit 1
1.
Switch to the branch where you want to apply the commit:
git checkout target-branch
2.
Apply the specific commit:
git cherry-pick i7j8k9l
3.
Now, commit i7j8k9l is applied to the target-branch without merging the whole branch.
Handling Merge Conflicts in Cherry-Pick
If the cherry-picked commit has conflicts, Git will show a conflict message.
● Resolve the conflicts manually in the affected files.
Once resolved, run:
git cherry-pick --continue
●
If you want to abort the cherry-pick:
git cherry-pick --abort
●
Interview Question Example
💡 Q: You made 5 commits today but need to merge only the 3rd commit into another branch. What will you
✅ A: Use git cherry-pick <commit-hash> to apply only the required commit.
do?
🛑 Note: If you use git merge, it will merge all commits, not just one.
Key Differences: Git Merge vs Git Cherry-Pick
Feature Git Merge Git Cherry-Pick
Purpose Combines all changes from one branch Picks only specific commits
into another
Applies All Yes No (only selected commits)
Commits?
Use Case When merging an entire feature or When applying specific
bugfix branch changes only
Risk May bring unwanted commits Only applies what you need
Date -18/03
This lecture gives an introduction to Software Development Life Cycle (SDLC) using a construction analogy and
highlights the importance of understanding SDLC for working in IT. Below is a structured version of your lecture
notes with proper flow and readability.
Introduction to SDLC & Bug Tracking Tools
Popular Defect Tracking Tools
● Bugzilla – A widely used tool for defect reporting.
● IBM ClearQuest & ClearCase – Captured the market for some time.
● HP QC (Quality Center) – Another famous bug-reporting tool.
● Jira – Currently one of the most popular tools used in companies.
Understanding Software Development Life Cycle
(SDLC)
What is SDLC?
SDLC refers to the phases involved in software development, defining what activities happen at each stage of
a project. It ensures that software is developed systematically and efficiently.
Analogy: Constructing a House
1. Requirement Gathering – The customer provides specifications to the contractor.
2. Requirement Analysis – The contractor evaluates feasibility.
3. Design – Structural designs are created.
4. Development – Site engineers construct the house.
5. Testing & Inspection – The house is inspected for issues.
6. Deployment & Maintenance – The house is handed over; future modifications happen.
Similarly, in software development, SDLC includes structured phases:
Phase Description
1. Requirement Business Analysts (BA) gather and analyze requirements.
Analysis
2. Design High-Level Design (HLD) & Low-Level Design (LLD) are created.
3. Development Developers write and implement the code.
4. Testing Test engineers find and report bugs.
5. Deployment The application is released to production.
6. Maintenance Bug fixes, enhancements, and feature additions occur.
Role of a Business Analyst (BA)
● Domain Experts: BAs must have extensive knowledge of the domain they work in (e.g., Banking, CRM,
Travel).
● Requirement Gathering: BAs meet customers and document business needs.
● Bridging Communication Gaps: They ensure accurate communication between customers and
developers.
Challenges in Requirement Gathering
● Miscommunication: Customers might express one requirement, BAs might document another, and
developers may interpret it differently.
● Solution: Use Prototypes to create a basic version of the application to validate requirements.
Types of Software Development Projects
1. New Development Projects – Built from scratch.
2. Maintenance Projects – Modify and enhance an existing system.
○ Challenges: Understanding old code, debugging, and adapting to the business flow.
○ Hotfixes: Fixing urgent production bugs.
3. Migration Projects – Converting old technologies (e.g., JSP/Servlets) into modern frameworks.
1. Understanding Prototypes in Software Development
Prototype Development in Software Engineering
Before starting actual software development, a prototype is often created to visualize the user flow and gather
client feedback. This helps to avoid miscommunication and reduces rework.
Why do we create a prototype?
Imagine a scenario where we start directly developing the software based on initial requirements. Later, when we
show the final product to the customer, they say:
● "No, no! This is not what I wanted!"
● "I asked for something else, and you developed something different!"
This is a huge waste of time and effort.
To avoid such situations, we create a dummy application (prototype) before developing the actual software.
How is a prototype developed?
Example given by Sir:
A developer starts by creating a simple dummy flow of the application:
1. First, we design the HTML pages with basic front-end structure.
2. Then, we gather the UI/UX team to build a login page and show the flow:
○ The customer enters their mobile number.
○ An OTP is generated and sent.
○ The customer enters the OTP, and then a home page is displayed.
3. The prototype is then shown to the customer for feedback.
At this stage, if the customer wants changes, they can tell us:
● "No, I want the OTP to be sent via WhatsApp, email, and SMS, not just email."
● "The home page should contain additional sections."
By doing this, we clarify requirements before actual development.
Two ways to create a prototype:
1. Mock-up using images: A simple static design showing different screens without functionality.
2. Static application: A basic front-end with no back-end code, just to show the business flow.
Why is prototyping important?
● Saves time: Prevents unnecessary development and changes later.
● Reduces confusion: Ensures the customer and developers are on the same page.
● Improves communication: Bridges the gap between technical and non-technical stakeholders.
Now, after finalizing the prototype, we move on to the software development models.
2. Waterfall Model – The Father of All Models
The Waterfall Model is a sequential development process where each phase must be completed before moving
to the next phase.
Why is it called the "Waterfall Model"?
Water flows downwards and never moves backward. Similarly, in the Waterfall Model, once a phase is
completed, we do not go back unless a major issue is found.
Steps in the Waterfall Model:
1. Requirement Gathering
○ The complete project requirement is collected before development begins.
○ The customer must be very clear about what they need.
○ Example: If you are constructing a building, you need the entire blueprint first before construction
starts.
2. Analysis
○ The collected requirements are analyzed to ensure feasibility.
○ Example: You can't build a skyscraper on weak soil without analyzing ground conditions.
3. Design
○ Architects (developers) create the software blueprint based on the requirements.
○ Example: Just like a construction blueprint is needed before building a house, a software design is
needed before coding.
4. Coding
○ Developers start writing the actual code.
○ Coding follows the complete design—no changes allowed mid-way.
5. Testing
○ The software is tested for bugs, security flaws, and performance issues.
○ If bugs are found, developers go back to coding, fix them, and retest.
6. Deployment
○ After successful testing, the software is delivered to the customer.
Where is the Waterfall Model used?
● Defense projects (missile software, security systems)
● Construction projects (building, bridges)
● Banking software
Drawbacks of the Waterfall Model
1. Customer involvement is minimal after the requirement phase.
2. Not flexible—if a major change is needed, we must restart.
3. Not suitable for evolving requirements—best for fixed requirements only.
Because of these drawbacks, companies moved towards iterative models like Agile.
3. Agile Process – The Modern Approach
Agile was introduced to fix the problems of the Waterfall Model. It follows an iterative and incremental
approach, allowing continuous feedback and flexibility.
How Agile works?
● The project is divided into small parts (iterations called sprints).
● Each sprint lasts 2-4 weeks, and a working feature is delivered at the end.
● Customer feedback is taken regularly to ensure the product meets expectations.
● Development is done in multiple cycles, improving the product gradually.
Agile Team Roles:
1. Product Owner – Represents the customer’s requirements.
2. Scrum Master – Facilitates Agile meetings.
3. Development Team – Developers, testers, and designers.
Agile Practices and Terminologies:
1. Daily Stand-up Meetings – Short meetings where team members discuss progress.
2. Sprint Planning – Planning tasks for the next sprint.
3. User Stories – Small features described in simple terms.
4. Kanban Board – A visual board to track progress.
5. JIRA – A tool used for managing Agile projects.
Example of Agile Implementation (as per Sir’s Explanation):
● Sir worked in a company where they transitioned from Waterfall to Agile.
● Initially, they faced challenges in implementing Agile.
● Scrum calls were strictly monitored—if team members discussed irrelevant topics, the trainer would
disconnect the call!
● Agile was borrowed from Spiral Model but improved with better structure and flexibility.
● Agile follows Planning Poker Activity, Fibonacci Sizing, and T-shirt Sizing to estimate tasks.
Why Agile is Better than Waterfall?
1. Continuous Customer Involvement – Reduces misunderstandings.
2. Flexibility – Allows changes during development.
3. Faster Delivery – Features are released in small chunks instead of waiting for full project completion.
4. Better Bug Fixing – Bugs are identified early and fixed immediately.
Final Thoughts:
● Waterfall Model is best for fixed requirements (defense, construction).
● Agile is best for dynamic projects (web applications, mobile apps, software products).
● Bug tracking tools like JIRA are used to manage Agile processes efficiently.
Date - 19/03
Understanding Agile in SDLC
In the last class, we discussed SDLC (Software Development Life Cycle) and explored the Waterfall Model.
Today, we are moving towards Agile methodology because without understanding Agile, working with JIRA would
be difficult. JIRA has specific functionalities designed for Agile project management.
Now, let’s break it down:
What is Agile?
Before diving into Agile, let's first examine the drawbacks of the earlier models like Waterfall.
Problems with Waterfall Model:
● In Waterfall, complete requirements are gathered at the beginning.
● All developers work on the same set of requirements.
● Tracking which developer is working on which task is difficult, especially in large teams.
Example:
Imagine a team of 100 developers working on a single project. As a project manager, keeping track of who is
working on what is challenging.
Let’s take a real-world example:
● Suppose one manager has to manage 200 employees.
● Is it easy or difficult? Difficult.
● Why? Because the manager cannot allocate tasks effectively, track progress, or identify who is working
efficiently.
Analogy:
Think of it like ordering a North Indian meal in a hotel. If the entire meal (15 items) is served at once, you consume
everything together but might not remember the taste of each individual dish.
But if the items are served one by one:
1. First, you get the soup → You enjoy it and rate its taste.
2. Then, you get the salad → You analyze whether it’s good or bad.
This systematic serving allows better appreciation of each item.
Similarly, in Agile:
● Big requirements are broken down into smaller parts.
● Work happens in stages, improving clarity and tracking.
How Agile is Different?
Key Difference:
Waterfall Model Agile Model
Entire project requirements are gathered at Requirements are broken into smaller
once. tasks.
All developers work on the entire requirement Developers work on small parts (user
together. stories).
Difficult to track who is doing what. Tasks are allocated systematically.
Testing happens after development is Testing happens parallelly with
completed. development.
Breaking Down Requirements: User Stories
In Agile, the big requirement is divided into smaller requirements called User Stories.
What is a User Story?
A User Story is a small independent requirement that defines a feature from the end-user’s perspective.
Example of Breaking Down a Requirement
Let’s say we are developing an E-commerce Website. Instead of giving one huge requirement, we break it down
like this:
1. Login Page → One developer handles only login.
2. Registration Page → Another developer handles only registration.
3. Email/SMS Notifications → A third developer works on notification integration.
4. Reports Dashboard → A fourth developer handles analytics and reports.
By breaking it down, each developer has clear responsibility, and tracking progress becomes easier.
Where are User Stories Stored? (Product Backlog)
● All User Stories are stored in a Product Backlog.
● Product Backlog is a collection of user stories that need to be developed.
● Example of a Product Backlog:
○ User Story 1: Login feature
○ User Story 2: Registration feature
○ User Story 3: Password reset functionality
○ User Story 4: Email & SMS notifications
By organizing User Stories like this, Agile ensures structured development.
User Story Format (Template)
👉
Each User Story follows a specific template:
"As a [user], I want [feature] so that [benefit]."
Example:
💡 As a registered user, I want to log in using my email and password so that I can access my account and
personalized features.
✅
This format ensures:
✅
User perspective is considered.
✅
Clear understanding of the feature.
Structured tracking of requirements.
Who Writes User Stories? (Role of Product Owner)
● User Stories are not written by developers.
● They are created by Business Analysts (in Agile, called Product Owners).
Who is a Product Owner?
● A domain expert who understands the business requirements.
● Talks to customers and gathers requirements.
● Stores them in Product Backlog as User Stories.
Example:
✅
Imagine IBM hires you as a Product Owner. Your job:
✅
Talk to customers.
✅
Gather requirements.
✅
Convert them into User Stories.
Store them in Product Backlog for developers.
Acceptance Criteria in Agile
Each User Story has Acceptance Criteria that define when a feature is complete.
Example: Login Feature Acceptance Criteria
● The login page should have fields for email and password.
● Users should be able to enter credentials and click Login.
● The system should validate credentials with the database.
● If credentials are correct → Redirect user to Dashboard.
● If credentials are incorrect → Show error message.
● Allow users to reset password.
● The feature should work on both Desktop & Mobile.
This ensures clarity for the developer and avoids confusion.
Technical Details in User Stories
Sometimes, technical specifications are included:
● Use JWT Token for security.
● API Endpoint: POST /api/login
● Enable Google Login Integration
● Log failed login attempts for security tracking.
By providing technical details, developers understand exactly what needs to be built.
Why Agile is Faster?
The word "Agile" means quick, flexible, and efficient.
How Agile Speeds Up Development?
1. Parallel Development:
○ Different developers work on different User Stories simultaneously.
2. Continuous Testing:
○ As each small feature is developed, it is tested immediately.
3. Quick Feedback Loops:
○ Customers review features frequently, ensuring alignment with expectations.
Mockups in Agile
● Mockups (wireframes/prototypes) help developers visualize features.
● Example: A UI/UX designer creates a mockup of a login page.
● Developers use the mockup as a reference while coding.
User Story Description
A user story defines how a user interacts with the application, which is why it’s called a user story. The format for a
user story is:
"As a [user], I want [goal] so that [reason]."
Example:
● As a guest user, when I log in, I should be able to perform only a flight search.
User stories are stored in the product backlog, along with defects.
Defects and Bugs
In a project, development and defect management happen simultaneously. Testers report defects.
● What is a defect?
If the actual value does not match the expected value, it is a defect (or bug).
Example:
● I enter ₹100, expecting a 10% discount, so the final value should be ₹90.
● However, due to a developer’s mistake (adding instead of subtracting), the output is ₹110 instead of ₹90.
● Since expected ≠ actual, this is a bug.
Bug Reporting Template
Just like user stories, bugs follow a reporting template:
1. Summary: Login button not working on mobile.
2. Priority: High (determines how soon the defect should be fixed).
3. Severity: Defines the impact of the bug on the application.
○ Critical: Major impact on business (e.g., incorrect premium calculation in insurance).
○ Major: Affects functionality but not critical.
○ Minor: Small issues like spelling mistakes.
4. Assignee: The person responsible for fixing the bug.
5. Steps to Reproduce:
○ Open the app on a mobile device.
○ Navigate to the login screen.
○ Enter credentials and tap login.
○ Expected: User logs in successfully.
○ Actual: Login button is unresponsive.
6. Attachments: Screenshots or video recordings (Jira allows screen recording).
Product Backlog
The product backlog stores pending work items, including:
● User Stories (added by the Product Owner or Business Analyst).
● Bugs (reported by Testers).
Example:
● 500 user stories → Features that need development.
● 20 defects → Bugs that need fixing.
Iterative Development in Agile
● Agile follows an iterative approach, meaning development happens part by part.
● This differs from the Waterfall Model, where the entire project is completed in sequential phases. Unlike the
waterfall model, which completes the entire project at once, Agile develops software piece by piece
● Agile is inspired by the Spiral Model, which also focuses on iterations.
User Story Template & Examples
A user story follows this structure:
As a [role], I want [feature] so that [benefit].
Examples:
● As an admin, I should be able to log in with my username and password so that I can create sub-user
accounts.
● As an accountant, I should be able to generate a bill so that I can email it to my customer.
Jira and Bug Tracking
● Jira provides tools like Kanban boards, backlog management, and planning poker for Agile teams.
● All pending work (user stories + defects) is managed in Jira’s product backlog.
Date - 20/03
Introduction to Agile Process and Product Backlog
Alright, so guys, let's begin. I was talking about Agile, and we started understanding the Agile process a bit.
Yesterday, we saw something called a Product Backlog, correct? The Product Backlog stores user stories and is
also used in companies to store bugs.
● User stories and bugs are managed in the Product Backlog.
● Who adds user stories? → The Product Owner, not developers or testers.
● The Product Owner is responsible for adding user stories and managing backlog items.
Let’s note down the roles involved:
1. Product Owner – Adds user stories to the backlog.
2. Business Analysts and Testers – Work alongside the Product Owner.
Now, what happens after adding user stories? Backlog Grooming!
Backlog Grooming and Story Points Estimation
1. Backlog Grooming is the process where the team refines user stories.
2. Defining Story Points → A measure of complexity, time, and effort required to complete a user story.
3. To assign story points, companies use the Planning Poker Activity.
Planning Poker Activity: Estimating Complexity
● A meeting is held via Microsoft Teams or other platforms.
● The Product Owner explains a user story (e.g., "Develop a login feature").
● Developers, testers, project managers, and team leads listen and estimate complexity.
● Planning Poker Cards are used to assign story points.
● The team discusses and agrees on the complexity using a Fibonacci series (1, 2, 3, 5, 8, 13, etc.).
● More complex tasks get higher numbers (e.g., 8 or 13), simpler tasks get lower numbers (e.g., 1 or 3).
Example Scenario:
● Developer 1 and 2 say complexity is 8.
● Developer 4 (more experienced) says complexity is 5.
● Discussion happens → Developer 4 justifies that Spring Security can simplify the login feature.
● The team agrees, and the final story point is set to 5.
If there's disagreement, a coffee break card can be used to take a break before continuing discussions.
Product Backlog Finalization and Estimation
Once all user stories are assigned points, companies estimate time required:
● 3 points → 0.5 days
● 5 points → 2 days
● 8 points → 4 days
The backlog remains dynamic, meaning new stories can be added as per changing requirements.
Some companies use T-Shirt Sizing (XS, S, M, L, XL) instead of Story Points, but Planning Poker is the standard
practice.
Agile Team Structure & Team Splitting
● Agile works with smaller teams (6-9 people per team).
● Teams consist of developers, testers, and a Scrum Master.
● Scrum Master ensures smooth execution and resolves blockers.
Agile teams work in iterations (Sprints), ensuring faster, more efficient development and adaptability.
Date - 22/03