Skip to content

Latest commit

Β 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›’ Shopping Cart Backend System

Java Spring Boot Maven MySQL License GitHub stars

πŸ“‹ Table of Contents

πŸ“– About The Project

Shopping Cart Backend System is a production-ready e-commerce backend solution built with Spring Boot. It provides a complete set of RESTful APIs for managing products, shopping carts, orders, and users. This project demonstrates best practices in software development including layered architecture, DTO pattern, exception handling, and clean code principles.

Purpose

  • βœ… Demonstrate expertise in Java Spring Boot development
  • βœ… Showcase RESTful API design and implementation
  • βœ… Implement real-world e-commerce functionality
  • βœ… Follow industry best practices and design patterns

✨ Key Features

Core Functionality

Feature Description Status
User Management Registration, authentication, profile management βœ…
Product Management CRUD operations with category support βœ…
Shopping Cart Add/remove items, update quantities βœ…
Order Processing Place orders, track order status βœ…
Image Upload Product image management βœ…
Category Management Product categorization βœ…

Technical Features

  • πŸ”„ RESTful APIs with proper HTTP methods and status codes
  • πŸ“¦ DTO Pattern for data transfer between layers
  • πŸ—„οΈ Spring Data JPA for database operations
  • 🚨 Global Exception Handling with meaningful error messages
  • πŸ“ Structured Logging for debugging and monitoring
  • πŸ”Œ Layered Architecture (Controller β†’ Service β†’ Repository)
  • πŸ’‰ Dependency Injection using Spring IoC container
  • πŸ§ͺ Comprehensive Unit & Integration Testing with JUnit 5 and Mockito
  • πŸ” JWT Token-Based Authentication with secure token generation and validation
  • πŸ‘₯ Role-Based Access Control (RBAC) with @PreAuthorize annotations for endpoint protection

πŸ› οΈ Technology Stack

Backend Technologies

Detailed Tech Stack

Technology Version Purpose
Java 21 LTS Core programming language
Spring Boot 3.3.5 Application framework
Spring Data JPA - ORM and database operations
Spring Security 6.x Authentication and authorization
Spring Web MVC - REST API development
Hibernate 6.x JPA implementation
Maven 3.8+ Dependency management
MySQL 8.0+ Production database
Lombok 1.18.x Boilerplate code reduction
ModelMapper 3.2.0 Entity-DTO mapping
JWT (JJWT) 0.12.6 Token-based authentication
JUnit 5 5.10.x Unit testing framework
Mockito 5.x Mocking framework for tests
AssertJ 3.25.x Fluent assertion library
Validation API 2.0+ Input validation

πŸ—οΈ System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Client │────▢│ Controller │────▢│ Service β”‚ β”‚ (Browser/ β”‚ β”‚ Layer β”‚ β”‚ Layer β”‚ β”‚ Mobile) │◀────│ (REST API) │◀────│ (Business) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Database │◀────│ Repository │◀────│ DTO β”‚ β”‚ (MySQL) β”‚ β”‚ Layer β”‚ β”‚ Layer β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Getting Started

Prerequisites

Before you begin, ensure you have the following installed:

# Check Java version
java --version
# Should output: Java 21 or higher

# Check Maven version
mvn --version
# Should output: Maven 3.8 or higher

# Check MySQL (if using MySQL)
mysql --version

Installation
1. Clone the repository
git clone https://github.com/Kumar-Aman7974/Shopping-Cart-Backend-System.git
cd Shopping-Cart-Backend-System

2. Configure Database
Option A: Using MySQL (Production)
2. Configure Database
Option A: Using MySQL (Production)

Option B: Using H2 (Development)

No setup required, in-memory database

3. Configure application.properties
Update src/main/resources/application.properties:
# MySQL Configuration (uncomment for MySQL)
spring.datasource.url=jdbc:mysql://localhost:3306/shop_db
spring.datasource.username=shop_user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# H2 Configuration (uncomment for H2)
# spring.datasource.url=jdbc:h2:mem:testdb
# spring.datasource.driverClassName=org.h2.Driver
# spring.datasource.username=sa
# spring.datasource.password=

# JPA Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.format_sql=true

# Server Configuration
server.port=8080
server.servlet.context-path=/api

# File Upload
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

4. Build the Project
# Clean and compile
mvn clean compile

# Package the application
mvn package

5. Run the Application
Using Maven:
mvn spring-boot:run

Using JAR file:
java -jar target/demo-shops-0.0.1-SNAPSHOT.jar

6. Verify Installation
Open your browser and navigate to:

API Base URL: http://localhost:8080/api

H2 Console (if using H2): http://localhost:8080/h2-console


πŸ“‘ API Documentation
Base URL
http://localhost:8080/api

Authentication APIs
Method	Endpoint	Description	Request Body	Response
POST	/api/v1/auth/register	Register new user	User details	User object
POST	/api/v1/auth/login	User login	Email & password	JWT Token
GET	/api/v1/users/{id}	Get user profile	-	User details (requires auth)
PUT	/api/v1/users/{id}	Update user	Updated details	Updated user (requires auth)

**JWT Token Example:**
After login, the response will contain a JWT token:
```json
{
    "message": "Login successful",
    "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyQGVtYWlsLmNvbSIsImlkIjoxLCJyb2xlcyI6WyJST0xFX1VTRVIiXSwiaWF0IjoxNjAxNjM4MzAwLCJleHAiOjE2MDE2NDE5MDB9.signature"
}

Use this token in subsequent requests:

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
     http://localhost:8080/api/v1/products/all

Product APIs Method Endpoint Description Auth Required Role Required GET /api/v1/products/all Get all products No - GET /api/v1/products/product/{id}/product Get product by ID No - GET /api/v1/products/category/{category} Get products by category No - POST /api/v1/products/add Create new product Yes ROLE_ADMIN PUT /api/v1/products/{id} Update product Yes ROLE_ADMIN DELETE /api/v1/products/{id} Delete product Yes ROLE_ADMIN

Example Request - Create Product: POST /api/v1/products/add Authorization: Bearer <JWT_TOKEN>

{ "name": "iPhone 15 Pro", "brand": "Apple", "price": 999.99, "inventory": 50, "description": "Latest iPhone with A17 Pro chip", "category": { "name": "Electronics" } }

Example Response: { "id": 1, "name": "iPhone 15 Pro", "brand": "Apple", "price": 999.99, "inventory": 50, "description": "Latest iPhone with A17 Pro chip", "category": { "id": 1, "name": "Electronics" } }

Cart APIs

Method Endpoint Description Auth Required GET /api/v1/carts/{userId} Get user's cart Yes POST /api/v1/cartItems/add Add item to cart Yes PUT /api/v1/cartItems/update Update cart item quantity Yes DELETE /api/v1/cartItems/{cartItemId} Remove from cart Yes DELETE /api/v1/carts/{userId}/clear Clear entire cart Yes

Example Request - Add to Cart: POST /api/v1/cartItems/add Authorization: Bearer <JWT_TOKEN>

{ "userId": 1, "productId": 1, "quantity": 2 }

Order APIs Method Endpoint Description Auth Required POST /api/v1/orders Place order Yes GET /api/v1/orders/{userId} Get user orders Yes GET /api/v1/orders/order/{orderId} Get order by ID Yes PUT /api/v1/orders/{orderId}/status Update order status Yes (ADMIN only) DELETE /api/v1/orders/{orderId} Cancel order Yes

Category APIs Method Endpoint Description Auth Required Role Required GET /api/v1/categories Get all categories No - GET /api/v1/categories/{id} Get category by ID No - POST /api/v1/categories Create category Yes ROLE_ADMIN PUT /api/v1/categories/{id} Update category Yes ROLE_ADMIN DELETE /api/v1/categories/{id} Delete category Yes ROLE_ADMIN

πŸ—„οΈ Database Schema Entity Relationship Diagram

Authentication & User Management:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     Role     β”‚         β”‚    User      β”‚         β”‚   Cart       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ id (PK)      │◀────────│ id (PK)      │────────▢│ id (PK)      β”‚
β”‚ name         β”‚ (M2M)   β”‚ firstName    β”‚         β”‚ user_id(FK)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚ lastName     β”‚         β”‚ totalAmount  β”‚
                         β”‚ email        β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚ password     β”‚              β”‚
                         β”‚ createdAt    β”‚              β–Ό
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                            β”‚    CartItem      β”‚
                                            β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                                            β”‚ id (PK)          β”‚
                                            β”‚ cart_id(FK)      β”‚
                                            β”‚ product_id(FK)   β”‚
                                            β”‚ quantity         β”‚
                                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Order Management:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Order       │◀──────│    OrderItem     │──────▢│   Product    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ id (PK)          β”‚       β”‚ id (PK)          β”‚       β”‚ id (PK)      β”‚
β”‚ user_id(FK)      β”‚       β”‚ order_id(FK)     β”‚       β”‚ name         β”‚
β”‚ orderDate        β”‚       β”‚ product_id(FK)   β”‚       β”‚ brand        β”‚
β”‚ totalAmount      β”‚       β”‚ quantity         β”‚       β”‚ price        β”‚
β”‚ status           β”‚       β”‚ price            β”‚       β”‚ inventory    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚ category_id  β”‚
                                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                             β”‚
                                                             β–Ό
                                                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                      β”‚   Category   β”‚
                                                      β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                                                      β”‚ id (PK)      β”‚
                                                      β”‚ name         β”‚
                                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Product Images:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Product    │────────▢│    Image     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€(1:M)    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ id (PK)      β”‚         β”‚ id (PK)      β”‚
β”‚ name         β”‚         β”‚ product_id   β”‚
β”‚ ...          β”‚         β”‚ image_url    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure Shopping-Cart-Backend-System/ β”‚ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ main/ β”‚ β”‚ β”œβ”€β”€ java/com/dailycodework/demoshops/ β”‚ β”‚ β”‚ β”œβ”€β”€ DemoShopsApplication.java # Main application class β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ controller/ # REST Controllers β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ProductController.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ CartController.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ OrderController.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ CategoryController.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ImageController.java β”‚ β”‚ β”‚ β”‚ └── UserController.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ service/ # Business Logic Layer β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ product/ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ IProductService.java β”‚ β”‚ β”‚ β”‚ β”‚ └── ProductService.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ cart/ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ICartService.java β”‚ β”‚ β”‚ β”‚ β”‚ └── CartService.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ order/ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ IOrderService.java β”‚ β”‚ β”‚ β”‚ β”‚ └── OrderService.java β”‚ β”‚ β”‚ β”‚ └── user/ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ IUserService.java β”‚ β”‚ β”‚ β”‚ └── UserService.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ repository/ # Data Access Layer β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ProductRepository.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ CartRepository.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ OrderRepository.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ UserRepository.java β”‚ β”‚ β”‚ β”‚ └── CategoryRepository.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ model/ # Entity Classes β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Product.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Cart.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Order.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ User.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Category.java β”‚ β”‚ β”‚ β”‚ └── Image.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ dto/ # Data Transfer Objects β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ProductDto.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ OrderDto.java β”‚ β”‚ β”‚ β”‚ └── ImageDto.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ request/ # Request Objects β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ AddProductRequest.java β”‚ β”‚ β”‚ β”‚ └── ProductUpdateRequest.java β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ response/ # Response Objects β”‚ β”‚ β”‚ β”‚ └── ApiResponse.java β”‚ β”‚ β”‚ β”‚ | β”‚ β”‚ β”‚ β”œβ”€β”€ exceptions/ # Custom Exceptions | β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ResourceNotFoundException.java | β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ProductNotFoundException.java | β”‚ β”‚ β”‚ β”‚ └── AlreadyExistsException.java | β”‚ β”‚ β”‚ β”‚ | β”‚ β”‚ β”‚ β”œβ”€β”€ security/ # Security & JWT Configuration | β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ config/ | β”‚ β”‚ β”‚ β”‚ β”‚ └── ShopConfig.java # Security beans, JWT config | β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Jwt/ | β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ JwtUtils.java # JWT token generation & validation | β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ AuthTokenFilter.java # JWT request filter | β”‚ β”‚ β”‚ β”‚ β”‚ └── JwtAutEntryPoint.java # JWT error handler | β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ user/ | β”‚ β”‚ β”‚ β”‚ β”‚ └── ShopUserDetails.java # User principal for Spring Security | β”‚ β”‚ β”‚ β”‚ └── service/ | β”‚ β”‚ β”‚ β”‚ └── ShopUserDetailsService.java # User details service | β”‚ β”‚ β”‚ β”‚ | β”‚ β”‚ β”‚ β”œβ”€β”€ enums/ # Enumerations | β”‚ β”‚ β”‚ β”‚ └── OrderStatus.java | β”‚ β”‚ β”‚ β”‚ | β”‚ β”‚ β”‚ └── data/ # Data Initialization | β”‚ β”‚ β”‚ └── DataInitializer.java # Seed default roles and users β”‚ β”‚ β”‚ β”‚ β”‚ └── resources/ β”‚ β”‚ β”œβ”€β”€ application.properties # Configuration β”‚ β”‚ └── static/ # Static resources β”‚ β”‚ | β”‚ └── test/ # Unit & Integration Tests | β”‚ └── java/com/dailycodework/demoshops/ | β”‚ β”œβ”€β”€ service/ | β”‚ β”‚ β”œβ”€β”€ product/ | β”‚ β”‚ β”‚ └── ProductServiceTest.java # Service layer tests with Mockito | β”‚ β”‚ └── cart/ | β”‚ β”‚ └── CartServiceTest.java # Cart service tests | β”‚ └── DemoShopsApplicationTests.java # Application context tests β”‚ β”œβ”€β”€ pom.xml # Maven configuration β”œβ”€β”€ mvnw # Maven wrapper script β”œβ”€β”€ mvnw.cmd # Maven wrapper (Windows) └── README.md # Project documentation

πŸ’» Code Examples

Example 1: Creating a Product Service @Service @Transactional public class ProductService implements IProductService {

@Autowired
private ProductRepository productRepository;

@Override
public Product addProduct(AddProductRequest request) {
    // Check if product already exists
    if (productRepository.existsByName(request.getName())) {
        throw new AlreadyExistsException("Product already exists!");
    }
    
    // Convert DTO to Entity
    Product product = new Product();
    product.setName(request.getName());
    product.setBrand(request.getBrand());
    product.setPrice(request.getPrice());
    product.setInventory(request.getInventory());
    
    // Save to database
    return productRepository.save(product);
}

}

Example 2: REST Controller with Exception Handling @RestController @RequestMapping("/api/products") public class ProductController {

@Autowired
private IProductService productService;

@GetMapping("/{id}")
public ResponseEntity<ApiResponse> getProductById(@PathVariable Long id) {
    try {
        Product product = productService.getProductById(id);
        return ResponseEntity.ok(new ApiResponse("success", product));
    } catch (ProductNotFoundException e) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ApiResponse("error", e.getMessage()));
    }
}

}

| Example 3: Global Exception Handler | @ControllerAdvice | public class GlobalExceptionHandler { |
| @ExceptionHandler(ResourceNotFoundException.class) | public ResponseEntity handleResourceNotFound( | ResourceNotFoundException ex) { | return ResponseEntity.status(HttpStatus.NOT_FOUND) | .body(new ApiResponse("error", ex.getMessage())); | } |
| @ExceptionHandler(Exception.class) | public ResponseEntity handleGenericException(Exception ex) { | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) | .body(new ApiResponse("error", "An unexpected error occurred")); | } | } | | Example 4: JWT Authentication & Role-Based Access Control | @RestController | @RequestMapping("${api.prefix}/products") | public class ProductController { |
| @PreAuthorize("hasRole('ROLE_ADMIN')") // Only ADMIN can add products | @PostMapping("/add") | public ResponseEntity addProduct(@RequestBody AddProductRequest request) { | try { | Product theProduct = productService.addProduct(request); | ProductDto productDto = productService.convertToDto(theProduct); | return ResponseEntity.status(HttpStatus.CREATED) | .body(new ApiResponse("Item added successfully!", productDto)); | } catch (AlreadyExistsException e) { | return ResponseEntity.status(HttpStatus.CONFLICT) | .body(new ApiResponse(e.getMessage(), null)); | } | } |
| @GetMapping("/all") // Public endpoint | public ResponseEntity getAllProducts() { | List products = productService.getAllProducts(); | List convertedProducts = productService.getConvertedProducts(products); | return ResponseEntity.ok(new ApiResponse("success", convertedProducts)); | } | } | | Example 5: User Authentication with JWT Token | @RestController | @RequestMapping("${api.prefix}/auth") | public class AuthController { |
| @PostMapping("/login") | public ResponseEntity login(@RequestBody LoginRequest request) { | try { | Authentication authentication = authenticationManager.authenticate( | new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()) | ); |
| String jwt = jwtUtils.generateTokenForUser(authentication); | return ResponseEntity.ok(new ApiResponse("Login successful", jwt)); | } catch (AuthenticationException e) { | return ResponseEntity.status(HttpStatus.UNAUTHORIZED) | .body(new ApiResponse("Invalid credentials", null)); | } | } | } | | Example 6: Unit Testing with JUnit 5 & Mockito | @ExtendWith(MockitoExtension.class) | class ProductServiceTest { |
| @Mock | private ProductRepository productRepository; |
| @Mock | private CategoryRepository categoryRepository; |
| @InjectMocks | private ProductService productService; |
| @BeforeEach | void setUp() { | // Initialize test data | } |
| @Test | @DisplayName("Should return product when ID exists") | void getProductById_ExistingId_ReturnsProduct() { | // Given | Long productId = 1L; | Product expectedProduct = new Product("iPhone", "Apple", BigDecimal.valueOf(999.99), 10, "Latest iPhone", null); | when(productRepository.findById(productId)).thenReturn(Optional.of(expectedProduct)); |
| // When | Product result = productService.getProductById(productId); |
| // Then | assertThat(result).isNotNull(); | assertThat(result.getName()).isEqualTo("iPhone"); | verify(productRepository).findById(productId); | } |
| @Test | @DisplayName("Should throw exception when product does not exist") | void getProductById_NonExistentId_ThrowsException() { | // Given | Long productId = 999L; | when(productRepository.findById(productId)).thenReturn(Optional.empty()); |
| // When & Then | assertThatThrownBy(() -> productService.getProductById(productId)) | .isInstanceOf(ProductNotFoundException.class); | } | }

πŸ§ͺ Testing

Test Framework & Tools:

  • JUnit 5 - Modern unit testing framework with parameterized and nested test support
  • Mockito - Powerful mocking framework for isolating units under test
  • AssertJ - Fluent assertions for expressive test conditions

Run tests:

# Run all tests
mvn test

# Run specific test class
mvn -Dtest=ProductServiceTest test

# Run specific test method
mvn -Dtest=ProductServiceTest#getProductById_ExistingId_ReturnsProduct test

# Run with coverage report (requires jacoco plugin)
mvn test jacoco:report

Testing Patterns Used:

  • @ExtendWith(MockitoExtension.class) for dependency injection of mocks
  • @Mock for mocking dependencies
  • @InjectMocks for injecting mocks into service under test
  • @BeforeEach for test data setup
  • @Nested and @DisplayName for organizing and describing test cases
  • AssertJ fluent assertions: assertThat().isEqualTo().isNotNull()
  • Mockito verification: verify(repository).findById()
  • assertThatThrownBy() for exception testing

🚨 Error Handling

HTTP Status Codes Status Code Description Usage 200 OK Success GET, PUT, DELETE operations 201 CREATED Resource created POST operations 400 BAD REQUEST Invalid input Validation errors 404 NOT FOUND Resource not found Missing product/user/cart 409 CONFLICT Duplicate resource Existing product/user 500 INTERNAL ERROR Server error Unexpected exceptions

πŸ”’ Security

Security Features Implemented: βœ… JWT Token-Based Authentication - Stateless authentication using JSON Web Tokens (JJWT 0.12.6) βœ… Role-Based Access Control (RBAC) - Fine-grained endpoint protection using @PreAuthorize("hasRole('ROLE_ADMIN')") and @PreAuthorize("hasRole('ROLE_USER')") βœ… Password Encryption - BCryptPasswordEncoder for secure password hashing βœ… Token Validation - Comprehensive token validation with expiration checks βœ… Security Filter Chain - JWT authentication filter (AuthTokenFilter) integrated into Spring Security βœ… Default Users - DataInitializer creates 5 ROLE_USER and 2 ROLE_ADMIN users (password: "12345") for testing βœ… Input Validation - Jakarta Bean Validation for request validation βœ… SQL Injection Prevention - JPA parameterized queries βœ… Exception Security - Proper error handling without exposing system details

JWT Token Details:

  • Token Format: Bearer <JWT_TOKEN>
  • Expiration: 1 hour (configurable via auth.token.expirationInMils)
  • Secret Key: Hex-encoded secret in application.properties
  • Claims: Includes user ID, email, and roles

Authentication Flow:

  1. User calls /api/v1/auth/login with email and password
  2. Server validates credentials using Spring Security's AuthenticationManager
  3. Server generates JWT token via JwtUtils.generateTokenForUser()
  4. Client stores token and includes it in subsequent requests: Authorization: Bearer <token>
  5. AuthTokenFilter intercepts requests and validates token
  6. If valid, user identity and roles are loaded into SecurityContext

Default Credentials (for development/testing):

Future Security Enhancements:

  • API rate limiting per user/IP
  • Token refresh mechanism
  • Social login integration (OAuth 2.0)
  • Two-factor authentication (2FA)

🀝 Contributing Contributions are what make the open-source community amazing!

  1. How to Contribute

  2. Fork the Project git checkout -b feature/AmazingFeature

  3. Commit your Changes git commit -m 'Add some AmazingFeature'

  4. Push to the Branch git push origin feature/AmazingFeature

  5. Open a Pull Request

Guidelines . Follow Java coding conventions . Write meaningful commit messages . Update documentation as needed . Add tests for new features

Create your Feature Branch πŸ“§ Contact Kumar Aman

GitHub: @Kumar-Aman7974

Email: amanbth7974@gmail.com

LinkedIn: [Add your LinkedIn URL]

Project Link: https://github.com/Kumar-Aman7974/Shopping-Cart-Backend-System

πŸ™ Acknowledgments Spring Boot Documentation Baeldung Tutorials Daily Code Work tutorials Open-source community

⭐ Show Your Support If you found this project helpful, please give it a ⭐ on GitHub! https://img.shields.io/github/stars/Kumar-Aman7974/Shopping-Cart-Backend-System?style=social

Built with ❀️ using Spring Boot | © 2026 Kumar Aman

How to Add This README:

# 1. Create the README file with the content above
# You can either:
# - Copy the content and create README.md manually
# - Or use this command to create it:

# 2. If you have the content in clipboard, create the file:
notepad README.md
# Then paste the content and save

# 3. Move it to root (if needed) and commit
git add README.md
git commit -m "docs: add comprehensive README with complete documentation"
git push

# 4. Delete the old Readme.md if it exists in src folder
git rm src/main/java/com/dailycodework/demoshops/Readme.md
git commit -m "chore: remove old README from src folder"
git push

About

Built a complete e-commerce shopping cart backend using Spring Boot, Spring Security and JWT for secure user authentication and authorization

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages