Spring Boot
Complete Study Guide
Security • JPA • Relationships • Validation • Starters • Configuration • Spring
MVC
Mohamed Alouani
Production-Ready Spring Boot Development
Spring Spring JPA
Security Data JPA Entity Bean Vali
■ & JWT
■ & Reposi ■ Relations dation
Auth
■ tories hips
■ (JSR 380)
Configur Spring
Spring ation MVC
Boot
■ & ■ REST
■ Starters
■ Profiles APIs
Spring Boot Complete Study Guide • Mohamed Alouani • 2024
Spring Boot Complete Guide Mohamed Alouani
Table of Contents
1. Spring Security & JWT Authentication
› Why Application Security Matters
› Web Security Threats
› Authentication vs Authorization
› Session vs JWT Token Authentication
› Spring Security Architecture
› SecurityFilterChain, AuthenticationManager, UserDetailsService
2. Spring Data JPA & Repositories
› What is JpaRepository?
› CRUD Operations (Save, Find, Delete)
› JPA Naming Method Conventions
› Custom Queries with @Query
› Native SQL & Modifying Queries
› Avoiding the N+1 Problem
3. Bean Validation (JSR 380)
› Core Validation Annotations
› Nullity, Strings, Numeric, Boolean, Date Constraints
› Cascading Validation with @Valid
› Handling Errors with BindingResult
4. Spring Boot Starters
› What are Starters?
› Web, JPA, Security, Test Starters
› Other Useful Starters
5. Spring Boot Configuration
› [Link] vs [Link]
› External Configuration & Priority
› Profiles (@Profile)
› @Value & @ConfigurationProperties
6. Spring Boot Components Overview
› @Component, @Service, @Repository, @Controller
› Dependency Injection & IoC
› Application Context Lifecycle
7. JPA Entity Relationships
› One-to-One (Unidirectional & Bidirectional)
› One-to-Many / Many-to-One
› Many-to-Many with Join Table
› Fetch Types: EAGER vs LAZY
› Cascade Types & OrphanRemoval
8. Web Development with Spring MVC
› Creating REST APIs with @RestController
› Request Parameters: @PathVariable, @RequestParam, @RequestBody
› ResponseEntity & HTTP Status Codes
› Exception Handling Best Practices
Page 2
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 1
Spring Security & JWT Authentication
Securing REST APIs with stateless, scalable token-based auth
1.1 Why Application Security Matters
Security is not optional in modern API development. Every exposed endpoint is a potential attack surface —
protecting user data, preventing unauthorized access, ensuring compliance, and enabling microservices
boundaries all depend on a solid security foundation.
Safeguard sensitive Enforce strict controls so ■ industry
Meet regulations
Microservices Every service bo
■ Prevent
credentials and personal only■verified
Trust users
& Compliance
reach andReady
build user confidence. a potential attack
Unauthorized
information from Access your resources.
■ Protect User Data breaches.
1.2 Web Security Threats
■ Authentication Attacks: Brute force and credential stuffing exploit weak or reused passwords to gain
unauthorized entry.
■ Session Hijacking: Attackers steal or manipulate session tokens to impersonate authenticated users.
■ CSRF & XSS: Cross-site attacks trick users or inject malicious scripts to compromise data and sessions.
■ API Enumeration: Exposing predictable endpoints allows attackers to map your API surface and probe for
vulnerabilities.
1.3 Authentication vs Authorization
Authentication (Who are you?) Authorization (What can you access?)
• Verifies the identity of the requester • Controls which resources a verified user can access
• User provides credentials (username/password) • Happens after authentication succeeds
• Example: Logging in with email and password • Example: Admin accessing the admin dashboard
• Produces a security principal • Checks authorities/roles against resource rules
■ Rule: Authentication must always precede Authorization. Spring Security handles both within its filter chain.
1.4 Session-Based vs JWT Authentication
Page 3
Spring Boot Complete Guide Mohamed Alouani
Traditional session-based authentication keeps state on the server. JWT (JSON Web Token, RFC 7519) moves
that state into a self-contained token carried by the client, enabling true statelessness.
Property Session-Based JWT Token
State Stateful Stateless
Token Storage Stored on server Stored on client
Scalability Hard to scale horizontally Scales easily across instances
Server Memory Grows with active users Lightweight — no server state
Infrastructure Requires session store (Redis) No server-side storage needed
Revocation Easy (delete session) Requires token blacklist or short TTL
JWT Structure: [Link]
HEADER PAYLOAD SIGNATURE
Algorithm + token type Claims: sub, roles, iat, exp HMACSHA256(base64(header) +
{"alg": "HS256", "typ": . {"sub": "user@[Link]", . "." + base64(payload),
"JWT"} "roles": ["ADMIN"]} secret)
1.5 Spring Security Architecture
Spring Security is built on top of the Servlet Filter Chain. Every HTTP request passes through an ordered pipeline of
security filters before reaching your application logic.
AuthenticationMa
SecurityFilterCha UserDetailsServi AuthenticationPr
nager
HTTP Request in ce ovider
Incoming client → Ordered filter → Coordinates → Loads user from → Validates
authentication,
request pipeline, intercepts database by credentials, returns
delegates to
all requests username Auth token
providers
SecurityFilterChain
The SecurityFilterChain is the entry point for all HTTP requests. It's a series of [Link]
instances executing in predefined order. Key filters include:
• UsernamePasswordAuthenticationFilter — handles form-based login
• JwtAuthenticationFilter (custom) — validates JWT tokens on each request
• ExceptionTranslationFilter — converts security exceptions to HTTP responses
• FilterSecurityInterceptor — enforces access control rules
UserDetailsService & Password Encoding
UserDetailsService is the bridge between your authentication mechanism and user storage. It loads a
UserDetails object containing username, hashed password, and authorities.
Interface / Class Purpose
UserDetailsService Contract for loading user by username
Page 4
Spring Boot Complete Guide Mohamed Alouani
Interface / Class Purpose
UserDetails Holds username, password, authorities, account status flags
BCryptPasswordEncoder Recommended password hasher (adaptive cost factor)
PBKDF2PasswordEncoder Standards-compliant alternative for regulated environments
GrantedAuthority Represents a permission or role (e.g., ROLE_ADMIN)
■ ■ Best Practice: Passwords must NEVER be stored in plain text. Always use BCryptPasswordEncoder or
a comparable adaptive hashing algorithm with a work factor >= 12.
Page 5
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 2
Spring Data JPA & Repositories
Elegant data access without writing boilerplate SQL
2.1 Introduction
Spring Data JPA simplifies database interaction by providing the JpaRepository interface with built-in CRUD
operations, query derivation from method names, and support for custom @Query annotations — all without writing
explicit SQL in most cases.
2.2 Repository Hierarchy
Spring Data provides a layered set of repository interfaces. Each extends the previous, adding more capabilities:
CrudRepository<T,ID> Basic save, findById, delete operations
PagingAndSortingRepository + Pagination and Sorting support
JpaRepository<T,ID> + Batch ops, flush, JPQL, findAll(Example)
Declaration: public interface UserRepository extends JpaRepository<User, Long> { }
2.3 Default JpaRepository Methods
Persisting Methods
Method Return Type Description
save(entity) S extends T Insert or update (merge if ID exists)
saveAll(Iterable<T>) List<T> Batch save, returns updated list
saveAndFlush(entity) T Save and immediately flush to DB
Retrieval Methods
Method Return Type Description
findById(id) Optional<T> Returns entity wrapped in Optional
findAll() List<T> Returns all entities
findAllById(ids) List<T> Returns entities for given ID list
existsById(id) boolean True if entity with ID exists
Page 6
Spring Boot Complete Guide Mohamed Alouani
Method Return Type Description
count() long Total number of records
Deletion Methods
Method Description
delete(entity) Deletes a specific entity instance
deleteById(id) Deletes by primary key
deleteAll() Deletes all records (use with caution)
deleteAllInBatch(entities) Single DELETE statement for performance
2.4 JPA Naming Method Conventions
Spring Data JPA interprets method names and auto-generates the corresponding JPQL query at runtime. No
implementation needed.
Method Name Generated JPQL (approximate)
findByFirstName(String n) WHERE [Link] = :n
findByEmailAndActive(String e, boolean a) WHERE [Link] = :e AND [Link] = :a
findByAgeBetween(int min, int max) WHERE [Link] BETWEEN :min AND :max
findByNameContaining(String s) WHERE [Link] LIKE '%:s%'
findByActiveOrderByLastNameAsc() WHERE [Link] = true ORDER BY lastName ASC
countByDepartment(String dept) SELECT COUNT(u) WHERE [Link] = :dept
SELECT CASE WHEN COUNT(u)>0 THEN true ELSE
existsByEmail(String e) false END WHERE [Link] = :e
deleteByStatus(String status) DELETE WHERE [Link] = :status
2.5 Custom Queries with @Query
When method naming conventions are insufficient for complex queries, use @Query to define JPQL or native SQL
directly on the repository method.
JPQL Query
@Query("SELECT u FROM User u WHERE [Link] > :minSalary AND [Link] = :dept")
List<User> findHighEarners(@Param("minSalary") double salary, @Param("dept") String dept);
Native SQL Query
@Query(value = "SELECT * FROM users WHERE email = :email", nativeQuery = true)
Optional<User> findByEmailNative(@Param("email") String email);
Modifying Query (UPDATE/DELETE)
@Modifying
@Transactional
Page 7
Spring Boot Complete Guide Mohamed Alouani
@Query("UPDATE User u SET [Link] = false WHERE [Link] < :cutoff")
int deactivateInactiveUsers(@Param("cutoff") LocalDate cutoff);
JOIN FETCH (Avoid N+1)
@Query("SELECT u FROM User u JOIN FETCH [Link] WHERE [Link] = :id")
Optional<User> findWithOrders(@Param("id") Long id);
■ N+1 Problem: Without JOIN FETCH, Hibernate executes 1 query to load Users + N additional queries for
their Orders. Always use JOIN FETCH or @EntityGraph for associations loaded eagerly.
Page 8
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 3
Bean Validation (JSR 380)
Ensuring data integrity at the API boundary
3.1 Introduction
Spring Boot uses Jakarta Bean Validation (JSR 380) with Hibernate Validator as the default implementation.
Validation ensures that incoming data respects business rules before any processing occurs — eliminating corrupt
state early.
3.2 Core Validation Annotations
Nullity Constraints
Annotation Constraint Description
@NotNull Value must not be null
@Null Value must be null
String Constraints
Annotation Constraint Description
@NotEmpty Not null and not empty string
@NotBlank Not null, not empty, not only whitespace
@Size(min=, max=) String length must be within bounds
@Pattern(regexp=) Must match regular expression
@Email Must be a valid email address format
Numeric Constraints
Annotation Constraint Description
@Min(value) Numeric value >= minimum
@Max(value) Numeric value <= maximum
@DecimalMin(value) BigDecimal >= minimum string value
@DecimalMax(value) BigDecimal <= maximum string value
@Digits(integer=, fraction=) Max digits in integer and fractional parts
Page 9
Spring Boot Complete Guide Mohamed Alouani
Annotation Constraint Description
@Positive Value must be > 0
@Negative Value must be < 0
@PositiveOrZero Value must be >= 0
@NegativeOrZero Value must be <= 0
Boolean Constraints
Annotation Constraint Description
@AssertTrue Value must be true
@AssertFalse Value must be false
Date / Time Constraints
Annotation Constraint Description
@Past Date must be in the past
@PastOrPresent Date must be past or current
@Future Date must be in the future
@FutureOrPresent Date must be present or future
3.3 Repeatable Annotations (.List)
Some constraints can be applied multiple times on the same field using their container annotation:
• @[Link]({ @Pattern(regexp="..."), @Pattern(regexp="...") })
• @[Link] — apply different messages per group
3.4 Cascading Validation with @Valid
When a DTO contains nested objects, annotate the nested field with @Valid to trigger recursive validation:
public class OrderDTO {
@Valid
@NotNull
private AddressDTO shippingAddress; // validates AddressDTO constraints too
}
3.5 Activating Validation in Controllers
Add @Valid or @Validated before the request body parameter to trigger validation automatically:
@PostMapping("/users")
public ResponseEntity<User> create(@Valid @RequestBody UserDTO dto) {
// Only reached if validation passes
return [Link]([Link](dto));
}
Page 10
Spring Boot Complete Guide Mohamed Alouani
3.6 Handling Validation Errors with BindingResult
BindingResult must be placed immediately after the validated parameter. It captures constraint violations
without throwing an exception:
@PostMapping("/users")
public ResponseEntity<?> create(@Valid @RequestBody UserDTO dto, BindingResult result) {
if ([Link]()) {
List<String> errors = [Link]()
.stream()
.map(e -> [Link]() + ": " + [Link]())
.collect([Link]());
return [Link]().body(errors); // 400 Bad Request
}
return [Link]([Link](dto));
}
✓ Result: When validation fails, the client receives a 400 Bad Request response containing a list of
field-level error messages — no uncaught exceptions.
Page 11
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 4
Spring Boot Starters
Pre-packaged dependencies for rapid application setup
4.1 What are Starters?
A Starter is a curated set of Maven/Gradle dependencies bundled into a single module. Starters eliminate manual
dependency management, ensure compatible library versions, and provide auto-configuration out of the box.
4.2 Core Starters
Build web applications & RESTful APIs
spring-boot-starter-web Spring MVC • Jackson (JSON binding) • Embedded Apache Tomcat
Data access with relational databases
spring-boot-starter-data-jpa Spring Data JPA • Hibernate ORM • Spring ORM
Authentication & authorization
Spring Security • Secures all endpoints by default • CSRF protection
spring-boot-starter-security included
Unit and integration testing
spring-boot-starter-test JUnit 5 • Mockito • Spring Test (MockMvc) • AssertJ
Bean validation (JSR 380)
spring-boot-starter-validation Jakarta Validation API • Hibernate Validator
4.3 Other Useful Starters
Starter Purpose
spring-boot-starter-thymeleaf Server-side HTML template rendering
spring-boot-starter-mail Sending emails via JavaMailSender
spring-boot-starter-actuator Production monitoring: health, metrics, info endpoints
spring-boot-starter-cache Spring Cache abstraction (Caffeine, Redis)
spring-boot-starter-aop Aspect-Oriented Programming with AspectJ
spring-boot-starter-websocket WebSocket support for real-time communication
Page 12
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 5
Spring Boot Configuration
Externalizing and managing application behavior across environments
5.1 [Link] vs [Link]
Spring Boot supports two configuration file formats. Both are equivalent in capability — choose based on your
team's readability preference:
[Link] [Link]
• Key=value flat format • Hierarchical, indentation-based
• Less readable for nested configs • More readable for grouped configs
• [Link]=8080 • server:\n port: 8080
• Simpler for single values • Better for complex configurations
• [Link]=jdbc:... • spring:\n datasource:\n url: jdbc:...
5.2 Configuration Priority (High → Low)
1—
Highest Command-line arguments --[Link]=9090
2 Environment variables SERVER_PORT=9090
3 Profile-specific files [Link]
4 — Default [Link] / yml Default file-based config
5.3 Spring Profiles
Profiles let you define environment-specific configurations without changing source code. Create separate property
files per environment:
• [Link] — local dev (H2, debug logging)
• [Link] — CI/CD testing environment
• [Link] — production (PostgreSQL, minimal logging)
Activating Profiles
Page 13
Spring Boot Complete Guide Mohamed Alouani
Method Example
[Link] [Link]=dev
Environment variable SPRING_PROFILES_ACTIVE=prod
CLI argument java -jar [Link] --[Link]=prod
@Profile annotation (Bean) @Profile("dev") — bean only active in dev
5.4 Property Injection
@Value (Individual Values) @ConfigurationProperties (Groups)
• Injects single property values • Maps a group of related properties to a POJO
• Lightweight and direct • Cleaner for structured / hierarchical configs
• @Value("${[Link]}") private int port; • @ConfigurationProperties(prefix="app") public
class AppConfig { String name; }
• Throws at startup if property missing • Supports relaxed binding and JSR-303 validation
• Best for 1-3 properties • Best for 4+ related properties
■ Pro Tip: Prefer @ConfigurationProperties over @Value for structured configs. It supports type-safe
injection, IDE completion, and integrates with @Validated for constraint checks on config values.
Page 14
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 6
Spring Boot Core Components
Understanding the IoC container, beans, and stereotypes
6.1 Inversion of Control & Dependency Injection
Spring's IoC container manages object creation and lifecycle. Instead of your code creating dependencies (new
Service()), the container injects them. This decouples components and dramatically improves testability.
6.2 Stereotype Annotations
These annotations mark classes as Spring-managed beans and communicate their architectural role:
@Component Generic spring-managed bean. Base for all stereotypes.
@Service Business logic layer. Semantically communicates service role.
@Repository Data access layer. Adds exception translation for persistence errors.
@Controller Web layer. Handles HTTP requests (returns views for MVC).
@RestController @Controller + @ResponseBody. Returns JSON/XML directly.
@Configuration Contains @Bean definitions. Replaces XML applicationContext.
6.3 Dependency Injection Types
Type Example When to Use
Constructor Injection (✓ @Autowired on constructor (implicit in Always — promotes immutability
Recommended) Spring 4.3+) & testability
Setter Injection @Autowired on setter method Optional dependencies only
Avoid — hides dependencies,
Field Injection (✗ Avoid) @Autowired directly on field
breaks testing
Constructor Injection Example (Preferred)
@Service
public class OrderService {
Page 15
Spring Boot Complete Guide Mohamed Alouani
private final UserRepository userRepo; // immutable
private final EmailService emailService;
// @Autowired optional since Spring 4.3 for single constructor
public OrderService(UserRepository userRepo, EmailService emailService) {
[Link] = userRepo;
[Link] = emailService;
}
}
6.4 Application Context & Bean Lifecycle
The ApplicationContext is the Spring IoC container. It loads bean definitions, manages their lifecycle, and handles
dependency wiring:
Parse Create bean Resolve and
@Configuration instances inject all
classes and (constructor
3. Injector dependencies
component
2. Instantiate factory)
1. Load scan paths
Run Bean [Link] Cleanup before
initialization initialized
@PreDestroyand context closes
4. @PostCon methods after
5. Ready in service
struct injection
■ Summary: Spring Boot combines powerful auto-configuration, a rich ecosystem of starters, and
battle-tested security/data patterns to let developers focus on business logic. Master the IoC container, filter
chain security, JPA repositories, validation constraints, and profile-based configuration — and you'll be
building production-grade microservices with confidence.
Page 16
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 7
JPA Entity Relationships
Mapping real-world associations between database entities
7.1 Overview of Relationship Types
Relational databases model structured data in tables, and applications must reflect associations between those
tables. JPA provides four core relationship annotations that map directly to database foreign keys and join tables.
Relationship Annotation Real-World Example FK Location
One-to-One @OneToOne User has one Profile Owner side table
One-to-Many @OneToMany User has many Orders Child table (Orders)
Many-to-One @ManyToOne Order belongs to one User Owner table (Orders)
Many-to-Many @ManyToMany Student enrolls in many Courses Join table
7.2 One-to-One Relationship
A One-to-One relationship means one entity instance is associated with exactly one instance of another. Example:
a User has exactly one Profile.
Unidirectional (User -> Profile) Bidirectional (User <-> Profile)
• Only User knows about Profile • Both User and Profile reference each other
• Profile has no link back to User • Profile has @OneToOne(mappedBy="profile")
• Simpler — no mappedBy needed • Requires mappedBy on the inverse side
• No risk of infinite JSON loops • Must use @JsonManagedReference /
@JsonBackReference
• Use when navigation is one-way • Use when both sides need to navigate
Bidirectional One-to-One Example
// OWNER SIDE (holds the foreign key)
@Entity
public class User {
@OneToOne
@JoinColumn(name = "profile_id") // FK: user.profile_id -> [Link]
private Profile profile;
Page 17
Spring Boot Complete Guide Mohamed Alouani
}
// INVERSE SIDE (no FK here)
@Entity
public class Profile {
@OneToOne(mappedBy = "profile") // Managed by User side
private User user;
}
7.3 One-to-Many / Many-to-One Relationship
The most common relationship pattern. A User can have many Orders; each Order belongs to one User. The
foreign key always lives on the Many side (Orders table).
Order (N)
User (1) user_id FK
→ → Many side — @ManyToOne
One side — @OneToMany Foreign key in orders table
(OWNER)
// MANY SIDE — owns the foreign key (OWNER)
@Entity
public class Order {
@ManyToOne
@JoinColumn(name = "user_id") // FK column in orders table
private User user;
}
// ONE SIDE — navigation only (INVERSE)
@Entity
public class User {
@OneToMany(mappedBy = "user") // No extra table generated
private List<Order> orders;
}
■ Important: Never use @OneToMany alone (without the @ManyToOne side). Hibernate will generate an
unnecessary join table (e.g. users_orders) which degrades performance. Always define @ManyToOne as
the owning side with the foreign key.
7.4 Many-to-Many Relationship
Multiple entities on both sides are associated with multiple on the other. Example: a Student can enroll in many
Courses; a Course can have many Students. JPA always generates a join table.
// OWNER SIDE
@Entity
public class Student {
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
Page 18
Spring Boot Complete Guide Mohamed Alouani
private List<Course> courses;
}
// INVERSE SIDE
@Entity
public class Course {
@ManyToMany(mappedBy = "courses")
private List<Student> students;
}
Generated join table: student_course(student_id FK, course_id FK)
7.5 Fetch Types: EAGER vs LAZY
Fetch strategy controls WHEN associated entities are loaded from the database. Choosing wrong can cause
significant performance problems.
EAGER Loading (Immediate) LAZY Loading (On-Demand)
• Loads associated entities immediately • Loads associations only when accessed
• Default for @OneToOne and @ManyToOne • Default for @OneToMany and @ManyToMany
• Safe — no LazyInitializationException • Risk of LazyInitializationException outside session
• Can cause N+1 if misused in lists • Efficient — only loads what you actually use
• fetch = [Link] • fetch = [Link]
// LAZY — recommended for collections
@ManyToOne(fetch = [Link])
@JoinColumn(name = "user_id")
private User user;
// Use JOIN FETCH to avoid N+1 with LAZY
@Query("SELECT o FROM Order o JOIN FETCH [Link] WHERE [Link] = :status")
List<Order> findByStatusWithUser(@Param("status") String status);
7.6 Cascade Types & OrphanRemoval
Cascade propagates lifecycle operations from parent to child entities. OrphanRemoval deletes child entities
automatically when removed from the parent collection.
CascadeType Effect
PERSIST Saving parent automatically saves all children
MERGE Updating parent automatically merges all children
REMOVE Deleting parent automatically deletes all children
REFRESH Refreshing parent also refreshes all children from DB
DETACH Detaching parent also detaches all children
ALL All of the above combined
Page 19
Spring Boot Complete Guide Mohamed Alouani
[Link] orphanRemoval = true
• Triggered when PARENT is deleted • Triggered when child is REMOVED from collection
• DELETE FROM orders WHERE user_id=? • DELETE FROM orders WHERE id=?
• DELETE FROM users WHERE id=? • Parent (User) still exists
• Use: delete parent + all its children • Use: removing a single child from a list
// orphanRemoval example
@Entity
public class User {
@OneToMany(mappedBy = "user", cascade = [Link], orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
}
// When you do this, the removed order is DELETE'd from DB automatically:
[Link]().remove(order); // triggers DELETE FROM orders WHERE id=?
[Link](user);
■ Best Practice: Use cascade = [Link] with orphanRemoval = true on parent-owned
collections (e.g., Order items). Avoid [Link] on @ManyToMany — it would delete shared
entities used by other parents.
Page 20
Spring Boot Complete Guide Mohamed Alouani
CHAPTER 8
Web Development with Spring MVC
Building RESTful APIs: controllers, parameters, and responses
8.1 Spring MVC Overview
Spring Boot supports full-stack web development through Spring MVC. It uses the DispatcherServlet as a front
controller, routing incoming HTTP requests to the appropriate @Controller or @RestController method based on
URL mappings.
Client HTTP DispatcherServle HandlerMapping Controller ResponseEntity
Request t Method
→ → Finds the correct
→ → Builds HTTP
Browser / Postman / Front controller — @RestController Executes business response with status
Frontend routes all requests method logic + body
8.2 Creating REST APIs with @RestController
@RestController combines @Controller + @ResponseBody. Every method return value is automatically
serialized to JSON and written to the HTTP response — no view resolution.
Annotation HTTP Method Typical Use
@GetMapping("/path") GET Retrieve resource(s)
@PostMapping("/path") POST Create a new resource
@PutMapping("/path/{id}") PUT Update entire resource
@PatchMapping("/path/{id}") PATCH Partial update of resource
@DeleteMapping("/path/{id}") DELETE Remove a resource
@RestController
@RequestMapping("/api/users") // Base path for all methods
public class UserController {
@GetMapping
public List<User> getAll() { return [Link](); }
@PostMapping
public ResponseEntity<User> create(@Valid @RequestBody UserDTO dto) {
User created = [Link](dto);
return [Link]([Link]).body(created);
}
}
Page 21
Spring Boot Complete Guide Mohamed Alouani
8.3 Handling Request Parameters
Spring MVC provides three main annotations for extracting data from HTTP requests:
Annotation Source Example URL / Usage
@PathVariable URL segment /users/{id} GET /users/42 -> Long id = 42
@RequestParam Query string ?key=value GET /users?role=admin -> String role
@RequestBody Request JSON/XML body POST /users with JSON body -> UserDTO dto
@PathVariable Example
@GetMapping("/{id}")
public ResponseEntity<User> getById(@PathVariable Long id) {
return [Link](id)
.map(ResponseEntity::ok)
.orElse([Link]().build());
}
// URL: GET /api/users/42
@RequestParam Example
@GetMapping("/search")
public List<User> search(
@RequestParam String role,
@RequestParam(defaultValue = "0") int page) {
return [Link](role, page);
}
// URL: GET /api/users/search?role=admin&page;=0
@RequestBody Example
@PostMapping
public ResponseEntity<User> create(@Valid @RequestBody UserDTO dto) {
// dto is deserialized from JSON body automatically by Jackson
User saved = [Link](dto);
return [Link]([Link]).body(saved);
}
// Body: { "name": "Alice", "email": "alice@[Link]" }
8.4 ResponseEntity & HTTP Status Codes
ResponseEntity<T> gives full control over the HTTP response: status code, headers, and body. It is the
recommended return type for REST endpoints.
Status Code HttpStatus Constant Typical Use Case
200 OK [Link] Successful GET, PUT, PATCH
201 Created [Link] Successful POST — new resource created
Page 22
Spring Boot Complete Guide Mohamed Alouani
Status Code HttpStatus Constant Typical Use Case
204 No Content HttpStatus.NO_CONTENT Successful DELETE — no body returned
400 Bad Request HttpStatus.BAD_REQUEST Validation error, malformed request
401 Unauthorized [Link] Missing or invalid authentication
403 Forbidden [Link] Authenticated but insufficient permissions
404 Not Found HttpStatus.NOT_FOUND Resource does not exist
409 Conflict [Link] Duplicate resource (e.g. email already exists)
500 Internal HttpStatus.INTERNAL_SERVER_ER
Unhandled server-side exception
Server Error ROR
ResponseEntity Builder Pattern
// Pattern 1: Static factory methods
return [Link](user); // 200 + body
return [Link](location).body(user); // 201 + Location header
return [Link]().build(); // 204 no body
return [Link]().build(); // 404 no body
return [Link]().body(errorMessage); // 400 + body
// Pattern 2: Full control
return ResponseEntity
.status([Link])
.header("X-Custom-Header", "value")
.body(createdUser);
8.5 Global Exception Handling with @ControllerAdvice
Instead of try/catch in every controller, use @ControllerAdvice with @ExceptionHandler to centralize error
handling across the entire application:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
ErrorResponse err = new ErrorResponse(404, [Link]());
return [Link](HttpStatus.NOT_FOUND).body(err);
}
@ExceptionHandler([Link])
public ResponseEntity<Map<String, String>> handleValidation(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
[Link]().getFieldErrors()
.forEach(e -> [Link]([Link](), [Link]()));
return [Link]().body(errors); // 400
}
}
Page 23
Spring Boot Complete Guide Mohamed Alouani
✓ Complete REST Layer Pattern: @RestController handles routing -> @Valid triggers Bean Validation ->
@ControllerAdvice catches exceptions globally -> ResponseEntity controls the HTTP response precisely.
This separation of concerns makes your REST layer clean, testable, and maintainable.
Spring Boot Complete Study Guide — Mohamed Alouani — 2024
Page 24