Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
2 views

Spring Boot - Notes

Maven is a build automation and dependency management tool used in Java projects, including Spring Boot applications, simplifying project setup and management. The pom.xml file is crucial for defining project details, dependencies, and build instructions. Spring Boot leverages Maven to streamline dependency management and project lifecycle through various commands and configurations.

Uploaded by

Jha Avinash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Spring Boot - Notes

Maven is a build automation and dependency management tool used in Java projects, including Spring Boot applications, simplifying project setup and management. The pom.xml file is crucial for defining project details, dependencies, and build instructions. Spring Boot leverages Maven to streamline dependency management and project lifecycle through various commands and configurations.

Uploaded by

Jha Avinash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 153

‭Spring Boot‬

‭Maven in Spring Boot‬

‭ aven is a build automation and dependency management tool used in Java projects,‬
M
‭including Spring Boot applications. It simplifies project setup, builds, and dependency‬
‭management.‬

‭1. What is Maven?‬

‭Maven is a tool that:‬

‭‬
● ‭ anages dependencies (e.g., Spring Boot libraries)‬
M
‭●‬ ‭Automates the build process‬
‭●‬ ‭Provides a standard project structure‬
‭●‬ ‭Handles plugins for testing, packaging, and deployment‬

‭2. Installing Maven‬


‭ heck if Maven is installed:‬
C
‭sh:‬
mvn -version‬

‭‬

‭●‬ ‭If not installed, download and install:‬
‭○‬ ‭Download from‬‭Apache Maven‬
‭○‬ ‭Set‬‭
MAVEN_HOME‬‭and‬‭
PATH‬‭environment variables.‬

‭3. Maven Project Structure‬

‭A typical Maven project follows:‬

‭bash:‬
‭y-springboot-app/‬
m
‭ -- src/main/java
│ # Application source code‬
‭ -- src/main/resources #
│ Configuration files‬
(application.properties)‬

‭ -- src/test/java
│ # Unit tests‬
‭ -- pom.xml
│ # Maven configuration file‬
‭4. Understanding‬‭
pom.xml‬
‭The‬‭
pom.xml‬‭(Project Object Model) is the core file‬‭in Maven projects.‬
‭A basic Spring Boot‬‭
pom.xml‬‭:‬

‭xml:‬
<project xmlns="http://maven.apache.org/POM/4.0.0"‬

‭xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"‬
‭xsi:schemaLocation="http://maven.apache.org/POM/4.0.0‬
http://maven.apache.org/xsd/maven-4.0.0.xsd">‬

<modelVersion>4.0.0</modelVersion>‬

‭groupId>com.example</groupId>‬
<
<artifactId>my-springboot-app</artifactId>‬

<version>1.0.0</version>‬

<packaging>jar</packaging>‬

<dependencies>‬

‭<!-- Spring Boot Starter -->‬
‭<dependency>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter</artifactId>‬
‭<version>3.2.0</version>‬
‭</dependency>‬

<‭!-- Spring Boot Starter for Web Applications -->‬


‭<dependency>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter-web</artifactId>‬
‭</dependency>‬
</dependencies>‬

<build>‬

‭<plugins>‬
‭<plugin>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-maven-plugin</artifactId>‬
‭</plugin>‬
‭</plugins>‬
</build>‬

</project>‬

‭‬
● ‭ roupId‬‭– Unique identifier (like a package name)‬
g
‭●‬ ‭artifactId‬‭– Project name‬
‭●‬ ‭version‬‭– Project version‬
‭●‬ ‭dependencies‬‭– Required libraries‬
‭●‬ ‭build/plugins‬‭– Used for packaging and execution‬

‭5. Useful Maven Commands‬


‭ reate a new project:‬
C
‭sh:‬
‭vn archetype:generate -DgroupId=com.example -DartifactId=myapp‬
m
-DarchetypeArtifactId=maven-archetype-quickstart‬

-DinteractiveMode=false‬

‭ uild the project:‬


B
‭sh:‬
mvn clean package‬

‭ un the application:‬
R
‭sh:‬
mvn spring-boot:run‬

‭ dd a dependency:‬
A
‭Add in‬‭
<dependencies>‬‭section of‬‭
pom.xml‬
‭, then run:‬
‭sh:‬
mvn clean install‬

‭ pdate dependencies:‬
U
‭sh:‬
mvn dependency:resolve‬

‭6. Maven vs. Gradle‬


‭Feature‬ ‭Maven‬ ‭Gradle‬

‭Build Script‬ ‭ ML‬


X ‭ roovy/Kotlin‬
G
‭(‬‭
pom.xml‬
‭)‬ ‭(‬‭
build.gradle‬‭)‬

‭Performance‬ ‭Slower‬ ‭Faster (incremental builds)‬

‭Learning Curve‬ ‭Easier‬ ‭More complex but powerful‬

‭Flexibility‬ ‭Less flexible‬ ‭More flexible‬


‭Conclusion‬

‭ aven simplifies dependency management and project builds in Spring Boot. The‬‭
M pom.xml‬
‭file is crucial for managing dependencies, plugins, and configurations. Running Maven‬
‭commands helps manage project lifecycle efficiently.‬
‭Understanding‬‭
pom.xml‬‭in Maven‬
‭ he‬‭
T pom.xml‬‭(Project Object Model) is the configuration‬‭file in a Maven project. It defines‬
‭project details, dependencies, plugins, and build instructions.‬

‭1. Basic Structure of‬‭


pom.xml‬
‭A minimal‬‭
pom.xml‬‭looks like this:‬

‭xml:‬
<project xmlns="http://maven.apache.org/POM/4.0.0"‬

‭xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"‬
‭xsi:schemaLocation="http://maven.apache.org/POM/4.0.0‬
http://maven.apache.org/xsd/maven-4.0.0.xsd">‬

<modelVersion>4.0.0</modelVersion>‬

‭groupId>com.example</groupId>‬
<
<artifactId>my-springboot-app</artifactId>‬

<version>1.0.0</version>‬

<packaging>jar</packaging>‬

</project>‬

‭2. Explanation of Key Elements‬


‭Tag‬ ‭Description‬

‭modelVersio‬ ‭Defines the POM model version (always‬‭


< 4.0.0‬
‭).‬
n>‬

<groupId>‬
‭ ‭Unique identifier for the project (e.g.,‬
‭com.example‬‭).‬

<artifactId>‬ ‭The project name (e.g.,‬‭


‭ my-springboot-app‬‭).‬

<version>‬
‭ ‭Project version (e.g.,‬‭
1.0.0‬‭).‬

<packaging>‬
‭ ‭Defines the output type (‬‭
jar‬‭or‬‭
war‬‭).‬
‭3. Adding Dependencies‬

‭Dependencies are external libraries required for the project. They are added inside‬
<dependencies>‬‭.‬

‭Example: Adding Spring Boot Starter dependencies‬

‭xml:‬
<dependencies>‬

<dependency>‬

‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter-web</artifactId>‬
</dependency>‬

<dependency>‬

‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter-data-jpa</artifactId>‬
</dependency>‬

</dependencies>‬

‭‬ T
● ‭ he‬‭
<groupId>‬‭and‬‭<artifactId>‬‭specify the dependency.‬
‭●‬ ‭The version is automatically resolved from Spring Boot’s parent.‬

‭4. Maven Plugins‬

‭Plugins extend Maven’s functionality. The most common plugin in Spring Boot is:‬

‭xml:‬
<build>‬

<plugins>‬

‭<plugin>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-maven-plugin</artifactId>‬
‭</plugin>‬
</plugins>‬

</build>‬

‭This allows us to run:‬

‭sh:‬
mvn spring-boot:run‬

‭5. Parent POM (Spring Boot Parent)‬

‭Instead of manually managing dependency versions, we use Spring Boot’s parent POM:‬

‭xml:‬
<parent>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-parent</artifactId>‬

<version>3.2.0</version>‬

<relativePath/> <!-- lookup from repository -->‬

</parent>‬

‭ ‬ I‭t simplifies dependency management.‬



‭●‬ ‭It provides default versions for many Spring dependencies.‬

‭6. Properties Section‬

‭We can define variables inside‬‭


<properties>‬‭to manage versions easily:‬

‭xml:‬
<properties>‬

<java.version>17</java.version>‬

</properties>‬

‭Usage:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter</artifactId>‬

<version>${spring.boot.version}</version>‬

</dependency>‬

‭7. Build Profiles‬

‭Maven allows different configurations for environments (dev, prod, test):‬

‭xml:‬
<profiles>‬

<profile>‬

‭<id>dev</id>‬
‭<properties>‬
‭<env>development</env>‬
‭</properties>‬
</profile>‬

<profile>‬

‭<id>prod</id>‬
‭<properties>‬
‭<env>production</env>‬
‭</properties>‬
</profile>‬

</profiles>‬

‭Activate with:‬

‭sh:‬
mvn package -Pdev‬

‭8. Final‬‭
pom.xml‬‭Example for a Spring Boot App‬
‭xml:‬
<project xmlns="http://maven.apache.org/POM/4.0.0"‬

‭xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"‬
‭xsi:schemaLocation="http://maven.apache.org/POM/4.0.0‬
http://maven.apache.org/xsd/maven-4.0.0.xsd">‬

<modelVersion>4.0.0</modelVersion>‬

<parent>‬

‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter-parent</artifactId>‬
‭<version>3.2.0</version>‬
‭<relativePath/>‬
</parent>‬

‭groupId>com.example</groupId>‬
<
<artifactId>my-springboot-app</artifactId>‬

<version>1.0.0</version>‬

<packaging>jar</packaging>‬

<properties>‬

‭<java.version>17</java.version>‬
</properties>‬

<dependencies>‬

‭<dependency>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-starter-web</artifactId>‬
‭</dependency>‬
</dependencies>‬

<build>‬

‭<plugins>‬
‭<plugin>‬
‭<groupId>org.springframework.boot</groupId>‬
‭<artifactId>spring-boot-maven-plugin</artifactId>‬
‭</plugin>‬
‭</plugins>‬
</build>‬

</project>‬

‭Conclusion‬

‭‬ ‭
● pom.xml‬‭is the core file of Maven projects.‬
‭●‬ I‭t defines dependencies, plugins, and build configurations.‬
‭●‬ ‭Spring Boot uses‬‭spring-boot-starter-parent‬‭to simplify dependency‬
‭management.‬
‭●‬ ‭Maven profiles help manage different environments.‬
‭1. What are Beans in Spring?‬

‭ ‬‭Bean‬‭is an object managed by the Spring IoC container. It is created, configured, and‬
A
‭managed by Spring.‬

‭●‬ ‭Beans are defined in Java classes with annotations like‬‭


@Component‬‭,‬‭
@Service‬
‭,‬
@Repository‬
‭ ‭, or‬‭
@Bean‬
‭.‬
‭●‬ ‭They are‬‭singleton‬‭by default (only one instance exists per container).‬

‭Example of a Bean:‬
‭java:‬
import org.springframework.stereotype.Component;‬

‭Component‬
@
public class MyBean {‬

public void showMessage() {‬

‭System.out.println("Hello from MyBean!");‬
}‬

}‬

‭2. IoC (Inversion of Control) Container‬

‭The‬‭IoC Container‬‭is responsible for managing the lifecycle of Beans.‬

‭ ‬ I‭t‬‭creates, configures, and injects‬‭dependencies into beans automatically.‬



‭●‬ ‭The two main IoC containers in Spring are:‬
‭○‬ ‭BeanFactory‬‭– Basic container, lazy initialization.‬
‭○‬ ‭ApplicationContext‬‭– Advanced, supports AOP, events, and property files.‬

‭3. ApplicationContext in Spring Boot‬

ApplicationContext‬‭is the most commonly used IoC container.‬‭It provides:‬


‭‬ B
● ‭ ean lifecycle management‬
‭●‬ ‭Dependency injection‬
‭●‬ ‭Internationalization, event handling, and more.‬

‭Example of using ApplicationContext:‬


‭java:‬
import org.springframework.context.ApplicationContext;‬

‭mport‬
i
org.springframework.context.annotation.AnnotationConfigApplicationCo‬

ntext;‬

public class MainApp {‬



public static void main(String[] args) {‬

‭ApplicationContext context = new‬
AnnotationConfigApplicationContext(AppConfig.class);‬

‭MyBean myBean = context.getBean(MyBean.class);‬
‭myBean.showMessage();‬
}‬

}‬

‭Here,‬‭
ApplicationContext‬‭loads beans from the‬‭
AppConfig‬‭class.‬

‭4. Important Spring Annotations‬

‭Spring Boot provides annotations to simplify bean management.‬

‭(a)‬‭
@Component‬

‭Marks a class as a Spring-managed bean.‬

‭java:‬
‭Component‬
@
public class MyService {‬

public String getService() {‬

‭return "Service called!";‬
}‬

}‬

‭(b)‬‭
@ComponentScan‬

‭ cans a package for components (‬‭


S @Component‬‭,‬‭
@Service‬
‭,‬‭
@Repository‬
‭) and registers‬
‭them.‬

‭java:‬
‭mport org.springframework.context.annotation.ComponentScan;‬
i
import org.springframework.context.annotation.Configuration;‬

@Configuration‬

‭ComponentScan(basePackages = "com.example")‬
@
public class AppConfig {‬

}‬

‭(c)‬‭
@SpringBootApplication‬

‭This is a‬‭combination of three annotations‬‭:‬

‭●‬ ‭Configuration‬‭– Marks the class as a configuration class.‬


@
‭‬ ‭
● @EnableAutoConfiguration‬‭– Enables Spring Boot’s auto-configuration.‬
‭●‬ ‭
@ComponentScan‬‭– Scans for beans in the package.‬

‭Example:‬

‭java:‬
‭mport org.springframework.boot.SpringApplication;‬
i
import org.springframework.boot.autoconfigure.SpringBootApplication;‬

‭SpringBootApplication‬
@
public class MyApp {‬

public static void main(String[] args) {‬

‭SpringApplication.run(MyApp.class, args);‬
}‬

}‬

‭This annotation‬‭eliminates the need‬‭for‬‭


@ComponentScan‬‭and‬‭
@Configuration‬‭.‬

‭5. Dependency Injection (DI)‬

‭ ependency Injection‬‭is a design pattern where the‬‭IoC container injects dependencies‬


D
‭automatically‬‭instead of manually creating objects.‬

‭Types of Dependency Injection‬


‭ onstructor Injection‬‭(Preferred)‬
C
‭java:‬
‭Component‬
@
public class Car {‬

private Engine engine;‬

‭Autowired‬
@
public Car(Engine engine) {‬

‭this.engine = engine;‬
}‬

}‬

‭ etter Injection‬
S
‭java:‬
‭Component‬
@
public class Car {‬

private Engine engine;‬

‭Autowired‬
@
public void setEngine(Engine engine) {‬

‭this.engine = engine;‬
}‬

}‬

‭ ield Injection‬‭(Not recommended)‬


F
‭java:‬
‭Component‬
@
public class Car {‬

@Autowired‬

private Engine engine;‬

}‬

‭6. More Spring Boot Annotations‬


‭Annotation‬ ‭Description‬

@Service‬
‭ ‭Marks a service class (business logic).‬

‭Reposito‬ ‭Marks a repository (DAO layer, database interactions).‬


@
ry‬

@Bean‬
‭ ‭Used inside‬‭
@Configuration‬‭to define beans manually.‬

‭Autowire‬ ‭Injects dependencies automatically.‬


@
d‬

‭Qualifie‬ U
@ ‭ sed to select a specific bean when multiple implementations‬
r‬
‭ ‭exist.‬

@Primary‬
‭ ‭Marks a bean as the default choice.‬
‭Conclusion‬

‭‬ S
● ‭ pring Beans‬‭are objects managed by the IoC Container.‬
‭●‬ ‭The‬‭IoC Container‬‭(ApplicationContext) creates and injects dependencies.‬
‭●‬ ‭Spring Boot simplifies configuration using‬‭annotations‬‭like‬‭
@Component‬
‭,‬
@SpringBootApplication‬‭, and‬‭
‭ @Autowired‬
‭.‬
‭●‬ ‭Dependency Injection‬‭reduces coupling and improves testability.‬
‭Spring Boot REST API Basics‬

‭Spring Boot makes it easy to create REST APIs using‬‭Spring Web‬‭. Let's go step by step.‬

‭1. What is a REST API?‬

‭ ‬‭REST API (Representational State Transfer API)‬‭is an interface for communication‬


A
‭between client and server using HTTP methods like:‬

‭‬
● ‭ ET‬‭– Retrieve data‬
G
‭●‬ ‭POST‬‭– Create new data‬
‭●‬ ‭PUT‬‭– Update existing data‬
‭●‬ ‭DELETE‬‭– Remove data‬

‭Spring Boot provides annotations to map these HTTP methods easily.‬

‭2.‬‭
@RestController‬‭Annotation‬
‭RestController‬‭is a‬‭specialized version‬‭of‬‭
@ @Controller‬‭that combines‬
@Controller‬‭and‬‭@ResponseBody‬‭.‬

‭●‬ ‭It automatically converts responses into JSON or XML.‬

‭Example‬
‭java:‬
‭mport org.springframework.web.bind.annotation.GetMapping;‬
i
import org.springframework.web.bind.annotation.RequestMapping;‬

import org.springframework.web.bind.annotation.RestController;‬

‭RestController‬
@
@RequestMapping("/api")‬

public class HelloController {‬

‭GetMapping("/hello")‬
@
public String sayHello() {‬

‭return "Hello, Avinash!";‬
}‬

}‬

‭●‬‭RestController‬‭makes this class a REST API.‬


@
‭‬ ‭
● @RequestMapping("/api")‬‭sets the base path for all endpoints.‬
‭●‬ @GetMapping("/hello")‬‭maps‬‭
‭ GET /api/hello‬
‭.‬

‭3. HTTP Methods Mapping‬


‭Annotation‬ ‭HTTP Method‬ ‭Purpose‬

@GetMapping‬
‭ ‭GET‬ ‭Retrieve data‬

@PostMapping‬ ‭POST‬
‭ ‭Create new data‬

@PutMapping‬
‭ ‭PUT‬ ‭ pdate existing‬
U
‭data‬

‭DeleteMappi‬ ‭DELETE‬
@ ‭Delete data‬
ng‬

‭4.‬‭
@GetMapping‬‭– Fetch Data‬
‭Used to retrieve resources.‬

‭Example: Get all users‬


‭java:‬
‭mport
i org.springframework.web.bind.annotation.GetMapping;‬
import
‭ org.springframework.web.bind.annotation.RequestMapping;‬
import
‭ org.springframework.web.bind.annotation.RestController;‬
import
‭ java.util.List;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭GetMapping‬
@
public List<String> getUsers() {‬

‭return List.of("Avinash", "John", "Alice");‬
}‬

}‬

‭●‬ ‭Calling‬‭
GET /users‬‭returns a JSON list.‬

‭5.‬‭
@PostMapping‬‭– Create Data‬
‭Used to send data to the server.‬

‭Example: Add a new user‬


‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭PostMapping‬
@
public String addUser(@RequestBody String name) {‬

‭return "User " + name + " added successfully!";‬
}‬

}‬

‭●‬ @RequestBody‬‭captures JSON input.‬



‭ ‬ ‭Sending a‬‭POST request‬‭with‬‭
● "Avinash"‬‭creates a new user.‬

‭6.‬‭
@PathVariable‬‭– Dynamic URL Parameters‬
‭Extracts‬‭values from the URL‬‭.‬

‭Example: Get user by ID‬


‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭GetMapping("/{id}")‬
@
public String getUser(@PathVariable int id) {‬

‭return "User with ID: " + id;‬
}‬

}‬

‭●‬ ‭GET‬‭
/users/101‬‭→‬‭"User with ID: 101"‬
‭7.‬‭
@PutMapping‬‭– Update Data‬
‭Updates existing data.‬

‭Example: Update user details‬


‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭PutMapping("/{id}")‬
@
public String updateUser(@PathVariable int id, @RequestBody‬

String name) {‬

‭return "User " + id + " updated to " + name;‬
}‬

}‬

‭●‬ ‭PUT‬‭
/users/101‬‭with‬‭"New Name"‬‭updates user 101.‬

‭8.‬‭
@DeleteMapping‬‭– Delete Data‬
‭Removes a resource.‬

‭Example: Delete a user‬


‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭DeleteMapping("/{id}")‬
@
public String deleteUser(@PathVariable int id) {‬

‭return "User with ID " + id + " deleted";‬
}‬

}‬

‭●‬ ‭DELETE‬‭
/users/101‬‭→‬‭"User with ID 101 deleted"‬
‭9. Full REST API Example‬
‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭mport java.util.ArrayList;‬
i
import java.util.List;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭rivate List<String> users = new ArrayList<>(List.of("Avinash",‬


p
"John", "Alice"));‬

‭GetMapping‬
@
public List<String> getUsers() {‬

‭return users;‬
}‬

‭GetMapping("/{id}")‬
@
public String getUser(@PathVariable int id) {‬

‭return users.get(id);‬
}‬

‭PostMapping‬
@
public String addUser(@RequestBody String name) {‬

‭users.add(name);‬
‭return "User " + name + " added successfully!";‬
}‬

‭PutMapping("/{id}")‬
@
public String updateUser(@PathVariable int id, @RequestBody‬

String name) {‬

‭users.set(id, name);‬
‭return "User " + id + " updated to " + name;‬
}‬

‭DeleteMapping("/{id}")‬
@
public String deleteUser(@PathVariable int id) {‬

‭users.remove(id);‬
‭return "User " + id + " deleted";‬
}‬

}‬

‭●‬ ‭GET‬‭
/users‬‭→ Returns all users.‬
‭●‬ ‭GET‬‭
/users/1‬‭→ Returns‬‭"John"‬‭.‬
‭●‬ ‭POST‬‭
/users‬‭with‬‭"Bob"‬‭→ Adds‬‭
"Bob"‬
‭.‬
‭●‬ ‭PUT‬‭
/users/1‬‭with‬‭"New
John"‬‭→ Updates‬‭
"John"‬‭.‬
‭ ELETE‬‭
‭‬ D
● /users/1‬‭→ Removes‬‭
"John"‬‭.‬

‭10. Testing REST APIs‬

‭‬ P
● ‭ ostman‬‭– GUI tool for API testing.‬
‭●‬ ‭cURL‬‭– Command-line tool.‬
‭●‬ ‭Swagger‬‭– API documentation.‬

‭Example‬‭cURL commands‬‭:‬

‭sh:‬
‭url
c -X GET http://localhost:8080/users‬
curl
‭ -X POST http://localhost:8080/users -d "Bob"‬
curl
‭ -X PUT http://localhost:8080/users/1 -d "New Bob"‬
curl
‭ -X DELETE http://localhost:8080/users/1‬

‭Conclusion‬

‭●‬‭RestController‬‭simplifies REST API creation.‬


@
‭‬ ‭
● @GetMapping‬
‭,‬‭
@PostMapping‬ ‭,‬‭
@PutMapping‬‭,‬‭
@DeleteMapping‬‭handle HTTP‬
‭methods.‬
‭‬ ‭
● @PathVariable‬‭extracts data from the URL.‬
‭●‬ A
‭ PIs can be tested using‬‭Postman, Swagger, or cURL‬‭.‬
‭1. What is a REST API?‬

‭ ‬‭REST API (Representational State Transfer API)‬‭is a web service that allows‬
A
‭communication between a client (frontend, mobile app, etc.) and a server using‬‭HTTP‬
‭methods‬‭. It follows‬‭REST principles‬‭, meaning:‬

‭‬ S
● ‭ tateless‬‭– No client data is stored on the server between requests.‬
‭●‬ ‭Client-Server Architecture‬‭– The frontend and backend are separate.‬
‭●‬ ‭Uses HTTP Methods‬‭– REST APIs commonly use:‬
‭○‬ ‭
GET‬‭→ Retrieve data‬
‭○‬ P‭OST‬‭→ Create data‬
‭‬ ‭
○ PUT‬‭→ Update data‬
‭○‬ ‭DELETE‬‭→ Remove data‬

‭Spring Boot makes REST API development easy with annotations.‬

‭2.‬‭
@RestController‬‭Annotation‬
@RestController‬‭is a combination of‬‭
‭ @Controller‬‭and‬‭
@ResponseBody‬
‭.‬

‭ ‬ I‭t‬‭automatically converts responses to JSON‬‭.‬



‭●‬ ‭Eliminates the need for‬‭
@ResponseBody‬‭on every method.‬

‭Example:‬
‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/api")‬

public class HelloController {‬

‭GetMapping("/hello")‬
@
public String sayHello() {‬

‭return "Hello, Avinash!";‬
}‬

}‬

‭●‬ ‭RestController‬‭makes this a REST API.‬


@
‭‬ ‭
● @RequestMapping("/api")‬‭sets the base path.‬
‭●‬ ‭
@GetMapping("/hello")‬‭maps‬‭GET /api/hello‬‭to return‬‭a response.‬
‭3.‬‭
@GetMapping‬‭– Retrieve Data‬
‭Used to fetch resources.‬

‭Example: Get all users‬


‭java:‬
‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭GetMapping‬
@
public List<String> getUsers() {‬

‭return List.of("Avinash", "John", "Alice");‬
}‬

}‬

‭●‬ ‭Calling‬‭GET‬‭
/users‬‭returns a JSON list.‬

‭4.‬‭
@PostMapping‬‭– Create Data‬
‭Used to send data to the server.‬

‭Example: Add a new user‬


‭java:‬
‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭PostMapping‬
@
public String addUser(@RequestBody String name) {‬

‭return "User " + name + " added successfully!";‬
}‬

}‬

‭●‬ @RequestBody‬‭captures JSON input.‬



‭ ‬ ‭Sending a‬‭POST request‬‭with‬‭
● "Avinash"‬‭creates a new user.‬

‭5.‬‭
@PathVariable‬‭– Extract URL Data‬
‭Used to get‬‭dynamic values from the URL‬‭.‬
‭Example: Get user by ID‬
‭java:‬
‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭GetMapping("/{id}")‬
@
public String getUser(@PathVariable int id) {‬

‭return "User with ID: " + id;‬
}‬

}‬

‭●‬ ‭GET‬‭
/users/101‬‭→‬‭"User with ID: 101"‬

‭6.‬‭
@PutMapping‬‭– Update Data‬
‭Used to modify existing resources.‬

‭Example: Update user details‬


‭java:‬
‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭PutMapping("/{id}")‬
@
public String updateUser(@PathVariable int id, @RequestBody‬

String name) {‬

‭return "User " + id + " updated to " + name;‬
}‬

}‬

‭●‬ ‭PUT‬‭
/users/101‬‭with‬‭"New Name"‬‭updates user 101.‬

‭7.‬‭
@DeleteMapping‬‭– Remove Data‬
‭Used to delete resources.‬

‭Example: Delete a user‬


‭java:‬
‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭DeleteMapping("/{id}")‬
@
public String deleteUser(@PathVariable int id) {‬

‭return "User with ID " + id + " deleted";‬
}‬

}‬

‭●‬ ‭DELETE‬‭
/users/101‬‭→‬‭"User with ID 101 deleted"‬

‭8. Full REST API Example‬


‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭mport java.util.ArrayList;‬
i
import java.util.List;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

‭rivate List<String> users = new ArrayList<>(List.of("Avinash",‬


p
"John", "Alice"));‬

‭GetMapping‬
@
public List<String> getUsers() {‬

‭return users;‬
}‬

‭GetMapping("/{id}")‬
@
public String getUser(@PathVariable int id) {‬

‭return users.get(id);‬
}‬

‭PostMapping‬
@
public String addUser(@RequestBody String name) {‬

‭users.add(name);‬
‭return "User " + name + " added successfully!";‬
}‬

‭PutMapping("/{id}")‬
@
public String updateUser(@PathVariable int id, @RequestBody‬

String name) {‬

‭users.set(id, name);‬
‭return "User " + id + " updated to " + name;‬
}‬

‭DeleteMapping("/{id}")‬
@
public String deleteUser(@PathVariable int id) {‬

‭users.remove(id);‬
‭return "User " + id + " deleted";‬
}‬

}‬

‭●‬ ‭GET‬‭
/users‬‭→ Returns all users.‬
‭●‬ ‭GET‬‭
/users/1‬‭→ Returns‬‭"John"‬‭.‬
‭●‬ ‭POST‬‭
/users‬‭with‬‭"Bob"‬‭→ Adds‬‭
"Bob"‬
‭.‬
‭●‬ ‭PUT‬‭
/users/1‬‭with‬‭"New
John"‬‭→ Updates‬‭
"John"‬‭.‬
‭ ELETE‬‭
‭‬ D
● /users/1‬‭→ Removes‬‭
"John"‬‭.‬

‭Conclusion‬

‭●‬‭RestController‬‭simplifies API creation.‬


@
‭‬ ‭
● @GetMapping‬
‭,‬‭
@PostMapping‬ ‭,‬‭
@PutMapping‬
‭,‬‭
@DeleteMapping‬‭map HTTP‬
‭methods.‬
‭●‬ @PathVariable‬‭extracts values from the URL.‬

‭1. Object-Relational Mapping (ORM)‬
‭ RM‬‭is a technique that maps‬‭Java objects to database tables‬‭. Instead of writing raw SQL‬
O
‭queries, we use objects to interact with the database.‬

‭‬ H
● ‭ elps in‬‭reducing boilerplate code‬‭.‬
‭●‬ ‭Improves‬‭database independence‬‭.‬
‭●‬ ‭Examples of ORM frameworks:‬‭Hibernate, JPA, Spring Data JPA‬‭.‬

‭2. Java Persistence API (JPA)‬


‭JPA‬‭is a‬‭Java standard‬‭for ORM. It is just a specification (not an implementation).‬

‭‬ P
● ‭ rovides‬‭annotations‬‭like‬‭
@Entity‬‭,‬‭
@Id‬
‭,‬‭
@Table‬
‭, etc.‬
‭●‬ ‭Defines‬‭EntityManager‬‭to interact with the database.‬
‭●‬ ‭Can work with‬‭any persistence provider‬‭like Hibernate.‬

‭Example: JPA Entity (MySQL)‬


‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "users")‬

public class User {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭Column(nullable = false)‬
@
private String name;‬

// Getters & Setters‬



}‬

‭●‬ ‭Entity‬‭– Marks this as a table.‬


@
‭‬ ‭
● @Table(name="users")‬‭– Sets table name.‬
‭●‬ ‭@Id‬‭– Marks primary key.‬
‭●‬ ‭
@GeneratedValue‬‭– Auto-increments ID.‬
‭3. Spring Data JPA‬
‭Spring Data JPA‬‭simplifies‬‭database operations by removing the need for‬
EntityManager‬‭.‬

‭‬ U
● ‭ ses‬‭repositories‬‭instead of manually writing queries.‬
‭●‬ ‭Supports‬‭Query Method DSL‬‭and‬‭custom queries‬‭.‬

‭Spring Data JPA Repository (MySQL)‬


‭java:‬
import org.springframework.data.jpa.repository.JpaRepository;‬

‭ublic interface UserRepository extends JpaRepository<User, Long> {‬


p
}‬

‭●‬ ‭We get‬‭CRUD methods automatically‬‭(‭


s‬ ave()‬‭,‬‭
findAll()‬
‭,‬‭
findById()‬
‭, etc.).‬
‭●‬ ‭No need to write‬‭
EntityManager.persist()‬
‭,‬‭
EntityManager.find()‬
‭,‬‭etc.‬

‭4. Persistence Provider‬


‭A‬‭persistence provider‬‭is an implementation of JPA. Examples:‬

‭‬ H
● ‭ ibernate‬‭(most common for MySQL, PostgreSQL, etc.)‬
‭●‬ ‭EclipseLink‬
‭●‬ ‭OpenJPA‬

‭5. Hibernate (Most Common JPA Implementation)‬


‭‬ H
● ‭ ibernate is an‬‭ORM framework‬‭that implements JPA.‬
‭●‬ ‭Supports‬‭HQL (Hibernate Query Language)‬‭and‬‭Native‬‭SQL‬‭.‬
‭●‬ ‭Works with‬‭Spring Boot‬‭as a persistence provider.‬

‭Hibernate Configuration (MySQL) in‬‭


application.properties‬
‭properties:‬
‭pring.datasource.url=jdbc:mysql://localhost:3306/mydb‬
s
spring.datasource.username=root‬

spring.datasource.password=root‬

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver‬

‭pring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect‬
s
spring.jpa.hibernate.ddl-auto=update‬

‭●‬ hibernate.ddl-auto=update‬‭→ Automatically updates schema based on entity‬



‭classes.‬

‭6. Query Method DSL (Derived Query Methods)‬


‭Spring Data JPA allows defining methods in repositories without writing queries.‬

‭Example Queries in‬‭


UserRepository‬
‭java:‬
‭mport org.springframework.data.jpa.repository.JpaRepository;‬
i
import java.util.List;‬

public interface UserRepository extends JpaRepository<User, Long> {‬


‭/ Find users by name‬


/
List<User> findByName(String name);‬

‭/ Find users whose name contains a keyword‬


/
List<User> findByNameContaining(String keyword);‬

‭/ Find users by name ignoring case‬


/
List<User> findByNameIgnoreCase(String name);‬

}‬

‭●‬ ‭indByName("Avinash")‬‭→ Finds exact match.‬


f
‭‬ ‭
● findByNameContaining("vin")‬‭→ Finds partial match.‬
‭●‬ ‭
findByNameIgnoreCase("avinash")‬‭→ Case-insensitive‬‭search.‬

‭7. Criteria API (Dynamic Queries in Hibernate/JPA)‬


‭When queries‬‭depend on user input‬‭, Criteria API helps in building them dynamically.‬

‭Example: Criteria API Query‬


‭java:‬
‭mport jakarta.persistence.*;‬
i
import jakarta.persistence.criteria.*;‬

import java.util.List;‬

‭Repository‬
@
public class UserRepositoryCustom {‬

‭PersistenceContext‬
@
private EntityManager entityManager;‬

public List<User> getUsersWithName(String name) {‬



‭CriteriaBuilder cb = entityManager.getCriteriaBuilder();‬
‭CriteriaQuery<User> query = cb.createQuery(User.class);‬
‭Root<User> root = query.from(User.class);‬

‭query.select(root).where(cb.equal(root.get("name"), name));‬

‭return entityManager.createQuery(query).getResultList();‬
}‬

}‬

‭‬ C
● ‭ riteriaBuilder‬‭builds queries dynamically.‬
‭●‬ ‭Works with‬‭complex filtering‬‭conditions.‬
‭MongoDB (NoSQL) with Spring Boot‬
‭MongoDB is a‬‭document-based NoSQL database‬‭.‬

‭1. Setup MongoDB in‬‭


application.properties‬
‭properties:‬
‭pring.data.mongodb.uri=mongodb://localhost:27017/mydb‬
s
spring.data.mongodb.database=mydb‬

‭2. Define MongoDB Entity‬


‭MongoDB uses‬‭
@Document‬‭instead of‬‭
@Entity‬
‭.‬

‭java:‬
‭mport org.springframework.data.annotation.Id;‬
i
import org.springframework.data.mongodb.core.mapping.Document;‬

‭Document(collection = "users")‬
@
public class User {‬

‭Id‬
@
private String id;‬

private String name;‬

// Getters & Setters‬



}‬

‭●‬‭Document(collection = "users")‬‭– Defines a MongoDB collection.‬


@
‭‬ ‭
● @Id‬‭– Marks primary key (MongoDB uses‬‭ObjectId‬‭instead of numeric ID).‬

‭3. Spring Data MongoDB Repository‬


‭Spring Data MongoDB works like JPA but with‬‭
MongoRepository‬‭.‬

‭java:‬
‭mport org.springframework.data.mongodb.repository.MongoRepository;‬
i
import java.util.List;‬

‭ublic interface UserRepository extends MongoRepository<User,‬
p
String> {‬

List<User> findByName(String name);‬



}‬

‭‬ W
● ‭ orks the same as‬‭
JpaRepository‬ ‭, but for MongoDB.‬
‭●‬ ‭No need for Hibernate‬‭(MongoDB does not use ORM).‬

‭4. Query Method DSL for MongoDB‬


‭java:‬
‭mport org.springframework.data.mongodb.repository.Query;‬
i
import java.util.List;‬

‭ublic interface UserRepository extends MongoRepository<User,‬


p
String> {‬

‭/ Find users by name‬


/
List<User> findByName(String name);‬

‭/ Custom MongoDB Query‬


/
@Query("{ 'name' : ?0 }")‬

List<User> getUserByName(String name);‬

}‬

‭●‬‭Query("{ 'name' : ?0 }")‬‭– Native MongoDB query.‬


@
‭‬ ‭
● findByName("Avinash")‬‭– Finds users by name.‬

‭5. Criteria API for MongoDB (Dynamic Queries)‬


‭java:‬
‭mport
i org.springframework.data.mongodb.core.MongoTemplate;‬
import
‭ org.springframework.data.mongodb.core.query.Criteria;‬
import
‭ org.springframework.data.mongodb.core.query.Query;‬
import
‭ org.springframework.stereotype.Repository;‬
import
‭ java.util.List;‬
‭Repository‬
@
public class UserRepositoryCustom {‬

private final MongoTemplate mongoTemplate;‬


public UserRepositoryCustom(MongoTemplate mongoTemplate) {‬



‭this.mongoTemplate = mongoTemplate;‬
}‬

public List<User> getUsersByName(String name) {‬



‭Query query = new Query();‬
‭query.addCriteria(Criteria.where("name").is(name));‬

‭return mongoTemplate.find(query, User.class);‬


}‬

}‬

‭‬ M
● ‭ ongoTemplate‬‭is used for dynamic queries.‬
‭●‬ ‭Criteria.where("name").is(name)‬‭– Works like Hibernate's‬‭Criteria API.‬

‭Conclusion‬
‭Feature‬ ‭MySQL (Relational DB)‬ ‭MongoDB (NoSQL)‬

‭ORM‬ ‭Hibernate (JPA)‬ ‭No ORM needed‬

‭Entity Definition‬ ‭@Entity‬ @Document‬



‭Repository‬ ‭JpaRepository‬ MongoRepository‬

‭Query Method DSL‬ ‭Yes‬ ‭Yes‬

‭Criteria API‬ ‭CriteriaBuilder‬ MongoTemplate‬



‭ . Spring Boot Project Structure (Best‬
1
‭Practices)‬
‭A well-structured‬‭Spring Boot project‬‭follows the‬‭Layered Architecture‬‭:‬

‭rc/main/java/com/example/demo‬
s
‭ ── controller/
├ (REST APIs)‬
‭ ── service/
├ (Business logic)‬
‭ ── repository/
├ (Database interactions)‬
‭ ── entity/
├ (Database models)‬
‭ ── dao/
├ (Custom queries)‬
‭ ── config/
├ (Configuration classes)‬
‭ ── dto/
├ (Data Transfer Objects)‬
‭ ── exception/
├ (Exception handling)‬
‭ ── util/
├ (Utility classes)‬
‭ ── DemoApplication.java (Main class)‬

‭Explanation:‬

‭●‬ ‭controller/‬‭→ Exposes REST APIs (‬‭


@RestController‬
‭).‬
‭●‬ ‭service/‬‭→ Contains business logic (‬‭
@Service‬
‭).‬
‭●‬ ‭repository/‬‭→ Extends‬‭
JpaRepository‬‭or‬‭
MongoRepository‬‭.‬
‭●‬ ‭entity/‬‭→ Contains database models (‬‭
@Entity‬
‭,‬‭
@Document‬
‭).‬
‭‬
● ‭ ao/‬‭→ For complex queries using‬‭
d EntityManager‬‭or‬‭MongoTemplate‬
‭.‬
‭●‬ ‭config/‬‭→ Configures Beans, Security, Caching, etc.‬
‭●‬ ‭dto/‬‭→ Used to transfer data between layers.‬
‭●‬ ‭exception/‬‭→ Custom exceptions and global exception‬‭handling.‬
‭●‬ ‭util/‬‭→ Utility/helper methods.‬

‭2. Spring Boot Configuration‬


‭2.1. MySQL Configuration (‬‭
application.properties‬
‭)‬
‭properties:‬
‭pring.datasource.url=jdbc:mysql://localhost:3306/mydb‬
s
spring.datasource.username=root‬

spring.datasource.password=root‬

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver‬

‭pring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect‬
s
spring.jpa.hibernate.ddl-auto=update‬

spring.jpa.show-sql=true‬

‭●‬‭dl-auto=update‬‭→ Automatically updates schema.‬


d
‭‬ ‭
● show-sql=true‬‭→ Logs queries in console.‬

‭ .2. MongoDB Configuration‬


2
‭(‭
a‬ pplication.properties‬‭)‬
‭properties:‬
‭pring.data.mongodb.uri=mongodb://localhost:27017/mydb‬
s
spring.data.mongodb.database=mydb‬

‭●‬ ‭No need for Hibernate; Spring Data handles it.‬

‭3. Entity Definitions‬


‭3.1. MySQL Entity (‬‭
User.java‬‭)‬
‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "users")‬

public class User {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭Column(nullable = false)‬
@
private String name;‬

// Getters & Setters‬



}‬

‭3.2. MongoDB Entity (‬‭
User.java‬‭)‬
‭java:‬
‭mport org.springframework.data.annotation.Id;‬
i
import org.springframework.data.mongodb.core.mapping.Document;‬

‭Document(collection = "users")‬
@
public class User {‬

‭Id‬
@
private String id;‬

private String name;‬

// Getters & Setters‬



}‬

‭4. Repository Layer‬


‭4.1. MySQL Repository‬
‭java:‬
import org.springframework.data.jpa.repository.JpaRepository;‬

‭ublic interface UserRepository extends JpaRepository<User, Long> {‬


p
}‬

‭4.2. MongoDB Repository‬


‭java:‬
import org.springframework.data.mongodb.repository.MongoRepository;‬

‭ublic interface UserRepository extends MongoRepository<User,‬


p
String> {‬

}‬

‭5. Service Layer‬
‭5.1. Service Interface‬
‭java:‬
import java.util.List;‬

public interface UserService {‬



User saveUser(User user);‬

List<User> getAllUsers();‬

User getUserById(Long id);‬

User updateUser(Long id, User user);‬

void deleteUser(Long id);‬

}‬

‭5.2. Service Implementation (MySQL)‬


‭java:‬
‭mport org.springframework.stereotype.Service;‬
i
import java.util.List;‬

import java.util.Optional;‬

‭Service‬
@
public class UserServiceImpl implements UserService {‬

private final UserRepository userRepository;‬


public UserServiceImpl(UserRepository userRepository) {‬



‭this.userRepository = userRepository;‬
}‬

‭Override‬
@
public User saveUser(User user) {‬

‭return userRepository.save(user);‬
}‬

‭Override‬
@
public List<User> getAllUsers() {‬

‭return userRepository.findAll();‬
}‬

‭Override‬
@
public User getUserById(Long id) {‬

‭return userRepository.findById(id)‬
‭.orElseThrow(() -> new RuntimeException("User not‬
found"));‬

}‬

‭Override‬
@
public User updateUser(Long id, User user) {‬

‭User existingUser = getUserById(id);‬
‭existingUser.setName(user.getName());‬
‭return userRepository.save(existingUser);‬
}‬

‭Override‬
@
public void deleteUser(Long id) {‬

‭userRepository.deleteById(id);‬
}‬

}‬

‭6. Controller Layer‬


‭java:‬
‭mport org.springframework.web.bind.annotation.*;‬
i
import java.util.List;‬

‭RestController‬
@
@RequestMapping("/users")‬

public class UserController {‬

private final UserService userService;‬


public UserController(UserService userService) {‬



‭this.userService = userService;‬
}‬

‭PostMapping‬
@
public User createUser(@RequestBody User user) {‬

‭return userService.saveUser(user);‬
}‬

‭GetMapping‬
@
public List<User> getAllUsers() {‬

‭return userService.getAllUsers();‬
}‬

‭GetMapping("/{id}")‬
@
public User getUserById(@PathVariable Long id) {‬

‭return userService.getUserById(id);‬
}‬

‭PutMapping("/{id}")‬
@
public User updateUser(@PathVariable Long id, @RequestBody User‬

user) {‬

‭return userService.updateUser(id, user);‬
}‬

‭DeleteMapping("/{id}")‬
@
public void deleteUser(@PathVariable Long id) {‬

‭userService.deleteUser(id);‬
}‬

}‬

‭7. CRUD Operations‬


‭Saving Entity in DB‬
‭OST /users‬
P
Content-Type: application/json‬

{‬

"name": "Avinash"‬

}‬

‭Getting All Users‬


GET /users‬

‭Getting User by ID‬
GET /users/1‬

‭Updating User‬
‭UT /users/1‬
P
Content-Type: application/json‬

{‬

"name": "Updated Name"‬

}‬

‭Deleting User‬
DELETE /users/1‬

‭8. Best Practices‬




‭ ‬‭Use DTOs (Data Transfer Objects)‬‭to avoid exposing entities directly.‬
‭ ‬‭Exception Handling‬‭using‬‭
@ControllerAdvice‬ ‭.‬

‭ ‬‭Use Constructor Injection‬‭instead of‬‭
@Autowired‬ ‭.‬
‭✅‬‭Enable Logging‬‭(‭
s‬ lf4j.LoggerFactory‬‭).‬
‭✅‬‭Use Environment Variables‬‭for sensitive data (‬‭
@Value("${db.username}")‬
‭).‬
‭Types of HTTP Status Codes‬
‭ TTP status codes are‬‭3-digit numbers‬‭that indicate the response of a request. They are‬
H
‭categorized into‬‭five groups‬‭:‬

‭1. 1xx - Informational‬

‭These codes indicate that the request has been received and is being processed.‬

‭●‬ ‭00 Continue‬‭– Server received the request, and the client should continue.‬
1
‭●‬ ‭
101 Switching Protocols‬‭– Protocol upgrade request is accepted.‬

‭2. 2xx - Success‬

‭These codes indicate that the request was successful.‬

‭●‬ ‭00
2 OK‬‭– Request was successful.‬
‭‬ ‭
● 201 Created‬‭– Resource successfully created (e.g., after‬‭
POST‬‭request).‬
‭●‬ ‭202 Accepted‬‭– Request accepted but processing is not complete.‬
‭●‬ ‭
204 No Content‬‭– Request successful, but no response body is returned.‬

‭3. 3xx - Redirection‬

‭These codes indicate that the client must take additional action to complete the request.‬

‭●‬ ‭01 Moved Permanently‬‭– Resource is permanently moved to a new URL.‬


3
‭●‬ ‭302 Found‬–‭ Resource is temporarily moved.‬
‭●‬ ‭
304 Not Modified‬‭– Cached response is still valid; no need to re-fetch.‬

‭4. 4xx - Client Errors‬

‭These codes indicate that there is an issue with the client’s request.‬

‭●‬ ‭00
4 Bad Request‬‭– Invalid request syntax.‬
‭●‬ 401
‭ Unauthorized‬‭– Authentication is required.‬
‭●‬ 403
‭ Forbidden‬‭– Server understood but refuses to authorize.‬
‭●‬ 404
‭ Not Found‬‭– Requested resource does not exist.‬
‭●‬ 405
‭ Method Not Allowed‬‭– HTTP method is not supported for the requested‬
‭resource.‬

‭5. 5xx - Server Errors‬

‭These codes indicate that the server encountered an error while processing the request.‬

‭●‬ ‭00 Internal Server Error‬‭– Generic error message.‬


5
‭●‬ ‭
502 Bad Gateway‬‭– Server received an invalid response‬‭from the upstream server.‬
‭●‬ 503 Service Unavailable‬‭– Server is temporarily down or overloaded.‬

‭ResponseEntity Class in Spring Boot‬


ResponseEntity<T>‬‭is a class in Spring Boot that represents an‬‭HTTP response‬

‭including:‬

‭ .‬ R
1 ‭ esponse Body‬‭(Data)‬
‭2.‬ ‭HTTP Status Code‬
‭3.‬ ‭Headers‬

‭Basic Usage‬
‭java:‬
‭mport org.springframework.http.ResponseEntity;‬
i
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/api")‬

public class DemoController {‬

‭GetMapping("/success")‬
@
public ResponseEntity<String> successResponse() {‬

‭return ResponseEntity.ok("Request was successful!");‬
}‬

}‬

‭●‬ ResponseEntity.ok()‬‭→ Returns‬‭


‭ 200 OK‬‭with the response body.‬

‭Returning Different Status Codes‬


‭java:‬
‭mport org.springframework.http.HttpStatus;‬
i
import org.springframework.http.ResponseEntity;‬

‭GetMapping("/notfound")‬
@
public ResponseEntity<String> notFoundResponse() {‬

return new ResponseEntity<>("Resource not found",‬

HttpStatus.NOT_FOUND);‬

}‬

‭●‬ ‭Returns‬‭
404 Not Found‬
‭.‬

‭Returning Custom Headers‬


‭java:‬
import org.springframework.http.HttpHeaders;‬

‭GetMapping("/custom-header")‬
@
public ResponseEntity<String> customHeaderResponse() {‬

HttpHeaders headers = new HttpHeaders();‬

headers.add("Custom-Header", "Value");‬

‭eturn new ResponseEntity<>("Response with custom header",‬


r
headers, HttpStatus.OK);‬

}‬

‭●‬ ‭Adds a custom header to the response.‬

‭Returning a Response with a Java Object‬


‭java:‬
import java.util.List;‬

‭GetMapping("/users")‬
@
public ResponseEntity<List<User>> getUsers() {‬

List<User> users = List.of(new User(1L, "Avinash"), new User(2L,‬

"Kumar"));‬

return ResponseEntity.ok(users);‬

}‬

‭●‬ ‭Returns‬‭
200 OK‬‭with a list of users.‬

‭Exception Handling with ResponseEntity‬


‭java:‬
‭GetMapping("/error")‬
@
public ResponseEntity<String> errorResponse() {‬

try {‬

‭throw new RuntimeException("Something went wrong!");‬
} catch (Exception e) {‬

‭return‬
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error:‬

" + e.getMessage());‬

}‬

}‬

‭●‬ ‭Catches exceptions and returns‬‭


500 Internal Server Error‬
‭.‬

‭Conclusion‬

‭ ‬‭
ResponseEntity<T>‬‭is used to customize responses in Spring Boot REST APIs.‬


‭ It allows setting‬‭HTTP status codes, headers, and‬‭response bodies‬‭.‬
‭ It is useful for‬‭error handling, sending custom‬‭headers, and returning objects‬‭.‬
‭Lombok in Spring Boot‬
‭ ombok is a Java library that helps reduce boilerplate code (like getters, setters,‬
L
‭constructors, etc.) by using annotations. It is widely used in Spring Boot projects to make the‬
‭code more concise and readable.‬

‭1. Adding Lombok to a Spring Boot Project‬


‭To use Lombok, add the following dependency in‬‭
pom.xml‬‭:‬

‭xml:‬
<dependency>‬

<groupId>org.projectlombok</groupId>‬

<artifactId>lombok</artifactId>‬

<scope>provided</scope>‬

</dependency>‬

‭After adding, enable‬‭annotation processing‬‭in your IDE (like IntelliJ or Eclipse).‬

‭2. Important Lombok Annotations & Their Uses‬


‭A. Getter and Setter Annotations‬

‭●‬‭Getter‬‭→ Generates getter methods for all fields.‬


@
‭‬ ‭
● @Setter‬‭→ Generates setter methods for all fields.‬

‭Example:‬
‭java:‬
‭mport lombok.Getter;‬
i
import lombok.Setter;‬

‭Getter‬
@
@Setter‬

public class User {‬

private Long id;‬

private String name;‬

}‬

‭Equivalent Code Without Lombok:‬

‭java:‬
public class User {‬

private Long id;‬

private String name;‬

‭ublic
p 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; }‬
}‬

‭B.‬‭
@ToString‬
‭Generates a‬‭
toString()‬‭method automatically.‬

‭Example:‬
‭java:‬
import lombok.ToString;‬

‭ToString‬
@
public class User {‬

private Long id;‬

private String name;‬

}‬

‭Equivalent Code Without Lombok:‬

‭java:‬
‭Override‬
@
public String toString() {‬

return "User{id=" + id + ", name='" + name + "'}";‬

}‬

‭C.‬‭
@EqualsAndHashCode‬
‭Generates‬‭
equals()‬‭and‬‭hashCode()‬‭methods.‬

‭Example:‬
‭java:‬
import lombok.EqualsAndHashCode;‬

‭EqualsAndHashCode‬
@
public class User {‬

private Long id;‬

private String name;‬

}‬

‭Equivalent Code Without Lombok:‬

‭java:‬
‭Override‬
@
public boolean equals(Object o) { /* Implementation */ }‬

‭Override‬
@
public int hashCode() { /* Implementation */ }‬

‭D.‬‭
@NoArgsConstructor‬
‭,‬‭
@AllArgsConstructor‬‭,‬
‭@RequiredArgsConstructor‬
‭●‬ ‭NoArgsConstructor‬‭→ Generates a no-argument constructor.‬
@
‭‬ ‭
● @AllArgsConstructor‬‭→ Generates a constructor with all fields.‬
‭●‬ ‭
@RequiredArgsConstructor‬‭→ Generates a constructor for‬‭ final‬‭fields.‬

‭Example:‬
‭java:‬
‭mport lombok.NoArgsConstructor;‬
i
import lombok.AllArgsConstructor;‬

import lombok.RequiredArgsConstructor;‬

‭NoArgsConstructor‬
@
@AllArgsConstructor‬

@RequiredArgsConstructor‬

public class User {‬

private Long id;‬

private final String name;‬

}‬

‭E.‬‭
@Data‬
‭A‬‭shortcut annotation‬‭that includes:‬

‭●‬ ‭Getter‬
@
‭●‬ @Setter‬

‭●‬ @ToString‬

‭●‬ @EqualsAndHashCode‬

‭●‬ @RequiredArgsConstructor‬

‭Example:‬
‭java:‬
import lombok.Data;‬

‭Data‬
@
public class User {‬

private Long id;‬

private String name;‬

}‬

‭Equivalent Code Without Lombok:‬

‭java:‬
public class User {‬

private Long id;‬

private String name;‬

‭ublic
p 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; }‬

‭Override‬
@
public String toString() { /* Implementation */ }‬

‭Override‬
@
public boolean equals(Object o) { /* Implementation */ }‬

‭Override‬
@
public int hashCode() { /* Implementation */ }‬

}‬

‭F.‬‭
@Builder‬
‭Generates a‬‭builder pattern‬‭for object creation.‬

‭Example:‬
‭java:‬
import lombok.Builder;‬

‭Builder‬
@
public class User {‬

private Long id;‬

private String name;‬

}‬

‭Usage:‬

‭java:‬
User user = User.builder().id(1L).name("Avinash").build();‬

‭G.‬‭
@Value‬
‭Creates‬‭immutable‬‭classes (like‬‭
@Data‬‭but with‬‭
final‬‭fields and no setters).‬

‭Example:‬
‭java:‬
import lombok.Value;‬

‭Value‬
@
public class User {‬

Long id;‬

String name;‬

}‬

‭H.‬‭
@Slf4j‬
‭Generates a‬‭
Logger‬‭instance for logging.‬

‭Example:‬
‭java:‬
import lombok.extern.slf4j.Slf4j;‬

‭Slf4j‬
@
public class LoggerExample {‬

public void logMessage() {‬

‭log.info("Logging a message...");‬
}‬

}‬

‭Equivalent Code Without Lombok:‬

‭java:‬
‭mport org.slf4j.Logger;‬
i
import org.slf4j.LoggerFactory;‬

public class LoggerExample {‬



private static final Logger log =‬

LoggerFactory.getLogger(LoggerExample.class);‬

public void logMessage() {‬



‭log.info("Logging a message...");‬
}‬

}‬

‭3. Internal Working of Lombok‬


‭ ombok‬‭uses annotation processing‬‭to modify the‬‭Abstract Syntax Tree (AST)‬‭of Java‬
L
‭source code‬‭at compile time‬‭.‬

‭Steps of Execution:‬

‭ .‬ L
1 ‭ ombok Plugin‬‭→ Installed in IDE to support annotations.‬
‭2.‬ ‭Annotation Processor‬‭→ During compilation,‬‭ javac‬‭invokes‬‭Lombok's‬
‭processor‬‭.‬
‭3.‬ ‭AST Modification‬‭→ Lombok modifies the‬‭Java class‬‭bytecode‬‭before compiling.‬
‭4.‬ ‭Bytecode Generation‬‭→ The compiler then produces the final‬‭ .class‬‭file with the‬
‭necessary methods.‬

‭Example:‬

‭ hen the compiler processes:‬


W
‭java:‬
@Getter‬

private String name;‬

‭●‬

‭ ombok modifies the AST to:‬


L
‭java:‬
public String getName() { return name; }‬

‭●‬

‭4. Advantages of Using Lombok‬


✅ Reduces‬‭boilerplate code‬‭.‬
✅ Increases‬‭code readability‬‭.‬

✅ Improves‬‭code maintainability‬‭.‬

✅ Enhances‬‭performance‬‭as code is generated at compile-time.‬



‭Conclusion‬
‭ ombok simplifies Java development by‬‭automatically generating getters, setters,‬
L
‭constructors, logging, and more‬‭.‬
‭MongoDB Annotations in Spring Boot‬
‭ hen working with‬‭MongoDB in Spring Boot‬‭, we often need to create indexes for‬
W
‭performance optimization and define relationships between collections.‬
‭Two important annotations for this are‬‭
@Index‬‭and‬‭
@DBRef‬‭.‬

‭1.‬‭
@Indexed‬‭Annotation‬
@Indexed‬‭is used to create an‬‭index‬‭on a field in a MongoDB collection.‬

‭It helps in improving‬‭query performance‬‭.‬

‭Example: Using‬‭
@Indexed‬‭in a MongoDB Document‬
‭java:‬
‭mport org.springframework.data.annotation.Id;‬
i
import org.springframework.data.mongodb.core.index.Indexed;‬

import org.springframework.data.mongodb.core.mapping.Document;‬

‭Document(collection = "users")‬
@
public class User {‬

‭Id‬
@
private String id;‬

‭Indexed(unique = true) // Creates a unique index on the‬


@
"email" field‬

private String email;‬

private String name;‬


// Getters and Setters‬



}‬

‭Explanation:‬

‭●‬‭Indexed‬‭→ Creates an‬‭index‬‭on the‬‭


@ email‬‭field.‬
‭‬ ‭
● unique = true‬‭→ Ensures‬‭no duplicate values‬‭are inserted in the‬‭
email‬‭field.‬
‭2.‬‭
@DBRef‬‭Annotation (Referencing Another Collection)‬
‭ ongoDB is a‬‭NoSQL‬‭database, so it doesn’t have traditional joins like‬‭SQL databases‬‭.‬
M
‭However, we can create relationships between documents using‬‭ @DBRef‬‭.‬

‭Example: One-to-Many Relationship in MongoDB‬

‭Let's assume we have two collections:‬

‭‬ U
● ‭ ser‬‭→ Stores user details.‬
‭●‬ ‭Orders‬‭→ Stores orders placed by users.‬

‭User Collection (‬‭


User.java‬
‭)‬
‭java:‬
‭mport
i org.springframework.data.annotation.Id;‬
import
‭ org.springframework.data.mongodb.core.mapping.Document;‬
import
‭ org.springframework.data.mongodb.core.mapping.DBRef;‬
import
‭ java.util.List;‬

‭Document(collection = "users")‬
@
public class User {‬

‭Id‬
@
private String id;‬

private String name;‬


‭DBRef // Reference to the "orders" collection‬


@
private List<Order> orders;‬

// Getters and Setters‬



}‬

‭Order Collection (‬‭


Order.java‬
‭)‬
‭java:‬
‭mport org.springframework.data.annotation.Id;‬
i
import org.springframework.data.mongodb.core.mapping.Document;‬

‭Document(collection = "orders")‬
@
public class Order {‬

@Id‬

private String id;‬

‭rivate String productName;‬


p
private double price;‬

// Getters and Setters‬



}‬

‭3. How‬‭
@DBRef‬‭Works Internally?‬
‭●‬ T ‭ he‬‭ @DBRef‬‭annotation‬‭stores only the‬‭reference (ID)‬‭of the related document in‬
‭MongoDB.‬
‭●‬ ‭When retrieving a‬‭User‬‭, Spring Boot‬‭fetches related‬‭Order‬‭documents lazily‬‭(i.e.,‬
‭only when required).‬

‭Example of MongoDB Storage:‬

‭json:‬
‭/ User Collection‬
/
{‬

"_id": "user123",‬

"name": "Avinash",‬

"orders": [‬

‭{"$ref": "orders", "$id": "order456"},‬
‭{"$ref": "orders", "$id": "order789"}‬
]‬

}‬

‭/ Order Collection‬
/
{‬

"_id": "order456",‬

"productName": "Laptop",‬

"price": 800.0‬

}‬

{‬

"_id": "order789",‬

"productName": "Phone",‬

"price": 500.0‬

}‬

‭4. Querying Data with‬‭
@DBRef‬‭(Spring Boot Example)‬
‭Repository Interface (UserRepository.java)‬
‭java:‬
import org.springframework.data.mongodb.repository.MongoRepository;‬

‭ublic interface UserRepository extends MongoRepository<User,‬


p
String> {‬

User findByName(String name);‬

}‬

‭Saving Data (UserService.java)‬


‭java:‬
‭mport org.springframework.beans.factory.annotation.Autowired;‬
i
import org.springframework.stereotype.Service;‬

import java.util.Arrays;‬

‭Service‬
@
public class UserService {‬

‭Autowired‬
@
private UserRepository userRepository;‬

‭Autowired‬
@
private OrderRepository orderRepository;‬

public void createUserWithOrders() {‬



‭Order order1 = new Order();‬
‭order1.setProductName("Laptop");‬
‭order1.setPrice(800);‬

O‭rder order2 = new Order();‬


‭order2.setProductName("Phone");‬
‭order2.setPrice(500);‬

‭orderRepository.saveAll(Arrays.asList(order1, order2));‬

U‭ser user = new User();‬


‭user.setName("Avinash");‬
‭user.setOrders(Arrays.asList(order1, order2));‬
‭userRepository.save(user);‬
}‬

}‬

‭Fetching Data‬
‭java:‬
‭ser user = userRepository.findByName("Avinash");‬
U
System.out.println(user.getOrders()); // Fetches orders linked to‬

user‬

‭5. Alternative to‬‭


@DBRef‬‭: Manual Referencing‬
I‭nstead of using‬‭ @DBRef‬‭, we can manually store the related‬‭IDs‬‭and fetch data using‬
‭queries.‬
‭This is better for‬‭performance‬‭because MongoDB doesn't‬‭support real joins.‬

‭Example: Manual Referencing‬


‭java:‬
‭Document(collection = "users")‬
@
public class User {‬

‭Id‬
@
private String id;‬

private String name;‬


private List<String> orderIds; // Storing only order IDs‬


// Getters and Setters‬



}‬

‭●‬ ‭Fetching orders manually using repository queries‬‭instead of‬‭


@DBRef‬‭.‬
‭ his approach is‬‭faster‬‭than‬‭
‭●‬ T @DBRef‬‭because it avoids MongoDB's lookup‬
‭operations.‬
‭6. When to Use‬‭
@DBRef‬‭and When to Avoid?‬

‭ ‬‭Use‬‭
@DBRef‬‭when:‬

‭●‬ ‭You have‬‭small datasets‬‭and need‬‭automatic fetching‬‭of related documents.‬


‭ ‬‭Avoid‬‭
@DBRef‬‭when:‬

‭‬ Y
● ‭ ou have‬‭large collections‬‭→ Instead, use‬‭manual referencing‬‭(storing only IDs).‬
‭●‬ ‭You need‬‭high-performance queries‬‭.‬

‭Conclusion‬
‭●‬‭Indexed‬‭→ Improves query performance by creating an index.‬
@
‭‬ ‭
● @DBRef‬‭→ Establishes relationships between MongoDB collections (but can have‬
‭ erformance drawbacks).‬
p
‭ ‬ ‭Manual Referencing‬‭(storing only IDs) is often‬‭faster‬‭than‬‭
● @DBRef‬
‭.‬
‭MySQL:‬‭
@Index‬‭and Relationship Between Tables Using‬‭
@ManyToOne‬‭,‬
‭@OneToMany‬
I‭n‬‭Spring Boot with MySQL‬‭, we use‬‭JPA and Hibernate‬‭to manage relational databases.‬
‭Instead of‬‭
@DBRef‬‭(used in MongoDB), we define relationships‬‭using‬‭JPA annotations‬‭like‬
@ManyToOne‬‭and‬‭@OneToMany‬‭.‬

‭1.‬‭
@Index‬‭in MySQL‬
‭ ySQL uses indexes to‬‭optimize query performance‬‭. In‬‭Spring Data JPA‬‭, we can define‬
M
‭indexes using‬‭
@Index‬‭in the‬‭@Table‬‭annotation.‬

‭Example: Using‬‭
@Index‬‭in MySQL‬
‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "users", indexes = {‬

@Index(name = "idx_email", columnList = "email", unique = true)‬

})‬

public class User {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭Column(nullable = false, unique = true)‬


@
private String email;‬

private String name;‬


// Getters and Setters‬



}‬

‭Explanation:‬

‭●‬ @Table(indexes = { @Index(...) })‬‭→ Defines an‬‭index‬‭on the‬‭


‭ email‬
‭column.‬
‭●‬ unique = true‬‭→ Ensures that‬‭duplicate values‬‭are not inserted.‬

‭Generated SQL Query:‬

CREATE TABLE users (‬



id BIGINT AUTO_INCREMENT PRIMARY KEY,‬

email VARCHAR(255) NOT NULL UNIQUE,‬

name VARCHAR(255),‬

INDEX idx_email (email) -- Index on email column‬

);‬

‭2. Relationship Between Two Tables (‬‭


@ManyToOne‬‭,‬
@OneToMany‬‭)‬

‭In MySQL, we use‬‭foreign keys‬‭to establish relationships. In‬‭Spring Boot‬‭, we use‬
@ManyToOne‬‭and‬‭@OneToMany‬‭annotations.‬

‭Example: One-to-Many Relationship (User and Orders)‬

‭Let's define two tables:‬

‭●‬‭ser‬‭→ Stores user details.‬


U
‭‬ ‭
● Order‬‭→ Stores orders linked to a user.‬

‭User Entity (‬‭


User.java‬
‭)‬
‭java:‬
‭mport jakarta.persistence.*;‬
i
import java.util.List;‬

‭Entity‬
@
@Table(name = "users")‬

public class User {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

private String name;‬


‭OneToMany(mappedBy = "user", cascade = CascadeType.ALL)‬


@
private List<Order> orders;‬

// Getters and Setters‬

}‬

‭●‬‭OneToMany(mappedBy = "user")‬‭→ One user can have multiple orders.‬


@
‭‬ ‭
● cascade = CascadeType.ALL‬‭→ Ensures‬‭orders are deleted‬‭when a user is‬
‭deleted.‬

‭Order Entity (‬‭


Order.java‬‭)‬
‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "orders")‬

public class Order {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭rivate String productName;‬


p
private double price;‬

‭ManyToOne‬
@
@JoinColumn(name = "user_id") // Foreign Key‬

private User user;‬

// Getters and Setters‬



}‬

‭●‬‭ManyToOne‬‭→ Many orders can belong to one user.‬


@
‭‬ ‭
● @JoinColumn(name = "user_id")‬‭→ Creates a‬‭foreign key (user_id)‬‭in the‬
orders‬‭table.‬

‭3. Saving and Retrieving Data Using Spring Boot‬


‭JPA Repository for User‬
‭java:‬
import org.springframework.data.jpa.repository.JpaRepository;‬

public interface UserRepository extends JpaRepository<User, Long> {‬



User findByName(String name);‬

}‬

‭JPA Repository for Order‬


‭java:‬
import org.springframework.data.jpa.repository.JpaRepository;‬

‭ublic interface OrderRepository extends JpaRepository<Order, Long>‬


p
{‬

}‬

‭4. Saving a User with Orders (Service Layer)‬


‭java:‬
‭mport org.springframework.beans.factory.annotation.Autowired;‬
i
import org.springframework.stereotype.Service;‬

import java.util.Arrays;‬

‭Service‬
@
public class UserService {‬

‭Autowired‬
@
private UserRepository userRepository;‬

‭Autowired‬
@
private OrderRepository orderRepository;‬

public void createUserWithOrders() {‬



‭User user = new User();‬
‭user.setName("Avinash");‬

O‭rder order1 = new Order();‬


‭order1.setProductName("Laptop");‬
‭order1.setPrice(800);‬
‭order1.setUser(user);‬

‭Order order2 = new Order();‬


o‭rder2.setProductName("Phone");‬
‭order2.setPrice(500);‬
‭order2.setUser(user);‬

‭user.setOrders(Arrays.asList(order1, order2));‬

‭userRepository.save(user);‬
}‬

}‬

‭5. Fetching User with Orders‬


‭java:‬
‭ser user = userRepository.findByName("Avinash");‬
U
System.out.println(user.getOrders()); // Fetches all orders of user‬

‭6. Alternative: Using‬‭


@JoinTable‬‭for Many-to-Many‬
‭If a‬‭user can have multiple orders‬‭and an‬‭order can belong to multiple users‬‭, we use‬
@ManyToMany‬
‭ ‭.‬

‭java:‬
‭ManyToMany‬
@
@JoinTable(‬

name = "user_orders",‬

joinColumns = @JoinColumn(name = "user_id"),‬

inverseJoinColumns = @JoinColumn(name = "order_id")‬

)‬

private List<Order> orders;‬

‭This creates a‬‭separate table‬‭


user_orders‬‭to manage many-to-many relationships.‬

‭7. Generated SQL Queries in MySQL‬


‭After running the application, Hibernate generates:‬

CREATE TABLE users (‬



‭d BIGINT AUTO_INCREMENT PRIMARY KEY,‬
i
name VARCHAR(255)‬

);‬

CREATE TABLE orders (‬



id BIGINT AUTO_INCREMENT PRIMARY KEY,‬

product_name VARCHAR(255),‬

price DOUBLE,‬

user_id BIGINT,‬

FOREIGN KEY (user_id) REFERENCES users(id)‬

);‬

‭●‬ ‭Foreign Key (‬‭


user_id‬
‭)‬‭links‬‭
orders‬‭to‬‭
users‬‭.‬

‭8. When to Use Which Approach?‬


‭Approach‬ ‭When to Use‬

@Index‬
‭ ‭Improve search performance on frequently queried fields.‬

‭OneToMany‬‭and‬
@ I‭f one entity can have multiple related records (e.g., one user‬
@ManyToOne‬
‭ ‭has multiple orders).‬

@ManyToMany‬
‭ ‭ hen both entities can have multiple relationships (e.g., users‬
W
‭and courses).‬

‭Final Thoughts‬


‭ ‬‭
@Index‬‭improves MySQL query performance.‬
‭✅ Use‬‭JPA annotations‬‭(‬‭
@ManyToOne‬ ‭,‬‭
@OneToMany‬ ‭) to‬‭establish relationships.‬
‭✅ Avoid‬‭
@ManyToMany‬‭unless required, as it creates‬‭a‬‭separate join table‬‭.‬

‭ Spring Boot’s‬‭JPA repositories‬‭make CRUD operations easy.‬
‭ CID Principles and Implementing Transactions in‬
A
‭Spring Boot‬
‭1. Understanding ACID Principles‬

‭ACID is a set of properties ensuring reliable database transactions:‬

‭ACID Property‬ ‭Explanation‬

‭Atomicity‬ ‭ ransactions are‬‭all-or-nothing‬‭—if any part fails,‬‭the entire transaction‬


T
‭is rolled back.‬

‭Consistency‬ ‭The database remains in a‬‭valid state‬‭before and after‬‭the transaction.‬

‭Isolation‬ ‭Concurrent transactions do not interfere with each other.‬

‭Durability‬ ‭ nce committed, a transaction is‬‭permanently stored‬‭,‬‭even if the‬


O
‭system crashes.‬

‭2. Implementing Transactions in Spring Boot‬


‭ pring Boot provides‬‭transaction management‬‭using‬‭Spring Transactional‬
S
‭(‬‭
@Transactional‬ ‭)‬‭annotation.‬

‭Example: Bank Transfer‬

‭We will implement a scenario where a user transfers money from one account to another.‬

‭Entities: Account‬
‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "accounts")‬

public class Account {‬

‭Id‬
@
@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭rivate String accountHolder;‬


p
private double balance;‬

// Getters and Setters‬

}‬

‭Repository Layer (‬‭


AccountRepository‬‭)‬
‭java:‬
import org.springframework.data.jpa.repository.JpaRepository;‬

‭ublic interface AccountRepository extends JpaRepository<Account,‬


p
Long> {‬

Account findByAccountHolder(String accountHolder);‬

}‬

‭Service Layer (‬‭


BankService‬
‭)‬

‭We use‬‭
@Transactional‬‭to ensure‬‭atomicity‬‭in the money transfer.‬

‭java:‬
‭mport org.springframework.beans.factory.annotation.Autowired;‬
i
import org.springframework.stereotype.Service;‬

import org.springframework.transaction.annotation.Transactional;‬

‭Service‬
@
public class BankService {‬

‭Autowired‬
@
private AccountRepository accountRepository;‬

‭Transactional‬
@
public void transferMoney(String fromAccount, String toAccount,‬

double amount) {‬

‭Account sender =‬
accountRepository.findByAccountHolder(fromAccount);‬

‭Account receiver =‬
accountRepository.findByAccountHolder(toAccount);‬

‭if (sender.getBalance() < amount) {‬


‭throw new RuntimeException("Insufficient funds");‬
‭}‬
s‭ender.setBalance(sender.getBalance() - amount);‬
‭receiver.setBalance(receiver.getBalance() + amount);‬

a‭ccountRepository.save(sender);‬
‭accountRepository.save(receiver);‬
}‬

}‬

‭How This Ensures ACID Compliance‬

✅‬‭Atomicity‬‭→ If any operation fails, the entire transaction is‬‭rolled back‬‭.‬


✅‬‭Consistency‬‭→ Ensures account balances remain valid.‬

✅‬‭Isolation‬‭→ Other transactions do not see intermediate states.‬


✅‬‭Durability‬‭→ Once committed, changes persist even‬‭after a crash.‬



‭3. Handling Isolation Levels in Spring Boot‬


‭Spring supports‬‭different isolation levels‬‭using‬‭
@Transactional(isolation =‬
Isolation.LEVEL)‬

‭Isolation Level‬ ‭Behavior‬

‭solation.READ_UNCOMMI‬ ‭Allows uncommitted reads (dirty reads).‬


I
TTED‬

‭solation.READ_COMMITT‬ P
I ‭ revents dirty reads but allows non-repeatable reads.‬
ED‬
‭ ‭(Default for most databases)‬

‭solation.REPEATABLE_R‬ P
I ‭ revents dirty and non-repeatable reads, but allows‬
EAD‬
‭ ‭phantom reads.‬

Isolation.SERIALIZABLE‬ ‭Fully isolates transactions but reduces concurrency.‬


‭Example: Setting Isolation Level‬


‭java:‬
‭Transactional(isolation = Isolation.REPEATABLE_READ)‬
@
public void transferMoney(...) { ... }‬

‭4. Handling Transaction Propagation in Spring Boot‬
‭ pring provides‬‭different transaction propagation types‬‭to control how transactions‬
S
‭behave.‬

‭Propagation Type‬ ‭Behavior‬

REQUIRED‬
‭ ‭Uses the existing transaction or creates a new one.‬
‭(default)‬

REQUIRES_NEW‬
‭ ‭Suspends existing transaction and creates a new one.‬

MANDATORY‬
‭ ‭Requires an existing transaction, else throws an error.‬

SUPPORTS‬
‭ ‭ uns within a transaction if one exists, else runs‬
R
‭without.‬

NOT_SUPPORTED‬ ‭Runs outside any transaction.‬


NEVER‬
‭ ‭Throws an exception if a transaction exists.‬

NESTED‬
‭ ‭Creates a nested transaction within an existing one.‬

‭Example: Using‬‭
REQUIRES_NEW‬
‭java:‬
‭Transactional(propagation = Propagation.REQUIRES_NEW)‬
@
public void logTransaction(String details) {‬

// Logs transaction details separately‬

}‬

‭ his‬‭executes in a separate transaction‬‭, ensuring logging occurs‬‭even if the main‬


T
‭transaction fails‬‭.‬

‭5. Rollback Strategies in Spring Boot‬


‭By default,‬‭Spring rolls back only for unchecked exceptions (‬‭
RuntimeException‬
‭)‭.‬‬

‭Rollback Strategy‬ ‭Usage‬

‭Transactional(rollbackFor =‬
@ ‭ olls back for both checked and‬
R
Exception.class)‬
‭ ‭unchecked exceptions.‬

‭Transactional(noRollbackFor =‬
@ ‭ revents rollback for specific‬
P
NullPointerException.class)‬
‭ ‭exceptions.‬
‭Example: Rollback for Checked Exceptions‬
‭java:‬
‭Transactional(rollbackFor = Exception.class)‬
@
public void transferMoney(...) { ... }‬

‭6. Using Programmatic Transactions (Alternative to‬


@Transactional‬‭)‬

‭We can‬‭manually control transactions‬‭using‬‭
TransactionTemplate‬‭.‬

‭java:‬
‭mport org.springframework.transaction.support.TransactionTemplate;‬
i
import org.springframework.beans.factory.annotation.Autowired;‬

import org.springframework.stereotype.Service;‬

‭Service‬
@
public class BankService {‬

‭Autowired‬
@
private TransactionTemplate transactionTemplate;‬

‭ublic void transferMoney(String fromAccount, String toAccount,‬


p
double amount) {‬

‭transactionTemplate.executeWithoutResult(status -> {‬
‭Account sender =‬
accountRepository.findByAccountHolder(fromAccount);‬

‭Account receiver =‬
accountRepository.findByAccountHolder(toAccount);‬

s‭ender.setBalance(sender.getBalance() - amount);‬
‭receiver.setBalance(receiver.getBalance() + amount);‬

a‭ccountRepository.save(sender);‬
‭accountRepository.save(receiver);‬
‭});‬
}‬

}‬

‭7. Transaction Management in MySQL vs MongoDB‬
‭Feature‬ ‭MySQL (RDBMS)‬ ‭MongoDB (NoSQL)‬

‭Transactions‬ ‭ ully supports‬


F ‭ upports transactions from MongoDB‬
S
‭transactions‬ ‭4.0+‬

‭ CID‬
A ‭Fully ACID-compliant‬ ‭ CID-compliant in multi-document‬
A
‭Compliance‬ ‭transactions‬

‭Indexing‬ ‭ ses‬‭
U @Index‬‭for‬ ‭Uses‬‭
@Indexed‬‭annotation‬
‭optimization‬

‭For MongoDB Transactions:‬

‭java:‬
import org.springframework.transaction.annotation.Transactional;‬

‭Transactional‬
@
public void performMongoDBTransaction() {‬

// MongoDB operations inside a transaction‬

}‬

‭ . Best Practices for Transaction Management in Spring‬


8
‭Boot‬

‭ Use‬‭ @Transactional‬‭at the‬‭service layer‬‭, not in repositories or controllers.‬


‭ Choose the‬‭right isolation level‬‭to avoid performance‬‭bottlenecks.‬


‭ Handle‬‭checked exceptions carefully‬‭to prevent unwanted‬‭rollbacks.‬
‭ Use‬‭ Propagation.REQUIRES_NEW‬‭for‬‭logging transactions separately‬‭.‬

‭ ‬‭Optimize database indexes‬‭to speed up transaction‬‭queries.‬

‭Final Thoughts‬
‭‬ A
● ‭ CID properties ensure data integrity.‬
‭●‬ ‭Spring Boot simplifies transaction management with‬‭ @Transactional‬‭.‬
‭●‬ ‭Choosing the right isolation level and propagation type is critical for‬
‭performance.‬
‭1. Stateless Authentication (JWT)‬
‭ y default, Spring Security uses‬‭session-based authentication‬‭, but for stateless‬
B
‭authentication (like JWT), we‬‭disable sessions‬‭and‬‭rely on tokens.‬

‭Key Differences‬
‭Feature‬ ‭ ession-Based‬
S ‭Stateless Authentication (JWT)‬
‭Authentication‬

‭State‬ ‭Server maintains user session‬ ‭No session; authentication info is in JWT‬

‭Scalability‬ ‭Not ideal for distributed systems‬ ‭Ideal for microservices‬

‭Security‬ ‭Session hijacking possible‬ ‭JWT can be tamper-proof (signed)‬

‭2. Configuring Spring Security‬


‭ .1 WebSecurityConfigurerAdapter (Before Spring‬
2
‭Security 5.7)‬
‭ his class was used to define security configurations but is‬‭deprecated‬‭in Spring Security‬
T
‭5.7+.‬

‭Before (Using WebSecurityConfigurerAdapter)‬


‭java:‬
‭Configuration‬
@
@EnableWebSecurity‬

public class SecurityConfig extends WebSecurityConfigurerAdapter {‬

@Override‬

protected void configure(HttpSecurity http) throws Exception {‬

‭http.authorizeRequests()‬
‭.antMatchers("/hello").permitAll() // Allow access‬
without authentication‬

‭.anyRequest().authenticated() // All other requests‬
require authentication‬

‭.and()‬
‭.formLogin() // Enable form-based login‬
‭.and()‬
‭.logout(); // Enable logout‬
}‬

}‬

‭After (Spring Security 5.7+)‬

‭Now, we use a‬‭bean-based configuration‬‭:‬

‭java:‬
‭Configuration‬
@
@EnableWebSecurity‬

public class SecurityConfig {‬

‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity‬

http) throws Exception {‬

‭http.authorizeHttpRequests(auth -> auth‬
‭.requestMatchers("/hello").permitAll() // Public‬
endpoint‬

‭.anyRequest().authenticated() // Secure all other‬
endpoints‬

‭)‬
‭.formLogin(withDefaults()) // Enable form-based login‬
‭.logout(withDefaults()); // Enable logout‬
‭return http.build();‬
}‬

}‬

‭3. Key Security Methods‬


‭3.1 http.authorizeRequests()‬

‭Defines which endpoints are open and which require authentication.‬

‭3.2 antMatchers("/hello").permitAll()‬

‭Allows‬‭unauthenticated‬‭access to‬‭
/hello‬‭.‬

‭3.3 anyRequest().authenticated()‬

‭Requires authentication for‬‭all other endpoints‬‭.‬


‭3.4 formLogin()‬

‭Enables‬‭default Spring Security login form‬‭.‬

‭3.5 logout()‬

‭Provides a default logout URL (‬‭


/logout‬‭).‬

‭4. Session-Based Authentication‬


‭How Sessions Work in Spring Security‬
‭1. Session Creation‬

‭‬ A
● ‭ fter‬‭successful authentication‬‭, an HTTP‬‭session is‬‭created‬‭.‬
‭●‬ ‭Your authentication details are stored in this session.‬

‭2. Session Cookie (JSESSIONID)‬

‭‬ T
● ‭ he server sends a‬‭JSESSIONID‬‭cookie to the browser.‬
‭●‬ ‭The browser sends this‬‭cookie back‬‭in subsequent requests.‬

‭3. SecurityContext‬

‭●‬ U
‭ sing‬‭JSESSIONID‬‭, Spring Security‬‭retrieves authentication details‬‭for every‬
‭request.‬

‭4. Session Timeout‬

‭‬ S
● ‭ essions‬‭expire‬‭after a configured timeout (default is‬‭30 minutes‬‭).‬
‭●‬ ‭Users are‬‭logged out‬‭after inactivity.‬

‭5. Logout Mechanism‬

‭●‬ ‭When a user logs out, Spring Security:‬


‭○‬ ‭Invalidates the session‬‭.‬
‭○‬ ‭Deletes the JSESSIONID cookie‬‭.‬

‭6. Remember-Me Authentication‬

‭‬ A
● ‭ llows users to stay‬‭logged in even after session‬‭timeout‬‭.‬
‭●‬ ‭Uses a‬‭long-lived persistent cookie‬‭.‬
‭5. Stateless Authentication (JWT)‬
I‭n‬‭stateless authentication‬‭, we don’t use sessions. Instead, we rely on‬‭JSON Web Tokens‬
‭(JWT)‬‭.‬

‭How JWT Works‬


‭ .‬
1 ‭ ser logs in‬‭→ Server validates credentials and issues a JWT.‬
U
‭2.‬ ‭Client stores JWT‬‭(usually in localStorage or cookies).‬
‭3.‬ ‭JWT sent in headers‬‭(‬‭
Authorization: Bearer <JWT>‬‭).‬
‭4.‬ ‭Server verifies JWT‬‭on each request.‬

‭Spring Boot JWT Implementation‬


‭5.1 Maven Dependencies‬

‭Add dependencies:‬

‭xml:‬
<dependency>‬

<groupId>io.jsonwebtoken</groupId>‬

<artifactId>jjwt</artifactId>‬

<version>0.11.5</version>‬

</dependency>‬

‭5.2 JWT Utility Class‬


‭java:‬
‭mport
i io.jsonwebtoken.*;‬
import
‭ java.util.Date;‬
import
‭ io.jsonwebtoken.security.Keys;‬
import
‭ java.security.Key;‬

public class JwtUtil {‬



private static final String SECRET_KEY =‬

"mysecretkeymysecretkeymysecretkey";‬

private static final long EXPIRATION_TIME = 86400000; // 1 day‬

‭rivate static final Key key =‬


p
Keys.hmacShaKeyFor(SECRET_KEY.getBytes());‬

public static String generateToken(String username) {‬

‭return Jwts.builder()‬
‭.setSubject(username)‬
‭.setExpiration(new Date(System.currentTimeMillis() +‬
EXPIRATION_TIME))‬

‭.signWith(key, SignatureAlgorithm.HS256)‬
‭.compact();‬
}‬

public static String extractUsername(String token) {‬



‭return‬
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token‬

).getBody().getSubject();‬

}‬

}‬

‭5.3 JWT Authentication Filter‬


‭java:‬
‭mport jakarta.servlet.FilterChain;‬
i
import jakarta.servlet.ServletException;‬

import jakarta.servlet.http.HttpServletRequest;‬

import jakarta.servlet.http.HttpServletResponse;‬

import‬

org.springframework.security.core.context.SecurityContextHolder;‬

import org.springframework.web.filter.OncePerRequestFilter;‬

import java.io.IOException;‬

public class JwtAuthenticationFilter extends OncePerRequestFilter {‬


‭Override‬
@
protected void doFilterInternal(HttpServletRequest request,‬

HttpServletResponse response, FilterChain chain)‬

‭throws ServletException, IOException {‬

S‭tring header = request.getHeader("Authorization");‬


‭if (header == null || !header.startsWith("Bearer ")) {‬
‭chain.doFilter(request, response);‬
‭return;‬
‭}‬
S‭tring token = header.substring(7);‬
‭String username = JwtUtil.extractUsername(token);‬

‭if (username != null) {‬


‭SecurityContextHolder.getContext().setAuthentication(new‬
UsernamePasswordAuthenticationToken(username, null, new‬

ArrayList<>()));‬

‭}‬

‭chain.doFilter(request, response);‬
}‬

}‬

‭5.4 Register the Filter in Security Configuration‬


‭java:‬
‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity http)‬

throws Exception {‬

http.csrf().disable()‬

‭.authorizeHttpRequests(auth -> auth‬
‭.requestMatchers("/public").permitAll()‬
‭.anyRequest().authenticated()‬
‭)‬
‭.addFilterBefore(new JwtAuthenticationFilter(),‬
UsernamePasswordAuthenticationFilter.class);‬

return http.build();‬

}‬

‭6. Session Management in Spring Security‬


‭Spring Security provides‬‭three session management strategies‬‭:‬

‭Strategy‬ ‭Behavior‬

ALWAYS‬
‭ ‭Always creates a session (default)‬

‭F_REQUIR‬ ‭Creates a session only if needed‬


I
ED‬

NEVER‬
‭ ‭ pring Security‬‭never creates a‬
S
‭session‬

STATELESS‬ ‭No session, use JWT or API tokens‬


‭Configuring Stateless Authentication‬


‭java:‬
‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity http)‬

throws Exception {‬

http.sessionManagement()‬

‭.sessionCreationPolicy(SessionCreationPolicy.STATELESS);‬
return http.build();‬

}‬

‭Final Summary‬
‭Feature‬ ‭Session-Based Authentication‬ ‭ tateless (JWT)‬
S
‭Authentication‬

‭ ecurityContex‬ ‭Stores user details in session‬


S ‭Stores user details in token‬
‭t‬

‭Session‬ ‭Uses JSESSIONID‬ ‭No session, stateless‬

‭Storage‬ ‭Authentication stored in memory‬ ‭JWT stored in client-side‬

‭Scalability‬ ‭Not ideal for microservices‬ ‭Best for microservices‬

‭Best For‬ ‭Traditional web applications‬ ‭RESTful APIs‬

‭Role-Based Authentication in Spring Security‬

I‭n‬‭Role-Based Authentication‬‭, users are assigned‬‭roles‬‭(e.g.,‬‭


USER‬
‭,‬‭
ADMIN‬‭), and access‬
‭to resources is controlled based on these roles.‬
‭1. Adding Roles in Spring Security‬
‭We will:‬

‭ .‬ S
1 ‭ tore roles in the database‬‭.‬
‭2.‬ ‭Assign roles to users‬‭.‬
‭3.‬ ‭Restrict access‬‭based on roles.‬

‭2. Define User and Role Entities‬


‭We'll create‬‭two tables‬‭:‬‭
users‬‭and‬‭roles‬‭.‬

‭2.1 User Entity‬


‭java:‬
‭mport jakarta.persistence.*;‬
i
import java.util.Set;‬

‭Entity‬
@
@Table(name = "users")‬

public class User {‬

@Id‬

@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭rivate String username;‬


p
private String password;‬

‭ManyToMany(fetch = FetchType.EAGER)‬
@
@JoinTable(‬

‭name = "user_roles",‬
‭joinColumns = @JoinColumn(name = "user_id"),‬
‭inverseJoinColumns = @JoinColumn(name = "role_id")‬
)‬

private Set<Role> roles;‬

// Getters and Setters‬



}‬

‭2.2 Role Entity‬
‭java:‬
import jakarta.persistence.*;‬

‭Entity‬
@
@Table(name = "roles")‬

public class Role {‬

@Id‬

@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

private String name; // Example: ROLE_ADMIN, ROLE_USER‬


// Getters and Setters‬



}‬

‭3. User Repository and Service‬


‭3.1 UserRepository‬
‭java:‬
‭mport org.springframework.data.jpa.repository.JpaRepository;‬
i
import java.util.Optional;‬

public interface UserRepository extends JpaRepository<User, Long> {‬



Optional<User> findByUsername(String username);‬

}‬

‭3.2 UserDetailsService Implementation‬

‭Spring Security requires‬‭


UserDetailsService‬‭to load users.‬

‭java:‬
‭mport org.springframework.security.core.userdetails.*;‬
i
import‬

org.springframework.security.core.authority.SimpleGrantedAuthority;‬

import org.springframework.stereotype.Service;‬

import java.util.stream.Collectors;‬

@Service‬

‭ublic class CustomUserDetailsService implements UserDetailsService‬
p
{‬

private final UserRepository userRepository;‬

public CustomUserDetailsService(UserRepository userRepository) {‬



‭this.userRepository = userRepository;‬
}‬

‭Override‬
@
public UserDetails loadUserByUsername(String username) throws‬

UsernameNotFoundException {‬

‭User user = userRepository.findByUsername(username)‬
‭.orElseThrow(() -> new‬
UsernameNotFoundException("User not found"));‬

r‭eturn new‬
org.springframework.security.core.userdetails.User(‬

‭user.getUsername(),‬
‭user.getPassword(),‬
‭user.getRoles().stream()‬
‭.map(role -> new‬
SimpleGrantedAuthority(role.getName()))‬

‭.collect(Collectors.toSet())‬
‭);‬
}‬

}‬

‭4. Configure Security (Role-Based Authorization)‬


‭java:‬
‭mport org.springframework.context.annotation.Bean;‬
i
import‬

org.springframework.security.config.annotation.web.builders.HttpSecu‬

rity;‬

import‬

org.springframework.security.config.annotation.web.configuration.Ena‬

bleWebSecurity;‬

import‬

org.springframework.security.core.userdetails.UserDetailsService;‬

‭mport‬
i
org.springframework.security.provisioning.InMemoryUserDetailsManager‬

;‬

import‬

org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;‬

import org.springframework.security.web.SecurityFilterChain;‬

import static‬

org.springframework.security.config.Customizer.withDefaults;‬

‭EnableWebSecurity‬
@
public class SecurityConfig {‬

‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity‬

http) throws Exception {‬

‭http.csrf().disable()‬
‭.authorizeHttpRequests(auth -> auth‬
‭.requestMatchers("/admin/**").hasRole("ADMIN")‬
‭.requestMatchers("/user/**").hasRole("USER")‬
‭.anyRequest().authenticated()‬
‭)‬
‭.formLogin(withDefaults())‬
‭.logout(withDefaults());‬
‭return http.build();‬
}‬

‭Bean‬
@
public BCryptPasswordEncoder passwordEncoder() {‬

‭return new BCryptPasswordEncoder();‬
}‬

}‬

‭5. Role-Based Access Control (RBAC)‬


‭URL‬ ‭Role Required‬

‭admin/*‬ ‭ROLE_ADMIN‬
/
*‬

/user/**‬ ‭ROLE_USER‬

‭●‬ ‭asRole("ADMIN")‬‭→ Requires‬‭
h ROLE_ADMIN‬
‭‬ ‭
● hasRole("USER")‬‭→ Requires‬‭
ROLE_USER‬
‭●‬ ‭
anyRequest().authenticated()‬‭→ All other URLs require‬‭authentication‬

‭6. Testing with Users‬


‭To‬‭test authentication‬‭, insert users and roles into‬‭the database:‬

‭Example SQL Data‬


‭NSERT INTO users (id, username, password) VALUES (1, 'admin',‬
I
'$2a$10$xyz...'); -- Password: admin123‬

INSERT INTO roles (id, name) VALUES (1, 'ROLE_ADMIN'), (2,‬

'ROLE_USER');‬

INSERT INTO user_roles (user_id, role_id) VALUES (1, 1); -- Assign‬

ROLE_ADMIN to user‬

‭7. Accessing Endpoints‬


‭1. Login as ADMIN‬
‭OST /login‬
P
Content-Type: application/json‬

{‬

"username": "admin",‬

"password": "admin123"‬

}‬

‭→ Response:‬‭200 OK‬

‭2. Access Admin API‬


‭ET /admin/dashboard‬
G
Authorization: Bearer <JWT-TOKEN>‬


‭ ‬‭Allowed‬‭if user has‬‭
ROLE_ADMIN‬‭.‬

‭3. Access User API‬


‭ET /user/profile‬
G
Authorization: Bearer <JWT-TOKEN>‬


‭ ‬‭Allowed‬‭if user has‬‭
ROLE_USER‬‭.‬

‭8. Conclusion‬

‭ ‬‭Users & Roles stored in DB‬
‭✔‬‭Spring Security restricts endpoints based on roles‬
‭✔‬‭JWT or Session can be used for authentication‬
‭ omparison of‬‭
C application.properties‬ ‭,‬‭
application.yml‬ ‭,‬
‭Command-Line Properties, and Environment Variables in Spring Boot‬

‭ pring Boot provides multiple ways to configure properties. Let's compare these‬
S
‭approaches:‬

‭ .‬‭
1 application.properties‬‭(Traditional Key-Value‬
‭Format)‬
‭●‬ ‭Stored in:‬‭
src/main/resources/application.properties‬
‭●‬ ‭Format:‬‭
key=value‬

‭ xample:‬
E
‭properties:‬
‭erver.port=8081‬
s
spring.datasource.url=jdbc:mysql://localhost:3306/mydb‬

spring.datasource.username=root‬

spring.datasource.password=secret‬

‭●‬


‭ ‬‭Pros:‬

‭‬ S
● ‭ imple and widely used.‬
‭●‬ ‭Default format in Spring Boot.‬


‭ ‬‭Cons:‬

‭‬ N
● ‭ o hierarchy (difficult for nested properties).‬
‭●‬ ‭Can become lengthy for complex configurations.‬

‭2.‬‭
application.yml‬‭(YAML Format)‬
‭‬ S
● ‭ tored in:‬‭
src/main/resources/application.yml‬
‭●‬ ‭Format:‬‭Hierarchical (indentation-based)‬

‭ xample:‬
E
‭yaml:‬
server:‬

port: 8081‬

spring:‬

datasource:‬

url: jdbc:mysql://localhost:3306/mydb‬

username: root‬

password: secret‬

‭●‬


‭ ‬‭Pros:‬

‭‬ M
● ‭ ore readable (especially for complex configurations).‬
‭●‬ ‭Supports‬‭nested structures‬‭better than‬‭
.properties‬ ‭.‬


‭ ‬‭Cons:‬

‭‬ Y
● ‭ AML syntax is indentation-sensitive.‬
‭●‬ ‭Harder to debug if indentation errors occur.‬

‭3. Command-Line Properties (‬‭


--property=value‬‭)‬
‭●‬ ‭Format:‬‭Passed at runtime via the command line.‬

‭ xample (Run the application with custom properties):‬


E
‭sh:‬
‭ava -jar myapp.jar --server.port=9090‬
j
--spring.datasource.username=admin‬

‭●‬


‭ ‬‭Pros:‬

‭‬ O
● ‭ verrides‬‭both‬‭
application.properties‬‭and‬‭ application.yml‬‭.‬
‭●‬ ‭Useful for temporary changes without modifying files.‬


‭ ‬‭Cons:‬

‭‬ N
● ‭ ot persistent.‬
‭●‬ ‭Hard to manage for complex configurations.‬

‭4. Environment Variables‬


‭●‬ ‭Format:‬‭Set OS-level variables (‬‭
export‬
‭,‬‭
set‬‭, etc.).‬
‭ xample (Linux/Mac):‬
E
‭sh:‬
‭xport SERVER_PORT=9090‬
e
export SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/mydb‬

‭ xample (Windows CMD):‬
E
‭cmd:‬
‭et SERVER_PORT=9090‬
s
set SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/mydb‬

‭●‬


‭ ‬‭Pros:‬

‭‬ O
● ‭ verrides‬‭all other configurations (‬‭
properties‬‭,‬‭
YAML‬
‭, etc.).‬
‭●‬ ‭Best for‬‭production environments‬‭(e.g., AWS, Kubernetes).‬
‭●‬ ‭Secure (sensitive values like passwords don’t get committed in code).‬


‭ ‬‭Cons:‬

‭‬ H
● ‭ arder to track changes.‬
‭●‬ ‭Not project-specific (affects all applications running in the environment).‬

‭5. Precedence Order (Highest to Lowest)‬


1️⃣
‭ ‬‭Command-line arguments‬‭(‭
-‬ -server.port=9090‬‭)‬
‭2️⃣‬‭Environment variables‬‭(‬‭
export SERVER_PORT=9090‬ ‭)‬
‭3️⃣‬‭
application.properties‬‭or‬‭ application.yml‬
4️⃣
‭ ‬‭Default values‬‭(Spring Boot defaults)‬

🔹 Best Practices‬

‭ .‬
1 ‭ se‬‭
U application.yml‬‭for structured configuration.‬
‭2.‬ ‭Override with environment variables‬‭in production.‬
‭3.‬ ‭Use command-line arguments‬‭for temporary overrides.‬
‭4.‬ ‭Avoid hardcoding passwords‬‭in‬‭ properties‬‭or‬‭ yml‬‭(use environment variables‬
‭instead).‬

‭JUnit and Unit Testing in Spring Boot‬

‭ Unit is a popular testing framework for Java, and in Spring Boot, we use JUnit along with‬
J
‭Spring's testing support for unit and integration testing.‬
1️⃣ JUnit Basics‬

‭JUnit provides annotations and assertions for writing test cases.‬

‭Key JUnit Annotations‬


‭Annotation‬ ‭Description‬

@Test‬
‭ ‭Marks a method as a test case.‬

@BeforeEach‬
‭ ‭Runs before each test case (like setup).‬

@AfterEach‬
‭ ‭Runs after each test case (like cleanup).‬

@BeforeAll‬
‭ ‭ uns once before all test cases (static‬
R
‭method).‬

@AfterAll‬
‭ ‭Runs once after all test cases (static method).‬

‭DisplayName("Custom‬
@ ‭Provides a readable name for test cases.‬
Name")‬

@Disabled‬
‭ ‭Skips a test method.‬

‭Assertions in JUnit‬
‭Assertion‬ ‭Purpose‬

assertEquals(expected, actual)‬
‭ ‭Checks if values are equal.‬

assertNotEquals(val1, val2)‬
‭ ‭ hecks if values are not‬
C
‭equal.‬

assertTrue(condition)‬
‭ ‭Ensures condition is true.‬

assertFalse(condition)‬
‭ ‭Ensures condition is false.‬

assertNull(object)‬
‭ ‭Checks if an object is null.‬

assertNotNull(object)‬
‭ ‭Checks if an object is not null.‬

‭ssertThrows(Exception.class, () -> {‬
a ‭Ensures exception is thrown.‬
code })‬

‭Example: Simple JUnit Test‬


‭java:‬
‭mport org.junit.jupiter.api.Test;‬
i
import static org.junit.jupiter.api.Assertions.*;‬

class MathUtilsTest {‬

‭Test‬
@
void testAddition() {‬

‭int sum = 5 + 3;‬
‭assertEquals(8, sum, "Addition test failed");‬
}‬

‭Test‬
@
void testDivisionByZero() {‬

‭assertThrows(ArithmeticException.class, () -> {‬
‭int result = 10 / 0;‬
‭});‬
}‬

}‬

2️⃣ Unit Testing a Spring Boot Application‬



‭ pring Boot provides the‬‭
S spring-boot-starter-test‬‭dependency, which includes‬
‭JUnit, Mockito, and other testing utilities.‬

‭Add Dependencies (if not already present)‬

‭Add the following dependency in‬‭


pom.xml‬
‭:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-test</artifactId>‬

<scope>test</scope>‬

</dependency>‬

3️⃣ Writing Unit Tests in Spring Boot‬



‭Unit Testing a Service Layer (Without Spring Context)‬

‭We can use‬‭Mockito‬‭to mock dependencies.‬


‭Example: Service Layer Testing‬
‭java:‬
‭mport static org.mockito.Mockito.*;‬
i
import static org.junit.jupiter.api.Assertions.*;‬

‭mport
i org.junit.jupiter.api.BeforeEach;‬
import
‭ org.junit.jupiter.api.Test;‬
import
‭ org.mockito.InjectMocks;‬
import
‭ org.mockito.Mock;‬
import
‭ org.mockito.MockitoAnnotations;‬

‭mport com.example.service.UserService;‬
i
import com.example.repository.UserRepository;‬

import com.example.model.User;‬

import java.util.Optional;‬

class UserServiceTest {‬

‭Mock‬
@
private UserRepository userRepository;‬

‭InjectMocks‬
@
private UserService userService;‬

‭BeforeEach‬
@
void setUp() {‬

‭MockitoAnnotations.openMocks(this);‬
}‬

‭Test‬
@
void testFindUserById() {‬

‭User user = new User(1L, "Avinash");‬

when(userRepository.findById(1L)).thenReturn(Optional.of(user));‬

U‭ser foundUser = userService.findUserById(1L);‬


‭assertNotNull(foundUser);‬
‭assertEquals("Avinash", foundUser.getName());‬
}‬

}‬


‭ ‬‭Key Takeaways‬‭:‬

‭●‬ ‭Mock‬‭is used to create mock objects.‬


@
‭‬ ‭
● @InjectMocks‬‭injects mocks into the tested class.‬
‭●‬ ‭Mockito's‬‭when().thenReturn()‬‭is used to define behavior.‬

4️⃣ Unit Testing a Controller (Spring Boot Web Layer)‬



‭We use‬‭MockMvc‬‭for testing controllers without running the full application.‬

‭Example: Controller Testing‬


‭java:‬
‭mport static‬
i
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.‬

get;‬

import static‬

org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;‬

‭mport org.junit.jupiter.api.Test;‬
i
import org.springframework.beans.factory.annotation.Autowired;‬

import‬

org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;‬

import org.springframework.test.web.servlet.MockMvc;‬

‭WebMvcTest(UserController.class)‬
@
class UserControllerTest {‬

‭Autowired‬
@
private MockMvc mockMvc;‬

‭Test‬
@
void testGetUser() throws Exception {‬

‭mockMvc.perform(get("/users/1"))‬
‭.andExpect(status().isOk())‬
‭.andExpect(jsonPath("$.name").value("Avinash"));‬
}‬

}‬


‭ ‬‭Key Takeaways‬‭:‬

‭‬ ‭
● @WebMvcTest‬‭loads only the web layer (lightweight).‬
‭●‬ M‭ ockMvc‬‭allows us to test REST APIs.‬
‭●‬ ‭
jsonPath("$.name")‬‭checks JSON response fields.‬

5️⃣ Integration Testing (Spring Context)‬



‭Integration tests load the complete application context.‬

‭Example: Integration Test‬


‭java:‬
‭mport org.junit.jupiter.api.Test;‬
i
import org.springframework.boot.test.context.SpringBootTest;‬

import static org.assertj.core.api.Assertions.assertThat;‬

‭SpringBootTest‬
@
class ApplicationTests {‬

‭Test‬
@
void contextLoads() {‬

‭assertThat(true).isTrue();‬
}‬

}‬


‭ ‬‭
@SpringBootTest‬‭loads the whole application for testing.‬

6️⃣ Best Practices for Unit Testing in Spring Boot‬



‭ .‬
1 ‭ est small units‬‭(service methods, controllers).‬
T
‭2.‬ ‭Mock dependencies‬‭(repositories, APIs).‬
‭3.‬ ‭Use‬‭ MockMvc‬‭for controller tests‬‭instead of full Spring context.‬
‭4.‬ ‭Keep tests independent‬‭(no reliance on shared state).‬
‭5.‬ ‭Use meaningful assertions‬‭(check expected results clearly).‬
‭6.‬ ‭Follow naming conventions‬‭(‭ t‬ estMethodName_shouldDoSomething()‬‭).‬
‭Mockito: Usage and Annotations‬

‭ ockito is a powerful mocking framework used in unit testing to simulate dependencies. It‬
M
‭helps in testing components independently by replacing real dependencies with mock‬
‭objects.‬

1️⃣ Why Use Mockito?‬



‭‬ A
● ‭ voids testing with real databases or APIs.‬
‭●‬ ‭Makes unit tests‬‭faster‬‭and‬‭more reliable‬‭.‬
‭●‬ ‭Allows verifying‬‭method calls‬‭and‬‭interactions‬‭.‬

2️⃣ Mockito Dependencies (Spring Boot)‬



‭Ensure‬‭
spring-boot-starter-test‬‭(which includes Mockito) is in your‬‭
pom.xml‬‭:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-test</artifactId>‬

<scope>test</scope>‬

</dependency>‬

3️⃣ Mockito Annotations‬



‭Annotation‬ ‭Description‬

@Mock‬
‭ ‭Creates a mock object.‬

@InjectMocks‬
‭ I‭njects mock dependencies into the class under‬
‭test.‬

@Spy‬
‭ ‭Creates a spy (partial mock).‬

@Captor‬
‭ ‭Captures method arguments for verification.‬

‭ockitoAnnotations.openMocks(‬ ‭Initializes annotated mocks.‬


M
this)‬

4️⃣ Basic Mockito Example‬

‭Mocking a‬‭
UserRepository‬‭dependency in‬‭
UserService‬
‭:‬

‭java:‬
‭mport static org.mockito.Mockito.*;‬
i
import static org.junit.jupiter.api.Assertions.*;‬

‭mport
i org.junit.jupiter.api.BeforeEach;‬
import
‭ org.junit.jupiter.api.Test;‬
import
‭ org.mockito.InjectMocks;‬
import
‭ org.mockito.Mock;‬
import
‭ org.mockito.MockitoAnnotations;‬
import
‭ java.util.Optional;‬

class UserServiceTest {‬

‭Mock‬
@
private UserRepository userRepository;‬

‭InjectMocks‬
@
private UserService userService;‬

‭BeforeEach‬
@
void setUp() {‬

‭MockitoAnnotations.openMocks(this);‬
}‬

‭Test‬
@
void testFindUserById() {‬

‭User user = new User(1L, "Avinash");‬

when(userRepository.findById(1L)).thenReturn(Optional.of(user));‬

U‭ser foundUser = userService.findUserById(1L);‬


‭assertNotNull(foundUser);‬
‭assertEquals("Avinash", foundUser.getName());‬
}‬

}‬


‭ ‬‭Key Takeaways‬‭:‬

‭●‬ ‭Mock‬‭creates a mock‬‭UserRepository‬‭.‬


@
‭‬ ‭
● @InjectMocks‬‭injects‬‭userRepository‬‭into‬‭
UserService‬‭.‬
‭●‬ ‭
MockitoAnnotations.openMocks(this)‬‭initializes mocks.‬

5️⃣ Stubbing Methods with‬‭when().thenReturn()‬



‭Mockito allows‬‭stubbing methods‬‭to return predefined values.‬

‭Example: Stubbing a Repository Method‬


‭java:‬
‭hen(userRepository.findById(1L)).thenReturn(Optional.of(new‬
w
User(1L, "Avinash")));‬

👉
‭ ‬‭Returns a‬‭
User‬‭object when‬‭findById(1L)‬‭is called.‬

6️⃣ Verifying Method Calls with‬‭verify()‬



‭We can check if a method was called, how many times, and with what arguments.‬

‭Example: Verifying Method Calls‬


‭java:‬
‭serService.findUserById(1L);‬
u
verify(userRepository, times(1)).findById(1L);‬

‭Verification‬ ‭Explanation‬

‭erify(mock,‬
v ‭Ensures method was called once.‬
times(1))‬

verify(mock, never())‬ ‭Ensures method was never called.‬


‭erify(mock,‬
v ‭ nsures method was called at least‬
E
atLeast(2))‬
‭ ‭twice.‬
7️⃣ Throwing Exceptions with‬‭thenThrow()‬

‭Example: Handling Exception Scenarios‬


‭java:‬
‭hen(userRepository.findById(999L)).thenThrow(new‬
w
RuntimeException("User not found"));‬

‭ssertThrows(RuntimeException.class, () ->‬
a
userService.findUserById(999L));‬

👉
‭ ‬‭Ensures an exception is thrown for invalid user IDs.‬

8️⃣ Using‬‭@Spy‬‭for Partial Mocks‬



‭A‬‭Spy‬‭is a real object but allows method stubbing.‬

‭Example: Using‬‭
@Spy‬
‭java:‬
‭Spy‬
@
private UserService userService;‬

‭Test‬
@
void testSpy() {‬

doReturn("Mocked Name").when(userService).getUserName();‬

assertEquals("Mocked Name", userService.getUserName());‬

}‬

👉 Unlike‬‭@Mock‬‭,‬‭@Spy‬‭retains real method behavior‬‭unless stubbed.‬


9️⃣ Capturing Arguments with‬‭@Captor‬



‭Mockito’s‬‭
@Captor‬‭captures arguments passed to mocked methods.‬

‭Example: Capturing Arguments‬


‭java:‬
@Captor‬

ArgumentCaptor<Long> idCaptor;‬

‭Test‬
@
void testArgumentCaptor() {‬

userService.findUserById(1L);‬

verify(userRepository).findById(idCaptor.capture());‬

assertEquals(1L, idCaptor.getValue());‬

}‬

👉
‭ ‬‭Ensures the correct argument was passed.‬

🔟 Mocking Static Methods (Mockito 3.4+)‬



‭Mockito can now mock‬‭static methods‬‭using‬‭
mockStatic()‬‭.‬

‭Example: Mocking Static Methods‬


‭java:‬
try (MockedStatic<Utils> mockedStatic = mockStatic(Utils.class)) {‬

mockedStatic.when(Utils::generateId).thenReturn(100L);‬

assertEquals(100L, Utils.generateId());‬

}‬

👉
‭ ‬‭Temporarily overrides static method behavior.‬

1️⃣1️⃣ Best Practices‬





‭ ‬‭Mock only external dependencies‬‭, not the class under test.‬
‭ ‬‭Use‬‭
@InjectMocks‬‭to inject dependencies automatically.‬

‭ ‬‭Avoid‬‭@Mock‬‭when real objects are needed‬‭(use‬‭ @Spy‬‭).‬
‭✅‬‭Verify interactions when needed‬‭, not always.‬
‭✅‬‭Use meaningful assertions‬‭to validate behavior.‬
‭Spring Profiles: Managing Prod and Test Environments‬

‭ pring Profiles allow us to define different configurations for different environments like‬
S
‭development (dev), testing (test), and production (prod)‬‭. We can switch between these‬
‭profiles easily.‬

1️⃣ Enabling Spring Profiles‬



‭Spring Boot provides multiple ways to define profiles:‬

‭ .‬ a
1 ‭ pplication.properties / application.yml‬
‭2.‬ ‭Command-line arguments‬
‭3.‬ ‭Environment variables‬

2️⃣ Creating Profile-Specific Properties‬



‭We can create different property files for each environment:‬

‭application-dev.properties‬
‭properties:‬
‭erver.port=8081‬
s
spring.datasource.url=jdbc:mysql://localhost:3306/devdb‬

spring.datasource.username=dev_user‬

spring.datasource.password=dev_pass‬

‭application-test.properties‬
‭properties:‬
‭erver.port=8082‬
s
spring.datasource.url=jdbc:mysql://localhost:3306/testdb‬

spring.datasource.username=test_user‬

spring.datasource.password=test_pass‬

‭application-prod.properties‬
‭properties:‬
‭erver.port=8080‬
s
spring.datasource.url=jdbc:mysql://prod-db-server:3306/proddb‬

spring.datasource.username=prod_user‬

spring.datasource.password=prod_pass‬

3️⃣ Activating a Profile‬

‭We can activate a profile in different ways:‬

‭A. In‬‭
application.properties‬
‭properties:‬
spring.profiles.active=dev‬

‭B. Using Command-Line Arguments‬


‭sh:‬
java -jar myapp.jar --spring.profiles.active=prod‬

‭C. Using Environment Variables‬


‭sh:‬
export SPRING_PROFILES_ACTIVE=prod‬

4️⃣ Using‬‭@Profile‬‭Annotation in Beans‬



‭ e can use the‬‭
W @Profile‬‭annotation to define beans that should be created only for a‬
‭specific profile.‬

‭java:‬
‭Component‬
@
@Profile("dev")‬

public class DevConfig {‬

public DevConfig() {‬

‭System.out.println("Dev Configuration Loaded");‬
}‬

}‬

‭java:‬
‭Component‬
@
@Profile("prod")‬

public class ProdConfig {‬

public ProdConfig() {‬

‭System.out.println("Prod Configuration Loaded");‬
}‬

}‬

👉
‭ When we run the app with‬‭
spring.profiles.active=prod‬‭, only the‬‭
ProdConfig‬
‭bean will be loaded.‬

5️⃣ Using‬‭@Value‬‭to Inject Environment-Specific Values‬



‭We can inject property values based on the active profile.‬

‭java:‬
‭Value("${spring.datasource.url}")‬
@
private String dbUrl;‬

6️⃣ Switching Between MySQL and H2 for Testing‬



‭ or‬‭production‬‭, we may use‬‭MySQL‬‭, but for‬‭testing‬‭, we may use‬‭H2 (in-memory‬
F
‭database)‬‭.‬

‭application-test.properties‬
‭properties:‬
‭pring.datasource.url=jdbc:h2:mem:testdb‬
s
spring.datasource.driverClassName=org.h2.Driver‬

spring.datasource.username=sa‬

spring.datasource.password=‬

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect‬

👉
‭ ‬‭This allows running tests without an actual database.‬

7️⃣ Best Practices‬



✅ Use‬‭profiles‬‭to separate configurations for different environments.‬
✅ Use‬‭H2‬‭or an embedded database for‬‭unit testing‬‭.‬

✅ Avoid hardcoding‬‭sensitive credentials‬‭in properties (use environment variables).‬


✅ Use‬‭Spring Cloud Config‬‭for centralized configuration management in microservices.‬




‭Logging in Spring Boot‬

‭ pring Boot provides built-in support for‬‭Logback‬‭,‬‭Log4j2‬‭, and‬‭Java Util Logging (JUL)‬‭.‬
S
‭By default,‬‭Logback‬‭is used, but we can configure‬‭different logging frameworks based on‬
‭our needs.‬

1️⃣ Logging Levels‬



‭Logging levels help classify logs based on severity:‬

‭‬
● ‭ RACE‬‭– Very detailed information, mostly for debugging.‬
T
‭●‬ ‭DEBUG‬‭– Detailed information for debugging.‬
‭●‬ ‭INFO‬‭– General application-level events.‬
‭●‬ ‭WARN‬‭– Potential issues or non-critical failures.‬
‭●‬ ‭ERROR‬‭– Serious problems that may prevent execution.‬

‭Example of logging levels in code:‬

‭java:‬
‭mport org.slf4j.Logger;‬
i
import org.slf4j.LoggerFactory;‬

import org.springframework.stereotype.Service;‬

‭Service‬
@
public class LoggingService {‬

private static final Logger logger =‬

LoggerFactory.getLogger(LoggingService.class);‬

public void performLogging() {‬



‭logger.trace("This is a TRACE log");‬
‭logger.debug("This is a DEBUG log");‬
‭logger.info("This is an INFO log");‬
‭logger.warn("This is a WARN log");‬
‭logger.error("This is an ERROR log");‬
}‬

}‬

2️⃣ Configuring Logging in‬‭application.properties‬



‭By default, Spring Boot logs to the‬‭console‬‭at the‬‭
INFO‬‭level. We can change this in‬
application.properties‬‭:‬

‭properties:‬
‭ Set the logging level‬
#
logging.level.root=WARN‬

logging.level.com.example=DEBUG‬

‭This means:‬

‭●‬ ‭Logs from the‬‭root‬‭(all packages) will only show‬‭


WARN‬‭and above.‬
‭●‬ ‭Logs from‬‭com.example‬‭will show‬‭
DEBUG‬‭and above.‬

3️⃣ Logging to a File‬



‭To log to a file, update‬‭
application.properties‬‭:‬

‭properties:‬
‭ Log to a file‬
#
logging.file.name=logs/app.log‬

logging.file.path=logs‬

‭ Limit file size and rolling policy‬


#
logging.logback.rollingpolicy.max-file-size=10MB‬

logging.logback.rollingpolicy.max-history=7‬

‭ his logs messages to‬‭


T logs/app.log‬
‭, keeping a maximum of‬‭7 files‬‭with a maximum‬
‭10MB‬‭size each.‬

4️⃣ Configuring Logback with XML (‬‭logback.xml‬‭)‬



‭For more advanced configurations, create‬‭
src/main/resources/logback.xml‬‭:‬

‭xml:‬
<configuration>‬

‭!-- Define log levels -->‬


<
<logger name="com.example" level="DEBUG"/>‬

<logger name="org.springframework" level="INFO"/>‬

‭!-- Console Appender -->‬


<
<appender name="CONSOLE"‬

class="ch.qos.logback.core.ConsoleAppender">‬

‭<encoder>‬
‭<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level‬
%logger{36} - %msg%n</pattern>‬

‭</encoder>‬
</appender>‬

‭!-- File Appender -->‬


<
<appender name="FILE"‬

class="ch.qos.logback.core.rolling.RollingFileAppender">‬

‭<file>logs/app.log</file>‬
‭<rollingPolicy‬
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">‬

<fileNamePattern>logs/app-%d{yyyy-MM-dd}.log</fileNamePattern>‬

‭<maxHistory>7</maxHistory>‬
‭</rollingPolicy>‬
‭<encoder>‬
‭<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level‬
%logger{36} - %msg%n</pattern>‬

‭</encoder>‬
</appender>‬

‭!-- Root Logger -->‬


<
<root level="INFO">‬

‭<appender-ref ref="CONSOLE"/>‬
‭<appender-ref ref="FILE"/>‬
</root>‬

</configuration>‬

‭‬ L
● ‭ ogs are printed to both‬‭console‬‭and‬‭file‬‭(‬‭
logs/app.log‬‭).‬
‭●‬ ‭Log files are‬‭rotated daily‬‭and stored for‬‭7 days‬‭.‬
5️⃣ Switching to Log4j2‬

‭To use Log4j2 instead of Logback:‬

‭1.‬ ‭Add the dependency:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-log4j2</artifactId>‬

<scope>runtime</scope>‬

</dependency>‬

‭2.‬ ‭Create‬‭
src/main/resources/log4j2.xml‬
‭:‬

‭xml:‬
<Configuration status="WARN">‬

<Appenders>‬

‭<Console name="Console" target="SYSTEM_OUT">‬
‭<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t]‬
%-5level %c{1} - %msg%n"/>‬

‭</Console>‬
‭<RollingFile name="FileLogger" fileName="logs/app.log"‬
‭filePattern="logs/app-%d{yyyy-MM-dd}.log">‬
‭<PatternLayout>‬
‭<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %c{1}‬
- %msg%n</Pattern>‬

‭</PatternLayout>‬
‭<Policies>‬
‭<TimeBasedTriggeringPolicy />‬
‭</Policies>‬
‭</RollingFile>‬
</Appenders>‬

<Loggers>‬

‭<Root level="INFO">‬
‭<AppenderRef ref="Console"/>‬
‭<AppenderRef ref="FileLogger"/>‬
‭</Root>‬
</Loggers>‬

</Configuration>‬

6️⃣ Using Java Util Logging (JUL)‬

‭JUL is the default logging framework in Java but is rarely used in Spring Boot.‬

‭If needed, configure‬‭


logging.properties‬‭:‬

‭properties:‬
‭andlers=java.util.logging.ConsoleHandler‬
h
.level=INFO‬

‭ava.util.logging.ConsoleHandler.level=FINE‬
j
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleF‬

ormatter‬

‭This configuration logs‬‭


INFO‬‭messages to the console.‬

7️⃣ Best Practices‬





‭ Use‬‭INFO‬‭level for production and‬‭DEBUG‬‭for development.‬


‭ Store logs in‬‭files‬‭instead of just the console‬‭for troubleshooting.‬


‭ Use‬‭log rotation‬‭to avoid excessive log file sizes.‬


‭ ‬‭Don't log sensitive information‬‭like passwords.‬
‭ Use‬‭MDC (Mapped Diagnostic Context)‬‭to track logs for each request in a distributed‬
‭system.‬
‭SonarQube, SonarLint, and SonarCloud‬

‭ onarQube, SonarLint, and SonarCloud are tools used for‬‭static code analysis‬‭to improve‬
S
‭code quality‬‭,‬‭security‬‭, and‬‭maintainability‬‭in software development.‬

1️⃣ SonarQube‬

‭SonarQube is a‬‭self-hosted‬‭code quality analysis tool that scans code for:‬

‭‬
● ‭ ugs‬
B
‭●‬ ‭Security vulnerabilities‬
‭●‬ ‭Code smells (bad coding practices)‬
‭●‬ ‭Code coverage‬
‭●‬ ‭Duplications‬

‭It supports‬‭Java, Python, JavaScript, C++, and more‬‭.‬

‭How SonarQube Works‬

‭ .‬
1 ‭ evelopers commit code‬‭to a repository.‬
D
‭2.‬ ‭Sonar Scanner‬‭analyzes the code.‬
‭3.‬ ‭SonarQube Server‬‭processes the analysis results.‬
‭4.‬ ‭Developers review and fix issues‬‭via the SonarQube‬‭Dashboard.‬

‭How to Set Up SonarQube for Spring Boot (Self-Hosted)‬

‭1.‬ ‭Download and Install SonarQube‬


‭○‬ ‭Download from SonarQube‬

‭ xtract and start the server:‬


E
‭sh:‬
./sonarqube/bin/linux-x86-64/sonar.sh start‬

‭‬

‭○‬ ‭Access‬‭http://localhost:9000‬‭in a browser.‬
‭2.‬ ‭Add SonarQube Plugin to Spring Boot Project (‬‭ pom.xml‬‭)‬

‭xml:‬
<properties>‬

<sonar.projectKey>your-project-key</sonar.projectKey>‬

</properties>‬

<build>‬

<plugins>‬

‭<plugin>‬
‭<groupId>org.sonarsource.scanner.maven</groupId>‬
<‭artifactId>sonar-maven-plugin</artifactId>‬
‭<version>3.9.1.2184</version>‬
‭</plugin>‬
</plugins>‬

</build>‬

‭ un the Analysis‬
R
‭sh:‬
mvn clean verify sonar:sonar -Dsonar.host.url=http://localhost:9000‬

‭3.‬
‭○‬ ‭Results are available in‬‭SonarQube Dashboard‬‭.‬

2️⃣ SonarLint (IDE Plugin)‬



‭ onarLint is a‬‭real-time linting tool‬‭that integrates with IDEs like‬‭IntelliJ IDEA, Eclipse,‬
S
‭and VS Code‬‭.‬

‭Key Features‬

✔️ Detects issues‬‭as you code‬‭(real-time feedback).‬


✔️ Works‬‭offline‬‭without a SonarQube server.‬

✔️ Helps maintain clean and secure code.‬



‭How to Use SonarLint in IntelliJ IDEA‬

‭ .‬ I‭nstall SonarLint Plugin‬‭from the IntelliJ Plugin Marketplace.‬


1
‭2.‬ ‭Enable SonarLint‬‭in IntelliJ settings.‬
‭3.‬ ‭Analyze Code:‬
‭○‬ ‭Right-click on the project →‬‭SonarLint → Analyze‬‭.‬
‭○‬ ‭Fix suggested issues.‬

🔹
‭ ‬‭SonarLint vs. SonarQube‬

‭Feature‬ ‭SonarLint‬ ‭SonarQube‬

‭Scope‬ ‭Individual files in IDE‬ ‭Entire project in CI/CD‬

‭Works Offline‬ ✅ Yes‬


‭ ❌ No (requires a server)‬

‭ eal-time‬
R ‭✅ Yes‬ ‭❌ No (post-commit analysis)‬
‭Analysis‬

‭CI/CD Integration‬ ❌
‭ No‬ ✅
‭ Yes‬
3️⃣ SonarCloud‬

✔️
‭ onarCloud is‬‭SonarQube’s cloud-based version‬‭. It provides:‬
S

✔️
‭ ‬‭Automatic code analysis‬‭in cloud-based CI/CD pipelines.‬

✔️
‭ ‬‭Supports GitHub, Bitbucket, GitLab, and Azure DevOps.‬

✔️
‭ ‬‭No need to install and manage servers‬‭(unlike SonarQube).‬
‭ ‬‭Free for open-source projects‬‭but requires a paid‬‭plan for private projects.‬

‭How to Integrate SonarCloud with GitHub‬

‭ .‬ C
1 ‭ reate an account‬‭at‬‭SonarCloud.io‬‭.‬
‭2.‬ ‭Link your GitHub repository.‬
‭3.‬ ‭Add GitHub Actions workflow (‬‭ .github/workflows/sonarcloud.yml‬
‭):‬

‭yaml:‬
name: SonarCloud Analysis‬

on:‬

push:‬

branches:‬

- main‬

jobs:‬

sonar:‬

runs-on: ubuntu-latest‬

steps:‬

- uses: actions/checkout@v3‬

- name: Set up JDK 17‬

‭uses: actions/setup-java@v3‬
‭with:‬
‭distribution: 'temurin'‬
‭java-version: '17'‬
- name: Cache SonarCloud Packages‬

‭uses: actions/cache@v3‬
‭with:‬
‭path: ~/.sonar/cache‬
‭key: ${{ runner.os }}-sonar‬
- name: Run SonarCloud Analysis‬

‭env:‬
‭SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}‬
r‭un: mvn clean verify sonar:sonar‬
-Dsonar.projectKey=your_project_key‬

-Dsonar.organization=your_organization‬

‭4.‬ ‭Push changes‬‭, and SonarCloud will analyze your code.‬

4️⃣
‭ Comparison: SonarQube vs. SonarLint vs.‬
‭SonarCloud‬
‭Feature‬ ‭SonarQube‬ ‭SonarLint‬ ‭SonarCloud‬
‭(Self-hosted)‬ ‭(IDE)‬ ‭(Cloud-based)‬

‭Setup‬ ‭Requires installation‬ ‭ asy IDE‬


E ‭Cloud-based, no setup‬
‭plugin‬

‭Scope‬ ‭Entire project‬ ‭Single file‬ ‭Entire project‬

‭CI/CD Integration‬ ✅ Yes‬


‭ ❌ No‬
‭ ✅ Yes‬

‭ eal-time‬
R ‭❌ No‬ ‭✅ Yes‬ ‭❌ No‬
‭Feedback‬

‭ erver‬
S ✅
‭ Yes‬ ❌
‭ No‬ ❌
‭ No (managed by‬
‭Maintenance‬ ‭Sonar)‬

‭Cost‬ ‭ ree (Community‬


F ‭Free‬ ‭Free for open-source‬
‭Edition)‬

‭Best Practices for Using SonarQube, SonarLint, and SonarCloud‬

✅‬‭Use SonarLint‬‭for‬‭real-time feedback‬‭during development.‬


✅‬‭Use SonarQube/SonarCloud‬‭in CI/CD to analyze‬‭full‬‭projects‬‭.‬

✅‬‭Fix critical bugs & security issues‬‭before merging‬‭code.‬


✅‬‭Regularly check Sonar Dashboards‬‭to track code quality‬‭trends.‬




‭External API Integration in Spring Boot (GET & POST)‬

I‭ntegrating external APIs in a Spring Boot application involves making HTTP requests to‬

✔️
‭external services. This can be done using:‬
‭ ‬‭
RestTemplate‬‭(Deprecated, but still used in older projects)‬
✔️
‭ ‬‭
WebClient‬‭(Recommended for modern applications)‬

1️⃣ GET Request - Fetch Data from an External API‬


‭Using‬‭
RestTemplate‬‭(Traditional Approach)‬
‭java:‬
‭mport org.springframework.stereotype.Service;‬
i
import org.springframework.web.client.RestTemplate;‬

import org.springframework.http.ResponseEntity;‬

‭Service‬
@
public class ExternalApiService {‬

private final RestTemplate restTemplate = new RestTemplate();‬

public String fetchData() {‬



‭String url = "https://jsonplaceholder.typicode.com/posts/1";‬
‭ResponseEntity<String> response =‬
restTemplate.getForEntity(url, String.class);‬

‭return response.getBody();‬
}‬

}‬

‭ ‬‭
✔ getForEntity(url, responseType.class)‬‭→ Fetches the response along with‬
‭HTTP status.‬
‭✔‬‭
getForObject(url, responseType.class)‬‭→ Directly‬‭fetches the response body.‬

‭Using‬‭
WebClient‬‭(Recommended)‬
‭java:‬
‭mport org.springframework.stereotype.Service;‬
i
import org.springframework.web.reactive.function.client.WebClient;‬

import reactor.core.publisher.Mono;‬

@Service‬

public class ExternalApiService {‬

private final WebClient webClient = WebClient.create();‬

public String fetchData() {‬



‭return webClient.get()‬
‭.uri("https://jsonplaceholder.typicode.com/posts/1")‬
‭.retrieve()‬
‭.bodyToMono(String.class)‬
‭.block(); // Blocking call for synchronous execution‬
}‬

}‬

‭✔‬‭
retrieve()‬‭→ Fetches the response.‬
‭✔‬‭
bodyToMono(String.class)‬‭→ Converts response to‬‭
Mono<String>‬‭.‬
‭✔‬‭
.block()‬‭→ Converts reactive response to a synchronous‬‭one.‬

2️⃣ POST Request - Send Data to an External API‬


‭Using‬‭
RestTemplate‬
‭java:‬
‭mport
i org.springframework.http.HttpEntity;‬
import
‭ org.springframework.http.HttpHeaders;‬
import
‭ org.springframework.http.MediaType;‬
import
‭ org.springframework.stereotype.Service;‬
import
‭ org.springframework.web.client.RestTemplate;‬

‭mport java.util.HashMap;‬
i
import java.util.Map;‬

‭Service‬
@
public class ExternalApiService {‬

private final RestTemplate restTemplate = new RestTemplate();‬

public String sendData() {‬



‭String url = "https://jsonplaceholder.typicode.com/posts";‬

/‭/ Prepare request body‬


‭Map<String, Object> requestBody = new HashMap<>();‬
‭requestBody.put("title", "Spring Boot API Integration");‬
r‭equestBody.put("body", "This is a sample post request.");‬
‭requestBody.put("userId", 1);‬

/‭/ Set headers‬


‭HttpHeaders headers = new HttpHeaders();‬
‭headers.setContentType(MediaType.APPLICATION_JSON);‬

/‭/ Create HttpEntity‬


‭HttpEntity<Map<String, Object>> request = new‬
HttpEntity<>(requestBody, headers);‬

/‭/ Send POST request‬


‭return restTemplate.postForObject(url, request,‬
String.class);‬

}‬

}‬

‭ ‬‭
✔ postForObject(url, request, responseType.class)‬‭→ Sends a POST‬
‭request and retrieves the response.‬

‭Using‬‭
WebClient‬
‭java:‬
‭mport
i org.springframework.stereotype.Service;‬
import
‭ org.springframework.web.reactive.function.client.WebClient;‬
import
‭ reactor.core.publisher.Mono;‬
import
‭ java.util.Map;‬

‭Service‬
@
public class ExternalApiService {‬

private final WebClient webClient = WebClient.create();‬

public String sendData() {‬



‭String url = "https://jsonplaceholder.typicode.com/posts";‬

‭Map<String, Object> requestBody = Map.of(‬


‭"title", "Spring Boot API Integration",‬
‭"body", "This is a sample post request.",‬
‭"userId", 1‬
‭);‬
‭return webClient.post()‬
‭.uri(url)‬
‭.bodyValue(requestBody)‬
‭.retrieve()‬
‭.bodyToMono(String.class)‬
‭.block();‬
}‬

}‬

‭✔‬‭
.bodyValue(requestBody)‬‭→ Sends request body as JSON.‬
‭✔‬‭
.retrieve()‬‭→ Fetches response.‬

3️⃣ Handling Responses and Errors‬


‭Handling Errors in‬‭


RestTemplate‬
‭java:‬
try {‬

ResponseEntity<String> response = restTemplate.getForEntity(url,‬

String.class);‬

return response.getBody();‬

} catch (Exception e) {‬

return "Error: " + e.getMessage();‬

}‬

‭Handling Errors in‬‭


WebClient‬
‭java:‬
return webClient.get()‬

.uri(url)‬

.retrieve()‬

.onStatus(HttpStatus::is4xxClientError, response ->‬

‭Mono.error(new RuntimeException("Client error!"))‬
)‬

.onStatus(HttpStatus::is5xxServerError, response ->‬

‭Mono.error(new RuntimeException("Server error!"))‬
)‬

.bodyToMono(String.class)‬

.block();‬

4️⃣ Example Controller for API Integration‬

‭java:‬
‭mport
i org.springframework.web.bind.annotation.GetMapping;‬
import
‭ org.springframework.web.bind.annotation.PostMapping;‬
import
‭ org.springframework.web.bind.annotation.RequestMapping;‬
import
‭ org.springframework.web.bind.annotation.RestController;‬

‭RestController‬
@
@RequestMapping("/api")‬

public class ExternalApiController {‬

private final ExternalApiService apiService;‬

public ExternalApiController(ExternalApiService apiService) {‬



‭this.apiService = apiService;‬
}‬

‭GetMapping("/fetch")‬
@
public String fetchExternalData() {‬

‭return apiService.fetchData();‬
}‬

‭PostMapping("/send")‬
@
public String sendExternalData() {‬

‭return apiService.sendData();‬
}‬

}‬

‭Testing the APIs‬


‭ ET Request:‬
G
‭sh:‬
curl -X GET http://localhost:8080/api/fetch‬

‭●‬

‭ OST Request:‬
P
‭sh:‬
curl -X POST http://localhost:8080/api/send‬

‭●‬
5️⃣ Choosing Between‬‭RestTemplate‬‭and‬‭WebClient‬

‭Feature‬ ‭ estTemplate‬
R ‭WebClient (Recommended)‬
‭(Deprecated)‬

‭Synchronous‬ ✅ Yes‬
‭ ✅ Yes (with‬‭.block()‬‭)‬

‭Asynchronous‬ ‭❌ No‬ ‭✅ Yes (default)‬

‭ eactive‬
R ❌
‭ No‬ ✅
‭ Yes (supports Reactive‬
‭Support‬ ‭Streams)‬

‭Future Proof‬ ❌
‭ No (Deprecated)‬ ‭✅ Yes‬

✅ Use‬‭WebClient‬‭for modern Spring Boot applications.‬



‭✅ Use‬‭
RestTemplate‬‭only if you are working on legacy‬‭projects.‬
‭Criteria API and Query Methods in Spring Boot with MySQL‬

I‭n Spring Boot, we can interact with MySQL using‬‭Spring Data JPA‬‭. The two primary ways‬
‭to query data are:‬

‭ .‬ S
1 ‭ pring Data JPA Query Methods (Derived Queries)‬
‭2.‬ ‭Criteria API (For Dynamic Queries)‬

1️⃣ Spring Data JPA Query Methods (Derived Queries)‬



‭Spring Data JPA provides an easy way to define query methods based on method names.‬

‭Example Entity (‬‭


Employee‬‭)‬
‭java:‬
‭mport jakarta.persistence.*;‬
i
import lombok.*;‬

‭Entity‬
@
@Table(name = "employees")‬

@Getter‬

@Setter‬

@NoArgsConstructor‬

@AllArgsConstructor‬

public class Employee {‬

@Id‬

@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭rivate String name;‬


p
private String department;‬

private int salary;‬

}‬

‭Creating Repository‬
‭java:‬
‭mport org.springframework.data.jpa.repository.JpaRepository;‬
i
import org.springframework.stereotype.Repository;‬

import java.util.List;‬

@Repository‬

‭ublic interface EmployeeRepository extends JpaRepository<Employee,‬
p
Long> {‬

List<Employee> findByDepartment(String department);‬

List<Employee> findBySalaryGreaterThan(int salary);‬

Employee findByName(String name);‬

List<Employee> findByDepartmentAndSalaryGreaterThan(String‬

department, int salary);‬

}‬

‭Usage in Service‬
‭java:‬
‭mport org.springframework.stereotype.Service;‬
i
import java.util.List;‬

‭Service‬
@
public class EmployeeService {‬

private final EmployeeRepository employeeRepository;‬

public EmployeeService(EmployeeRepository employeeRepository) {‬



‭this.employeeRepository = employeeRepository;‬
}‬

‭ublic List<Employee> getEmployeesByDepartment(String‬


p
department) {‬

‭return employeeRepository.findByDepartment(department);‬
}‬

public List<Employee> getHighEarningEmployees(int salary) {‬



‭return employeeRepository.findBySalaryGreaterThan(salary);‬
}‬

}‬

‭Using Derived Queries in Controller‬


‭java:‬
‭mport org.springframework.web.bind.annotation.*;‬
i
import java.util.List;‬

‭RestController‬
@
@RequestMapping("/employees")‬

public class EmployeeController {‬

private final EmployeeService employeeService;‬

public EmployeeController(EmployeeService employeeService) {‬



‭this.employeeService = employeeService;‬
}‬

‭GetMapping("/by-department/{dept}")‬
@
public List<Employee> getByDepartment(@PathVariable String dept)‬

{‬

‭return employeeService.getEmployeesByDepartment(dept);‬
}‬

‭GetMapping("/high-salary/{salary}")‬
@
public List<Employee> getHighEarners(@PathVariable int salary) {‬

‭return employeeService.getHighEarningEmployees(salary);‬
}‬

}‬

2️⃣ Criteria API (For Dynamic Queries)‬



‭The‬‭Criteria API‬‭is useful for building complex and dynamic queries at runtime.‬

‭Using‬‭
CriteriaBuilder‬‭to Build Dynamic Queries‬
‭java:‬
‭mport
i jakarta.persistence.criteria.*;‬
import
‭ org.springframework.stereotype.Service;‬
import
‭ jakarta.persistence.EntityManager;‬
import
‭ jakarta.persistence.PersistenceContext;‬
import
‭ java.util.List;‬

‭Service‬
@
public class EmployeeCriteriaService {‬

@PersistenceContext‬

private EntityManager entityManager;‬

‭ublic List<Employee> findEmployeesWithSalaryGreaterThan(int‬


p
salary) {‬

‭CriteriaBuilder cb = entityManager.getCriteriaBuilder();‬
‭CriteriaQuery<Employee> query =‬
cb.createQuery(Employee.class);‬

‭Root<Employee> root = query.from(Employee.class);‬

q‭uery.select(root).where(cb.greaterThan(root.get("salary"),‬
salary));‬

‭return entityManager.createQuery(query).getResultList();‬
}‬

‭ublic List<Employee>‬
p
findEmployeesByDepartmentAndMinSalary(String department, int salary)‬

{‬

‭CriteriaBuilder cb = entityManager.getCriteriaBuilder();‬
‭CriteriaQuery<Employee> query =‬
cb.createQuery(Employee.class);‬

‭Root<Employee> root = query.from(Employee.class);‬

P‭redicate deptPredicate = cb.equal(root.get("department"),‬


department);‬

‭Predicate salaryPredicate =‬
cb.greaterThan(root.get("salary"), salary);‬

‭query.select(root).where(cb.and(deptPredicate,‬
salaryPredicate));‬

‭return entityManager.createQuery(query).getResultList();‬
}‬

}‬

‭Using Criteria API in Controller‬


‭java:‬
‭mport org.springframework.web.bind.annotation.*;‬
i
import java.util.List;‬

‭RestController‬
@
@RequestMapping("/employees/criteria")‬

public class EmployeeCriteriaController {‬

private final EmployeeCriteriaService employeeCriteriaService;‬

‭ublic EmployeeCriteriaController(EmployeeCriteriaService‬
p
employeeCriteriaService) {‬

‭this.employeeCriteriaService = employeeCriteriaService;‬
}‬

‭GetMapping("/high-salary/{salary}")‬
@
public List<Employee> getBySalary(@PathVariable int salary) {‬

‭return‬
employeeCriteriaService.findEmployeesWithSalaryGreaterThan(salary);‬

}‬

‭GetMapping("/by-department/{dept}/min-salary/{salary}")‬
@
public List<Employee> getByDeptAndSalary(@PathVariable String‬

dept, @PathVariable int salary) {‬

‭return‬
employeeCriteriaService.findEmployeesByDepartmentAndMinSalary(dept,‬

salary);‬

}‬

}‬

3️⃣ Native Queries and JPQL‬



‭Sometimes, we need to write‬‭custom SQL queries‬‭.‬

‭JPQL Query (Using‬‭


@Query‬‭)‬
‭java:‬
‭mport
i org.springframework.data.jpa.repository.Query;‬
import
‭ org.springframework.data.repository.query.Param;‬
import
‭ org.springframework.data.jpa.repository.JpaRepository;‬
import
‭ java.util.List;‬

‭ublic interface EmployeeRepository extends JpaRepository<Employee,‬


p
Long> {‬

‭Query("SELECT e FROM Employee e WHERE e.salary > :salary")‬


@
List<Employee> findHighSalaryEmployees(@Param("salary") int‬

salary);‬

}‬

‭Native Query (Using‬‭


@Query(nativeQuery = true)‬‭)‬
‭java:‬
‭Query(value = "SELECT * FROM employees WHERE department =‬
@
:department", nativeQuery = true)‬

‭ist<Employee> findByDepartmentNative(@Param("department") String‬
L
department);‬

4️⃣ Summary‬

‭Method‬ ‭Use Case‬

‭ erived‬
D ‭Simple queries like‬‭
findByName()‬‭or‬‭
findByDepartment()‬
‭Queries‬

‭JPQL (‬‭
@Query‬
‭)‬ ‭Custom queries using entity names (‬‭
SELECT e FROM Employee‬‭
e‬‭)‬
‭Native Queries‬ ‭When you need full control over SQL syntax (‬‭
SELECT‬‭
* FROM‬
‭employees‬
‭)‬

‭Criteria API‬ ‭When building‬‭dynamic queries‬


‭Sending Email Using JavaMailSender in Spring Boot‬

‭ pring Boot provides‬‭JavaMailSender‬‭to send emails using‬‭SMTP servers‬‭like Gmail,‬


S
‭Outlook, etc.‬

1️⃣ Add Dependencies‬



‭In your‬‭
pom.xml‬
‭, add the‬‭Spring Boot Starter Mail‬‭dependency:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-mail</artifactId>‬

</dependency>‬

2️⃣ Configure SMTP Settings‬



‭Add the following properties in‬‭
application.properties‬‭(for‬‭Gmail SMTP‬‭):‬

‭properties:‬
‭pring.mail.host=smtp.gmail.com‬
s
spring.mail.port=587‬

spring.mail.username=your_email@gmail.com‬

spring.mail.password=your_app_password‬

spring.mail.properties.mail.smtp.auth=true‬

spring.mail.properties.mail.smtp.starttls.enable=true‬

‭ ote:‬‭Gmail requires an‬‭App Password‬‭instead of your regular password. You‬


N
‭can generate it in your‬‭Google Account Security Settings‬‭.‬

3️⃣ Create Email Service‬



‭java:‬
‭mport
i org.springframework.mail.javamail.JavaMailSender;‬
import
‭ org.springframework.mail.javamail.MimeMessageHelper;‬
import
‭ org.springframework.stereotype.Service;‬
import
‭ jakarta.mail.MessagingException;‬
import
‭ jakarta.mail.internet.MimeMessage;‬
‭Service‬
@
public class EmailService {‬

private final JavaMailSender mailSender;‬

public EmailService(JavaMailSender mailSender) {‬



‭this.mailSender = mailSender;‬
}‬

‭ublic void sendSimpleEmail(String to, String subject, String‬


p
text) {‬

‭MimeMessage message = mailSender.createMimeMessage();‬
‭try {‬
‭MimeMessageHelper helper = new‬
MimeMessageHelper(message, true);‬

‭helper.setTo(to);‬
‭helper.setSubject(subject);‬
‭helper.setText(text, true); // 'true' for HTML content‬
‭mailSender.send(message);‬
‭System.out.println("Email sent successfully!");‬
‭} catch (MessagingException e) {‬
‭e.printStackTrace();‬
‭}‬
}‬

}‬

4️⃣ Expose an API to Send Emails‬



‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/email")‬

public class EmailController {‬

private final EmailService emailService;‬

public EmailController(EmailService emailService) {‬



‭this.emailService = emailService;‬
}‬

‭PostMapping("/send")‬
@
public String sendEmail(@RequestParam String to,‬

@RequestParam String subject,‬

@RequestParam String text) {‬

‭emailService.sendSimpleEmail(to, subject, text);‬
‭return "Email sent successfully!";‬
}‬

}‬

5️⃣ Test the API‬



‭Use‬‭Postman‬‭or a browser:‬

‭OST http://localhost:8080/email/send‬
P
Params:‬

- `to`: recipient@example.com‬

- `subject`: Test Email‬

- `text`: Hello, this is a test email!‬

6️⃣ Sending Attachments (Optional)‬



‭Modify‬‭
EmailService‬‭to send attachments:‬

‭java:‬
‭mport org.springframework.core.io.FileSystemResource;‬
i
import java.io.File;‬

‭ublic void sendEmailWithAttachment(String to, String subject,‬


p
String text, String attachmentPath) {‬

MimeMessage message = mailSender.createMimeMessage();‬

try {‬

‭MimeMessageHelper helper = new MimeMessageHelper(message,‬
true);‬

‭helper.setTo(to);‬
‭helper.setSubject(subject);‬
‭helper.setText(text, true);‬

‭// Add attachment‬


F‭ileSystemResource file = new FileSystemResource(new‬
File(attachmentPath));‬

‭helper.addAttachment(file.getFilename(), file);‬

m‭ailSender.send(message);‬
‭System.out.println("Email with attachment sent‬
successfully!");‬

} catch (MessagingException e) {‬

‭e.printStackTrace();‬
}‬

}‬

‭Conclusion‬


‭ his setup allows sending:‬
T


‭ ‬‭Plain text emails‬


‭ ‬‭HTML emails‬
‭ ‬‭Emails with attachments‬
‭Efficient Task Scheduling in Spring Boot Using Cron Jobs‬

‭ pring Boot provides a built-in mechanism for scheduling tasks using the‬‭
S @Scheduled‬
‭annotation. You can schedule tasks using‬‭fixed delays,‬‭fixed rates, or cron expressions‬‭.‬

1️⃣ Add Dependencies‬



‭ pring Boot comes with scheduling support, so no extra dependencies are needed.‬
S
‭However, ensure the‬‭
spring-boot-starter‬‭dependency is present in your‬‭ pom.xml‬‭:‬

‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter</artifactId>‬

</dependency>‬

2️⃣ Enable Scheduling in Spring Boot‬



‭ o enable scheduling, add the‬‭
T @EnableScheduling‬‭annotation in your main application‬
‭class:‬

‭java:‬
‭mport org.springframework.boot.SpringApplication;‬
i
import org.springframework.boot.autoconfigure.SpringBootApplication;‬

import org.springframework.scheduling.annotation.EnableScheduling;‬

‭SpringBootApplication‬
@
@EnableScheduling // Enables scheduling tasks‬

public class SchedulerApplication {‬

public static void main(String[] args) {‬

‭SpringApplication.run(SchedulerApplication.class, args);‬
}‬

}‬

3️⃣ Creating Scheduled Tasks in Spring Boot‬

‭Spring Boot provides three scheduling types:‬

‭ .‬ F
1 ‭ ixed Delay‬‭(Runs after the previous execution completes)‬
‭2.‬ ‭Fixed Rate‬‭(Runs at a fixed interval, independent‬‭of execution time)‬
‭3.‬ ‭Cron Expressions‬‭(Runs at specified times)‬

‭A) Fixed Delay Scheduling‬

‭Executes a task after a specific delay‬‭after the previous execution finishes‬‭.‬

‭java:‬
‭mport org.springframework.scheduling.annotation.Scheduled;‬
i
import org.springframework.stereotype.Component;‬

‭Component‬
@
public class FixedDelayTask {‬

@Scheduled(fixedDelay = 5000) // Runs 5 seconds after the‬

previous execution completes‬

public void executeTask() {‬

‭System.out.println("Fixed delay task executed at: " +‬
System.currentTimeMillis());‬

}‬

}‬

‭B) Fixed Rate Scheduling‬

‭Executes a task at a‬‭fixed interval‬‭, regardless of the execution time.‬

‭java:‬
‭Component‬
@
public class FixedRateTask {‬

@Scheduled(fixedRate = 5000) // Runs every 5 seconds,‬

regardless of previous execution‬

public void executeTask() {‬

‭System.out.println("Fixed rate task executed at: " +‬
System.currentTimeMillis());‬

}‬

}‬

‭C) Cron Expression Scheduling‬

‭Cron expressions define‬‭complex scheduling rules‬‭in the format:‬


second minute hour day month weekday‬

‭Example:‬‭
"0 0 9 * * *"‬‭→ Runs‬‭every day at 9 AM‬‭.‬

‭java:‬
‭Component‬
@
public class CronTask {‬

@Scheduled(cron = "0 0 9 * * *") // Runs daily at 9 AM‬

public void executeTask() {‬

‭System.out.println("Cron task executed at: " +‬
System.currentTimeMillis());‬

}‬

}‬

4️⃣ Understanding Cron Expressions‬



‭Expression‬ ‭Meaning‬

"0 * * * * *"‬
‭ ‭Every minute‬

"0 0 * * * *"‬
‭ ‭Every hour‬

"0 0 9 * * *"‬
‭ ‭Every day at 9 AM‬

‭0 0 9 * *‬
" ‭Every weekday at 9 AM‬
MON-FRI"‬

"0 30 9 * * *"‬
‭ ‭Every day at‬‭9:30 AM‬

"*/10 * * * * *"‬ ‭Every‬‭10 seconds‬


"0 0/15 * * * *"‬ ‭Every‬‭15 minutes‬


"0 0 9 1 * *"‬
‭ ‭First day‬‭of every month at 9 AM‬

"0 0 9 ? * 6"‬
‭ ‭Every‬‭Saturday at 9 AM‬
5️⃣ Scheduling Tasks Dynamically‬

‭ ometimes, you need to change the schedule‬‭without restarting‬‭the app. Store the cron‬
S
‭expression in‬‭
application.properties‬‭:‬

‭properties:‬
scheduler.cron=0 0 9 * * *‬

‭Then, update the task like this:‬

‭java:‬
‭mport org.springframework.beans.factory.annotation.Value;‬
i
import org.springframework.scheduling.annotation.Scheduled;‬

import org.springframework.stereotype.Component;‬

‭Component‬
@
public class DynamicCronTask {‬

@Value("${scheduler.cron}")‬

private String cronExpression;‬

‭Scheduled(cron = "#{@dynamicCronTask.cronExpression}") //‬


@
Fetches cron from properties‬

public void executeTask() {‬

‭System.out.println("Dynamic cron task executed at: " +‬
System.currentTimeMillis());‬

}‬

}‬

6️⃣ Advanced Scheduling: Using‬



ScheduledExecutorService‬

‭For‬‭more control‬‭over scheduled tasks, use‬‭
ScheduledExecutorService‬
‭:‬

‭java:‬
‭mport java.util.concurrent.Executors;‬
i
import java.util.concurrent.ScheduledExecutorService;‬

import java.util.concurrent.TimeUnit;‬

public class AdvancedScheduler {‬



‭rivate final ScheduledExecutorService scheduler =‬
p
Executors.newScheduledThreadPool(1);‬

public void startTask() {‬



‭scheduler.scheduleAtFixedRate(() ->‬
‭System.out.println("Advanced scheduled task executed"),‬
‭0, 5, TimeUnit.SECONDS);‬
}‬

}‬

7️⃣ Handling Long-Running Tasks‬



I‭f a scheduled task‬‭takes longer than the interval‬‭, it may overlap. Use‬‭
@Async‬‭to run tasks‬
‭in‬‭parallel‬‭:‬

‭Add the following dependency for‬‭asynchronous execution‬‭:‬

<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-aop</artifactId>‬

</dependency>‬

‭ nable Async Execution:‬


E
‭java:‬
‭mport org.springframework.boot.autoconfigure.SpringBootApplication;‬
i
import org.springframework.scheduling.annotation.EnableAsync;‬

‭SpringBootApplication‬
@
@EnableAsync // Enables async task execution‬

public class SchedulerApplication {‬

}‬

‭ se‬‭
U @Async‬‭for non-blocking execution:‬
‭java:‬
‭mport org.springframework.scheduling.annotation.Async;‬
i
import org.springframework.scheduling.annotation.Scheduled;‬

import org.springframework.stereotype.Component;‬

‭Component‬
@
public class AsyncTaskScheduler {‬

@Async‬

‭Scheduled(fixedRate = 5000)‬
@
public void executeTask() throws InterruptedException {‬

‭System.out.println("Executing async task...");‬
‭Thread.sleep(7000); // Simulate long execution‬
‭System.out.println("Async task completed.");‬
}‬

}‬

8️⃣ Best Practices for Scheduling in Spring Boot‬



✅‬‭Use cron expressions for precise control‬
✅‬‭Store cron expressions in application.properties‬‭for easy updates‬

✅‬‭Use‬‭@Async‬‭for long-running tasks to prevent blocking‬


✅‬‭Monitor task execution logs to detect failures‬


✅‬‭Use‬‭ScheduledExecutorService‬‭for high-performance‬‭scheduling‬

‭Conclusion‬
‭ pring Boot makes‬‭task scheduling easy‬‭using the‬‭
S @Scheduled‬‭annotation. Whether‬
‭using‬‭fixed delay, fixed rate, or cron expressions‬‭,‬‭you can efficiently manage background‬
‭jobs in your application.‬
‭Signup, Login, and Logout using JWT Authentication in Spring Boot‬

I‭n this guide, we will‬‭implement JWT-based authentication‬‭in a Spring Boot application.‬


‭Users will be able to‬‭sign up, log in, and log out‬‭securely using JWT tokens.‬

1️⃣ Add Dependencies in‬‭pom.xml‬



‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-web</artifactId>‬

</dependency>‬

<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-security</artifactId>‬

</dependency>‬

<dependency>‬

<groupId>io.jsonwebtoken</groupId>‬

<artifactId>jjwt</artifactId>‬

<version>0.11.5</version>‬

</dependency>‬

<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-data-jpa</artifactId>‬

</dependency>‬

<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-validation</artifactId>‬

</dependency>‬

<dependency>‬

<groupId>com.h2database</groupId>‬

<artifactId>h2</artifactId>‬

<scope>runtime</scope>‬

</dependency>‬

2️⃣ Configure Database in‬‭application.properties‬

‭For demonstration, we use an in-memory‬‭H2 database‬‭:‬

‭properties:‬
‭pring.datasource.url=jdbc:h2:mem:testdb‬
s
spring.datasource.driverClassName=org.h2.Driver‬

spring.datasource.username=sa‬

spring.datasource.password=‬

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect‬

spring.h2.console.enabled=true‬

3️⃣ Create the User Entity (‬‭User.java‬‭)‬



‭This entity will store user details.‬

‭java:‬
‭mport jakarta.persistence.*;‬
i
import lombok.*;‬

‭Getter‬
@
@Setter‬

@NoArgsConstructor‬

@AllArgsConstructor‬

@Entity‬

@Table(name = "users")‬

public class User {‬

@Id‬

@GeneratedValue(strategy = GenerationType.IDENTITY)‬

private Long id;‬

‭Column(unique = true, nullable = false)‬


@
private String username;‬

‭Column(nullable = false)‬
@
private String password;‬

‭Column(nullable = false)‬
@
private String role; // Example: ROLE_USER, ROLE_ADMIN‬

}‬

4️⃣ Create User Repository (‬‭UserRepository.java‬‭)‬

‭java:‬
‭mport org.springframework.data.jpa.repository.JpaRepository;‬
i
import java.util.Optional;‬

public interface UserRepository extends JpaRepository<User, Long> {‬



Optional<User> findByUsername(String username);‬

}‬

5️⃣ Create JWT Utility Class (‬‭JwtUtil.java‬‭)‬



‭This class will‬‭generate and validate JWT tokens‬‭.‬

‭java:‬
‭mport
i io.jsonwebtoken.*;‬
import
‭ io.jsonwebtoken.security.Keys;‬
import
‭ org.springframework.stereotype.Component;‬
import
‭ java.security.Key;‬
import
‭ java.util.Date;‬

‭Component‬
@
public class JwtUtil {‬

private static final String SECRET_KEY =‬

"mysecretkeymysecretkeymysecretkey123456"; // Use 256-bit key‬

private static final long EXPIRATION_TIME = 86400000; // 1 day‬

in milliseconds‬

‭rivate final Key key =‬


p
Keys.hmacShaKeyFor(SECRET_KEY.getBytes());‬

public String generateToken(String username) {‬



‭return Jwts.builder()‬
‭.setSubject(username)‬
‭.setIssuedAt(new Date())‬
‭.setExpiration(new Date(System.currentTimeMillis() +‬
EXPIRATION_TIME))‬

.‭signWith(key, SignatureAlgorithm.HS256)‬
‭.compact();‬
}‬

public String extractUsername(String token) {‬



‭return Jwts.parserBuilder()‬
‭.setSigningKey(key)‬
‭.build()‬
‭.parseClaimsJws(token)‬
‭.getBody()‬
‭.getSubject();‬
}‬

public boolean validateToken(String token) {‬



‭try {‬

‭wts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token‬
J
);‬

‭return true;‬
‭} catch (JwtException e) {‬
‭return false;‬
‭}‬
}‬

}‬

6️⃣ Create Authentication Service (‬‭AuthService.java‬‭)‬



‭java:‬
‭mport org.springframework.security.crypto.password.PasswordEncoder;‬
i
import org.springframework.stereotype.Service;‬

import java.util.Optional;‬

‭Service‬
@
public class AuthService {‬

private final UserRepository userRepository;‬

private final PasswordEncoder passwordEncoder;‬

private final JwtUtil jwtUtil;‬

‭ublic AuthService(UserRepository userRepository,‬


p
PasswordEncoder passwordEncoder, JwtUtil jwtUtil) {‬

t‭his.userRepository = userRepository;‬
‭this.passwordEncoder = passwordEncoder;‬
‭this.jwtUtil = jwtUtil;‬
}‬

‭ublic String signUp(String username, String password, String‬


p
role) {‬

‭if (userRepository.findByUsername(username).isPresent()) {‬
‭throw new RuntimeException("Username already exists!");‬
‭}‬
‭User user = new User();‬
‭user.setUsername(username);‬
‭user.setPassword(passwordEncoder.encode(password));‬
‭user.setRole(role);‬
‭userRepository.save(user);‬
‭return "User registered successfully!";‬
}‬

public String login(String username, String password) {‬



‭Optional<User> userOpt =‬
userRepository.findByUsername(username);‬

‭if (userOpt.isPresent()) {‬
‭User user = userOpt.get();‬
‭if (passwordEncoder.matches(password,‬
user.getPassword())) {‬

‭return jwtUtil.generateToken(username);‬
‭}‬
‭}‬
‭throw new RuntimeException("Invalid username or password!");‬
}‬

}‬

7️⃣
‭ Create Authentication Controller‬
‭(‭
A‬ uthController.java‬
‭)‬
‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/auth")‬

public class AuthController {‬

private final AuthService authService;‬

public AuthController(AuthService authService) {‬



‭this.authService = authService;‬
}‬

‭PostMapping("/signup")‬
@
public String signUp(@RequestParam String username,‬

@RequestParam String password, @RequestParam String role) {‬

‭return authService.signUp(username, password, role);‬
}‬

‭PostMapping("/login")‬
@
public String login(@RequestParam String username, @RequestParam‬

String password) {‬

‭return authService.login(username, password);‬
}‬

}‬

8️⃣ Secure the Application (‬‭SecurityConfig.java‬‭)‬



‭java:‬
‭mport org.springframework.context.annotation.Bean;‬
i
import org.springframework.context.annotation.Configuration;‬

import‬

org.springframework.security.authentication.AuthenticationManager;‬

import‬

org.springframework.security.config.annotation.authentication.config‬

uration.AuthenticationConfiguration;‬

import‬

org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;‬

import org.springframework.security.crypto.password.PasswordEncoder;‬

‭Configuration‬
@
public class SecurityConfig {‬

‭Bean‬
@
public PasswordEncoder passwordEncoder() {‬

‭return new BCryptPasswordEncoder();‬
}‬

‭Bean‬
@
public AuthenticationManager‬

authenticationManager(AuthenticationConfiguration configuration)‬

throws Exception {‬

‭return configuration.getAuthenticationManager();‬
}‬

}‬

9️⃣ Testing the API‬



📌 Signup (Register a User)‬

‭Request:‬‭
POST /auth/signup‬

‭json:‬
{‬

"username": "john",‬

"password": "password123",‬

"role": "ROLE_USER"‬

}‬

‭Response:‬‭
"User registered successfully!"‬

📌 Login (Generate JWT Token)‬


‭Request:‬‭
POST /auth/login‬

‭json:‬
{‬

"username": "john",‬

"password": "password123"‬

}‬

‭Response:‬

‭json:‬
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."‬

📌 Protecting Endpoints‬

‭Add a‬‭protected endpoint‬‭that requires authentication:‬

‭java:‬
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/user")‬

public class UserController {‬

‭GetMapping("/profile")‬
@
public String getProfile() {‬

‭return "User Profile Data";‬
}‬

}‬

‭Then configure security to allow only authenticated users:‬

‭java:‬
‭mport‬
i
org.springframework.security.config.annotation.web.builders.HttpSecu‬

rity;‬

import‬

org.springframework.security.config.annotation.web.configuration.Ena‬

bleWebSecurity;‬

import org.springframework.security.web.SecurityFilterChain;‬

import‬

org.springframework.security.web.authentication.UsernamePasswordAuth‬

enticationFilter;‬

‭EnableWebSecurity‬
@
public class SecurityConfig {‬

‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity‬

http) throws Exception {‬

‭http.csrf().disable()‬
‭.authorizeRequests()‬
.‭requestMatchers("/auth/signup",‬
"/auth/login").permitAll()‬

‭.anyRequest().authenticated();‬
‭return http.build();‬
}‬

}‬

🔚 Conclusion‬

✅ Implemented‬‭JWT authentication‬
✅ Built‬‭signup, login, and logout‬‭functionality‬

✅ Protected‬‭endpoints with authentication‬




‭Implementing Logout in JWT Authentication (Spring Boot)‬

I‭n a‬‭stateless JWT authentication system‬‭, logging out is different from traditional‬
‭session-based authentication. Since JWT tokens are‬‭self-contained‬‭, the server does not‬
‭store them, so we cannot "invalidate" a token in a database directly. However, we have‬
‭several ways to implement logout effectively.‬

1️⃣ Methods for Logout in JWT-Based Authentication‬



✅ Method 1: Token Blacklisting (Recommended for Production)‬

‭‬ S
● ‭ tore the JWT token in a‬‭database (Redis or SQL) or an in-memory blacklist‬‭.‬
‭●‬ ‭Check if the token is‬‭blacklisted‬‭before processing‬‭a request.‬
‭●‬ ‭Remove the token from the list when it expires.‬

✅ Method 2: Client-Side Logout (Basic Approach)‬


‭●‬ T ‭ he frontend (browser or app)‬‭removes the JWT token‬‭from storage (e.g.,‬


‭LocalStorage or Cookies).‬
‭●‬ ‭The server does‬‭not need to track logout‬‭since tokens expire automatically.‬

✅ Method 3: Changing Secret Key (Forcing Global Logout)‬


‭ ‬ I‭f you change the‬‭JWT signing key‬‭, all issued tokens‬‭become‬‭invalid‬‭immediately.‬



‭●‬ ‭However, this affects‬‭all users‬‭, so it's not ideal for individual logouts.‬

2️⃣ Implement Logout Using Token Blacklisting‬


‭Step 1: Store Tokens in a Blacklist (‬‭


TokenBlacklistService.java‬‭)‬
‭ e will use an‬‭in-memory HashSet‬‭for simplicity. In production, use‬‭Redis‬‭for better‬
W
‭scalability.‬

‭java:‬
‭mport org.springframework.stereotype.Service;‬
i
import java.util.HashSet;‬

import java.util.Set;‬

‭Service‬
@
public class TokenBlacklistService {‬

private final Set<String> blacklistedTokens = new HashSet<>();‬

public void blacklistToken(String token) {‬

‭blacklistedTokens.add(token);‬
}‬

public boolean isTokenBlacklisted(String token) {‬



‭return blacklistedTokens.contains(token);‬
}‬

}‬

‭Step 2: Implement Logout Controller (‬‭


AuthController.java‬
‭)‬
‭java:‬
‭mport jakarta.servlet.http.HttpServletRequest;‬
i
import org.springframework.web.bind.annotation.*;‬

‭RestController‬
@
@RequestMapping("/auth")‬

public class AuthController {‬

private final AuthService authService;‬

private final TokenBlacklistService tokenBlacklistService;‬

‭ublic AuthController(AuthService authService,‬


p
TokenBlacklistService tokenBlacklistService) {‬

‭this.authService = authService;‬
‭this.tokenBlacklistService = tokenBlacklistService;‬
}‬

‭PostMapping("/logout")‬
@
public String logout(HttpServletRequest request) {‬

‭String token = request.getHeader("Authorization");‬
‭if (token != null && token.startsWith("Bearer ")) {‬
‭token = token.substring(7);‬
‭tokenBlacklistService.blacklistToken(token);‬
‭return "Logout successful!";‬
‭}‬
‭return "Invalid token!";‬
}‬

}‬

‭Step 3: Check Blacklist in JWT Filter (‬‭
JwtFilter.java‬‭)‬
‭Modify the‬‭JWT filter‬‭to check if the token is blacklisted.‬

‭java:‬
‭mport io.jsonwebtoken.ExpiredJwtException;‬
i
import jakarta.servlet.FilterChain;‬

import jakarta.servlet.ServletException;‬

import jakarta.servlet.ServletRequest;‬

import jakarta.servlet.ServletResponse;‬

import jakarta.servlet.http.HttpServletRequest;‬

import‬

org.springframework.security.core.context.SecurityContextHolder;‬

import org.springframework.security.core.userdetails.UserDetails;‬

import‬

org.springframework.security.web.authentication.WebAuthenticationDet‬

ailsSource;‬

import org.springframework.stereotype.Component;‬

import org.springframework.web.filter.GenericFilterBean;‬

import java.io.IOException;‬

‭Component‬
@
public class JwtFilter extends GenericFilterBean {‬

private final JwtUtil jwtUtil;‬

private final TokenBlacklistService tokenBlacklistService;‬

‭ublic JwtFilter(JwtUtil jwtUtil, TokenBlacklistService‬


p
tokenBlacklistService) {‬

‭this.jwtUtil = jwtUtil;‬
‭this.tokenBlacklistService = tokenBlacklistService;‬
}‬

‭Override‬
@
public void doFilter(ServletRequest request, ServletResponse‬

response, FilterChain chain)‬

‭throws IOException, ServletException {‬
‭HttpServletRequest httpRequest = (HttpServletRequest)‬
request;‬

‭String authHeader = httpRequest.getHeader("Authorization");‬
‭if (authHeader != null && authHeader.startsWith("Bearer "))‬
{‬

‭String token = authHeader.substring(7);‬

/‭/ Check if the token is blacklisted‬


‭if (tokenBlacklistService.isTokenBlacklisted(token)) {‬
‭SecurityContextHolder.clearContext();‬
‭chain.doFilter(request, response);‬
‭return;‬
‭}‬

‭try {‬
‭String username = jwtUtil.extractUsername(token);‬
‭if (username != null &&‬
SecurityContextHolder.getContext().getAuthentication() == null) {‬

‭UserDetails userDetails = new‬
CustomUserDetailsService().loadUserByUsername(username);‬

‭if (jwtUtil.validateToken(token)) {‬
‭UsernamePasswordAuthenticationToken‬
authentication =‬

new‬

UsernamePasswordAuthenticationToken(userDetails, null,‬

userDetails.getAuthorities());‬

‭authentication.setDetails(new‬
WebAuthenticationDetailsSource().buildDetails(httpRequest));‬

‭ecurityContextHolder.getContext().setAuthentication(authentication)‬
S
;‬

‭}‬
‭}‬
‭} catch (ExpiredJwtException e) {‬
‭SecurityContextHolder.clearContext();‬
‭}‬
‭}‬
‭chain.doFilter(request, response);‬
}‬

}‬

‭Step 4: Secure API Routes in‬‭


SecurityConfig.java‬
‭Ensure that‬‭logout is protected‬‭.‬

‭java:‬
‭mport org.springframework.context.annotation.Bean;‬
i
import org.springframework.context.annotation.Configuration;‬

import‬

org.springframework.security.config.annotation.web.builders.HttpSecu‬

rity;‬

import org.springframework.security.web.SecurityFilterChain;‬

import‬

org.springframework.security.web.authentication.UsernamePasswordAuth‬

enticationFilter;‬

‭Configuration‬
@
public class SecurityConfig {‬

private final JwtFilter jwtFilter;‬


public SecurityConfig(JwtFilter jwtFilter) {‬



‭this.jwtFilter = jwtFilter;‬
}‬

‭Bean‬
@
public SecurityFilterChain securityFilterChain(HttpSecurity‬

http) throws Exception {‬

‭http.csrf().disable()‬
‭.authorizeHttpRequests()‬
‭.requestMatchers("/auth/signup",‬
"/auth/login").permitAll()‬

‭.anyRequest().authenticated()‬
‭.and()‬
‭.addFilterBefore(jwtFilter,‬
UsernamePasswordAuthenticationFilter.class);‬

‭return http.build();‬
}‬

}‬

3️⃣ Testing Logout API‬

🔹 Step 1: Sign Up a User‬

‭POST‬‭
/auth/signup‬

‭json:‬
{‬

"username": "john",‬

"password": "password123",‬

"role": "ROLE_USER"‬

}‬


‭ ‬‭Response:‬‭
"User registered successfully!"‬

🔹 Step 2: Log In to Get JWT Token‬


‭POST‬‭
/auth/login‬

‭json:‬
{‬

"username": "john",‬

"password": "password123"‬

}‬


‭ ‬‭Response:‬

‭json:‬
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."‬

🔹 Step 3: Access Protected API‬


‭ ET‬‭
G /user/profile‬
‭Header:‬
Authorization: Bearer <JWT_TOKEN>‬


‭ ‬‭Response:‬‭
"User Profile Data"‬

🔹 Step 4: Logout‬

‭ OST‬‭
P /auth/logout‬
‭Header:‬
Authorization: Bearer <JWT_TOKEN>‬


‭ ‬‭Response:‬‭
"Logout successful!"‬

🔹 Step 5: Try Accessing API Again‬


‭ ET‬‭
G /user/profile‬
‭Header:‬
Authorization: Bearer <JWT_TOKEN>‬


‭ ‬‭Response:‬‭
"Invalid Token!"‬‭(Token is blacklisted)‬

4️⃣ Alternative: Client-Side Logout‬



‭If you do‬‭not want to store blacklisted tokens‬‭, a simple alternative is‬‭client-side logout‬‭:‬

‭‬ R
● ‭ emove the token from LocalStorage or Cookies‬‭.‬
‭●‬ ‭The next request will be‬‭unauthenticated‬‭because no‬‭token is sent.‬

‭javascript:‬
‭/ Frontend Logout‬
/
localStorage.removeItem("jwtToken");‬

🔚 Conclusion‬



‭ ‬‭Implemented secure JWT login and logout‬


‭ ‬‭Blacklisted tokens on logout‬
‭ ‬‭Ensured API protection‬
‭Hiding API Keys Using‬‭
@Value‬‭in Spring Boot‬
‭To‬‭avoid hardcoding‬‭API keys in your Java code, we can store them in the‬
application.properties‬‭(or‬‭application.yml‬
‭ ‭) file and‬‭inject them using‬‭
@Value‬
‭.‬

🔹 Step 1: Store API Key in‬‭application.properties‬


‭Add your API key in‬‭


src/main/resources/application.properties‬‭:‬

‭properties:‬
api.key=your-secret-api-key‬

‭Alternatively, if using‬‭
application.yml‬‭:‬

‭yaml:‬
api:‬

key: your-secret-api-key‬

🔹 Step 2: Inject API Key Using‬‭@Value‬


‭In your Spring Boot service or configuration class:‬

‭java:‬
‭mport org.springframework.beans.factory.annotation.Value;‬
i
import org.springframework.stereotype.Service;‬

‭Service‬
@
public class ApiService {‬

‭Value("${api.key}")‬
@
private String apiKey;‬

public void makeApiCall() {‬



‭System.out.println("Using API Key: " + apiKey);‬
}‬

}‬

🔹 Step 3: Using Environment Variables (For Extra Security)‬

I‭nstead of storing the key in‬‭


application.properties‬
‭, store it as an‬‭environment‬
‭variable‬‭:‬

‭Linux/Mac (Terminal):‬
‭sh:‬
export API_KEY=your-secret-api-key‬

‭Windows (Command Prompt):‬


‭cmd:‬
set API_KEY=your-secret-api-key‬

‭Modify‬‭
application.properties‬‭to reference the‬‭environment variable‬‭:‬

‭properties:‬
api.key=${API_KEY}‬

‭ ow,‬‭
N @Value("${api.key}")‬‭will automatically fetch‬‭the‬‭API key from the environment‬
‭variable‬‭, keeping it secure.‬

🔹 Step 4: Using‬‭@ConfigurationProperties‬‭(For Multiple Values)‬


‭For multiple API-related properties, use‬‭


@ConfigurationProperties‬‭:‬

‭java:‬
‭mport‬
i
org.springframework.boot.context.properties.ConfigurationProperties;‬

import org.springframework.stereotype.Component;‬

‭Component‬
@
@ConfigurationProperties(prefix = "api")‬

public class ApiConfig {‬

private String key;‬

‭ublic String getKey() { return key; }‬


p
public void setKey(String key) { this.key = key; }‬

}‬

‭Then, inject it into your service:‬

‭java:‬
import org.springframework.stereotype.Service;‬

‭Service‬
@
public class ApiService {‬

private final ApiConfig apiConfig;‬

public ApiService(ApiConfig apiConfig) {‬



‭this.apiConfig = apiConfig;‬
}‬

public void makeApiCall() {‬



‭System.out.println("Using API Key: " + apiConfig.getKey());‬
}‬

}‬

🔹 Best Practices‬


‭ ‬‭Never commit‬‭
application.properties‬‭with sensitive data‬‭(use‬‭
.gitignore‬
‭).‬
‭✅‬‭Use environment variables‬‭(‬‭API_KEY‬
‭✅‬‭Use Spring Cloud Config‬‭or‬‭Secrets Manager‬‭for highly sensitive keys.‬
‭) in production‬‭for extra security.‬
‭ nderstanding‬‭
U @PostConstruct‬‭and Application Caching in Spring‬
‭Boot‬

1️⃣
‭ ‬‭
@PostConstruct‬‭Annotation in Spring Boot‬
📌 What is‬‭@PostConstruct‬‭?‬

‭●‬ @PostConstruct‬‭is a‬‭lifecycle callback‬‭method that is executed‬‭after‬‭the‬



‭ ependency injection is done and‬‭before‬‭the class‬‭is put into service.‬
d
‭ ‬ ‭It is used for‬‭initialization logic‬‭that needs to run once when the Spring Bean is‬

‭created.‬

📌 Example Use Case‬


‭‬ L
● ‭ oading cache‬‭on application startup‬
‭●‬ ‭Initializing resources‬
‭●‬ ‭Logging application startup details‬

📝 Example: Using‬‭@PostConstruct‬‭to Load Data at Startup‬



‭java:‬
‭mport jakarta.annotation.PostConstruct;‬
i
import org.springframework.stereotype.Component;‬

import java.util.*;‬

‭Component‬
@
public class DataInitializer {‬

‭rivate static final Map<Integer, String> countryCache = new‬


p
HashMap<>();‬

‭PostConstruct‬
@
public void init() {‬

‭// Simulating fetching data from a database or API‬
‭countryCache.put(1, "India");‬
‭countryCache.put(2, "USA");‬
‭countryCache.put(3, "Germany");‬
‭System.out.println(" ✅
Country Cache Initialized: " +‬
countryCache);‬

}‬

public String getCountryById(int id) {‬



‭return countryCache.get(id);‬
}‬

}‬

‭●‬ T ‭ he‬‭
init()‬‭method will run once when the application starts and pre-loads the‬
‭cache‬‭.‬
‭●‬ ‭The cache can then be used‬‭without making a database‬‭call‬‭.‬

2️⃣ Application Caching in Spring Boot‬



📌 What is Caching?‬

‭ aching‬‭improves performance‬‭by‬‭storing frequently used data in memory‬‭so that the‬


C
‭system does not need to fetch it from the database or API every time.‬

📌 Spring Boot Supports Multiple Caching Mechanisms:‬




‭ ‬‭In-Memory Caching‬‭– Simple Java HashMap‬
‭ ‬‭Spring Cache Abstraction‬‭–‬‭
@Cacheable‬ ‭,‬‭
@CacheEvict‬

‭ ‬‭EhCache, Redis, Hazelcast‬‭– For distributed caching‬

📝 Example: Using‬‭@Cacheable‬‭for Method-Level Caching‬


‭Spring Boot provides built-in caching using the‬‭


@Cacheable‬‭annotation.‬

1️⃣ Enable Caching in Spring Boot‬



‭java:‬
‭mport org.springframework.cache.annotation.EnableCaching;‬
i
import org.springframework.context.annotation.Configuration;‬

‭Configuration‬
@
@EnableCaching‬

public class CacheConfig {‬

// Enables Spring's caching mechanism‬

}‬

2️⃣ Use‬‭@Cacheable‬‭in a Service‬



‭java:‬
import org.springframework.cache.annotation.Cacheable;‬

import org.springframework.stereotype.Service;‬

‭Service‬
@
public class CountryService {‬

‭Cacheable("countries")‬
@
public String getCountryById(int id) {‬

‭System.out.println("Fetching country from DB...");‬
‭return switch (id) {‬
‭case 1 -> "India";‬
‭case 2 -> "USA";‬
‭case 3 -> "Germany";‬
‭default -> "Unknown";‬
‭};‬
}‬

}‬

‭‬ T
● ‭ he first time‬‭
getCountryById(1)‬‭is called, it‬‭fetches from DB‬‭.‬
‭●‬ ‭The‬‭next time‬‭, the‬‭cached result is used‬‭instead of fetching again.‬

3️⃣ Clearing Cache Using‬‭@CacheEvict‬


‭To‬‭remove cache‬‭when data is updated:‬

‭java:‬
‭mport org.springframework.cache.annotation.CacheEvict;‬
i
import org.springframework.stereotype.Service;‬

‭Service‬
@
public class CountryService {‬

‭CacheEvict(value = "countries", allEntries = true)‬


@
public void updateCountry(int id, String country) {‬

‭System.out.println("Updating country...");‬
}‬

}‬

3️⃣ Using Redis for Distributed Caching‬

‭ or large applications,‬‭Redis‬‭is preferred because it supports‬‭persistent and distributed‬
F
‭caching‬‭.‬

1️⃣ Add Redis Dependency in‬‭pom.xml‬



‭xml:‬
<dependency>‬

<groupId>org.springframework.boot</groupId>‬

<artifactId>spring-boot-starter-data-redis</artifactId>‬

</dependency>‬

2️⃣ Configure Redis in‬‭application.properties‬



‭properties:‬
‭pring.redis.host=localhost‬
s
spring.redis.port=6379‬

3️⃣ Define a Redis Configuration Class‬



‭java:‬
‭mport org.springframework.context.annotation.Bean;‬
i
import org.springframework.context.annotation.Configuration;‬

import org.springframework.data.redis.cache.RedisCacheConfiguration;‬

import org.springframework.data.redis.cache.RedisCacheManager;‬

import‬

org.springframework.data.redis.connection.lettuce.LettuceConnectionF‬

actory;‬

import‬

org.springframework.data.redis.connection.RedisConnectionFactory;‬

import org.springframework.data.redis.serializer.*;‬

import java.time.Duration;‬

‭Configuration‬
@
@EnableCaching‬

public class RedisConfig {‬

‭Bean‬
@
public RedisConnectionFactory redisConnectionFactory() {‬

‭return new LettuceConnectionFactory();‬
}‬

‭Bean‬
@
public RedisCacheManager cacheManager(RedisConnectionFactory‬

redisConnectionFactory) {‬

‭RedisCacheConfiguration config =‬
RedisCacheConfiguration.defaultCacheConfig()‬

‭.entryTtl(Duration.ofMinutes(10)) // Cache expiry‬
time‬

‭.disableCachingNullValues()‬

‭serializeKeysWith(RedisSerializationContext.SerializationPair.fromS‬
.
erializer(new StringRedisSerializer()))‬

‭serializeValuesWith(RedisSerializationContext.SerializationPair.fro‬
.
mSerializer(new GenericJackson2JsonRedisSerializer()));‬

‭return RedisCacheManager.builder(redisConnectionFactory)‬
‭.cacheDefaults(config)‬
‭.build();‬
}‬

}‬

4️⃣ Use Redis Caching in a Service‬



‭java:‬
‭mport org.springframework.cache.annotation.Cacheable;‬
i
import org.springframework.stereotype.Service;‬

‭Service‬
@
public class CountryService {‬

‭Cacheable(value = "countries", key = "#id")‬


@
public String getCountryById(int id) {‬

‭System.out.println("Fetching from database...");‬
‭return switch (id) {‬
‭case 1 -> "India";‬
‭case 2 -> "USA";‬
‭case 3 -> "Germany";‬
‭default -> "Unknown";‬
‭};‬
}‬

}‬

✅ Summary‬

‭Feature‬ ‭Description‬

‭PostConstru‬ R
@ ‭ uns once after Spring initializes a‬
ct‬
‭ ‭Bean‬

‭Caching‬ ‭Stores frequently used data in memory‬

@Cacheable‬
‭ ‭Enables method-level caching‬

@CacheEvict‬
‭ ‭Removes cache when data updates‬

‭Redis Cache‬ ‭Distributed caching for better scalability‬

You might also like