- About The Project
- Key Features
- Technology Stack
- System Architecture
- Getting Started
- API Documentation
- Database Schema
- Project Structure
- Code Examples
- Testing
- Error Handling
- Security
- Future Enhancements
- Contributing
- Contact
- Acknowledgments
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.
- β 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
| 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 | β |
- π 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 | 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 |
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β Client ββββββΆβ Controller ββββββΆβ Service β β (Browser/ β β Layer β β Layer β β Mobile) βββββββ (REST API) βββββββ (Business) β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β βΌ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β Database βββββββ Repository βββββββ DTO β β (MySQL) β β Layer β β Layer β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
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/allProduct 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:reportTesting Patterns Used:
@ExtendWith(MockitoExtension.class)for dependency injection of mocks@Mockfor mocking dependencies@InjectMocksfor injecting mocks into service under test@BeforeEachfor test data setup@Nestedand@DisplayNamefor 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:
- User calls
/api/v1/auth/loginwith email and password - Server validates credentials using Spring Security's AuthenticationManager
- Server generates JWT token via
JwtUtils.generateTokenForUser() - Client stores token and includes it in subsequent requests:
Authorization: Bearer <token> AuthTokenFilterintercepts requests and validates token- If valid, user identity and roles are loaded into SecurityContext
Default Credentials (for development/testing):
- Admin Users: admin1@email.com, admin2@email.com (password: "12345")
- Regular Users: user1@email.com to user5@email.com (password: "12345")
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!
-
How to Contribute
-
Fork the Project git checkout -b feature/AmazingFeature
-
Commit your Changes git commit -m 'Add some AmazingFeature'
-
Push to the Branch git push origin feature/AmazingFeature
-
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
# 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