Spring Boot Microservices E-Commerce Project: Step-by-Step Tutorial

In this tutorial, we will create a simple e-commerce application using a microservices architecture with Spring Boot and Spring Cloud. We will create the following microservices:
  1. Product Service: Manages product information.
  2. Order Service: Manages customer orders.
  3. Inventory Service: Manages product inventory.
  4. Eureka Server: Service discovery.
  5. API Gateway: Acts as a single entry point to the system.
Spring Boot Microservices E-Commerce Project

Prerequisites

  • JDK 17 or later
  • Maven or Gradle
  • Docker
  • Docker Compose
  • IDE (IntelliJ IDEA, Eclipse, etc.)

Simple Microservices Architecture

Here is the simple microservices architecture for this e-commerce microservices application:

+-----------------------------+
|         Postman Client      |
|     (Client for Testing)    |
+-----------------------------+
                |
                v
+-----------------------------+              +-----------------------------+
|         API Gateway         |              |           Eureka Server     |
|  (Single Entry Point to the |   ---------->|       (Service Discovery)   |
|          System)            |              +-----------------------------+
+-----------------------------+
             |
             v
          +----------------------+-----------------------+
          |                      |                       |
          v                      v                       v
+-----------------+     +-----------------+     +------------------+
| Product Service |     | Order Service   |     | Inventory Service|
| (Manages        |     | (Manages Orders)|     | (Manages         |
| Product Info)   |     |                 |     | Inventory)       |
+-----------------+     +-----------------+     +------------------+

Explanation:

  1. Postman Client: Used for testing the APIs. This client sends requests to the API Gateway.

  2. API Gateway: The single entry point to the system, handling incoming requests and routing them to the appropriate microservice.

  3. Eureka Server: This is the service discovery component where all microservices register themselves. It enables the discovery of services for communication.

  4. Product Service: Manages product information such as details, pricing, and availability.

  5. Order Service: Manages customer orders, processing new orders, updating order status, etc.

  6. Inventory Service: Manages product inventory, keeping track of stock levels and updating inventory records.

The Postman client sends requests to the API Gateway, which uses the Eureka Server to locate the appropriate microservice. Each microservice registers itself with the Eureka Server and communicates with other microservices as needed.

Step 1: Set Up Eureka Server

1.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Eureka Server

1.2 Configure application.properties

Set up the application properties for the Eureka Server.

server.port=8761
spring.application.name=eureka-server

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

1.3 Enable Eureka Server

Add the @EnableEurekaServer annotation to the main application class.

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Step 2: Set Up API Gateway

2.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Cloud Gateway
  • Eureka Discovery Client

2.2 Configure application.properties

Set up the application properties for the API Gateway.

server.port=8080
spring.application.name=api-gateway

eureka.client.service-url.default-zone=http://localhost:8761/eureka/
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true

2.3 Enable Eureka Client and Gateway

Add the @EnableDiscoveryClient annotation in the main application class.

package com.example.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

Step 3: Set Up Product Service

3.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Spring Boot Actuator
  • Spring Data JPA
  • H2 Database
  • Eureka Discovery Client

3.2 Configure application.properties

Set up the application properties for the Product Service.

server.port=8081
spring.application.name=product-service

eureka.client.service-url.default-zone=http://localhost:8761/eureka/

spring.datasource.url=jdbc:h2:mem:productdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.h2.console.enabled=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

3.3 Enable Eureka Client

Add the @EnableDiscoveryClient annotation to the main application class.

package com.example.productservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.class, args);
    }
}

3.4 Create Product Model

Create a simple Product model.

package com.example.productservice;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Product {
    @Id
    private String id;
    private String name;
    private double price;

    // Getters and setters
}

3.5 Create Product Repository

Create a repository interface to manage Product entities.

package com.example.productservice;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, String> {
}

3.6 Create Product Service

Create a service to handle product-related business logic.

package com.example.productservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }

    public Product getProductById(String id) {
        return productRepository.findById(id).orElse(null);
    }

    public Product addProduct(Product product) {
        return productRepository.save(product);
    }
}

3.7 Create Product Controller

Create a controller to handle HTTP requests.

package com.example.productservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/products")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }

    @GetMapping("/{id}")
    public Product getProductById(@PathVariable String id) {
        return productService.getProductById(id);
    }

    @PostMapping
    public Product addProduct(@RequestBody Product product) {
        return productService.addProduct(product);
    }
}

Step 4: Set Up Order Service

4.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Spring Boot Actuator
  • Spring Data JPA
  • H2 Database
  • Eureka Discovery Client
  • OpenFeign

4.2 Configure application.properties

Set up the application properties for the Order Service.

server.port=8082
spring.application.name=order-service

eureka.client.service-url.default-zone=http://localhost:8761/eureka/

spring.datasource.url=jdbc:h2:mem:orderdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.h2.console.enabled=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

4.3 Enable Eureka Client and Feign Clients

Add the @EnableDiscoveryClient and @EnableFeignClients annotations to the main application class.

package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

4.4 Create Order Model

Create a simple Order model.

package com.example.orderservice;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Order {
    @Id
    private String id;
    private String productId;
    private int quantity;

    // Getters and setters
}

4.5 Create Order Repository

Create a repository interface to manage Order entities.

package com.example.orderservice;

import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, String> {
}

4.6 Create Product Client

Create a Feign client interface to communicate with the product-service.

package com.example.orderservice;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "product-service")
public interface ProductClient {

    @GetMapping("/products/{id}")
    Product getProductById(@PathVariable String id);
}

4.7 Create Product DTO

Create a Product DTO to match the one in product-service.

package com.example.orderservice;

public class Product {
    private String id;
    private String name;
    private double price;

    // Getters and setters
}

4.8 Create Order Service

Create a service to handle order-related business logic.

package com.example.orderservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private ProductClient productClient;

    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }

    public Order getOrderById(String id) {
        return orderRepository.findById(id).orElse(null);
    }

    public Order addOrder(Order order) {
        Product product = productClient.getProductById(order.getProductId());
        if (product != null) {
            return orderRepository.save(order);
        } else {
            throw new RuntimeException("Product not found");
        }
    }
}

4.9 Create Order Controller

Create a controller to handle HTTP requests.

package com.example.orderservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Rest

Controller
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping
    public List<Order> getAllOrders() {
        return orderService.getAllOrders();
    }

    @GetMapping("/{id}")
    public Order getOrderById(@PathVariable String id) {
        return orderService.getOrderById(id);
    }

    @PostMapping
    public Order addOrder(@RequestBody Order order) {
        return orderService.addOrder(order);
    }
}

Step 5: Set Up Inventory Service

5.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Spring Boot Actuator
  • Spring Data JPA
  • H2 Database
  • Eureka Discovery Client

5.2 Configure application.properties

Set up the application properties for the Inventory Service.

server.port=8083
spring.application.name=inventory-service

eureka.client.service-url.default-zone=http://localhost:8761/eureka/

spring.datasource.url=jdbc:h2:mem:inventorydb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.h2.console.enabled=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

5.3 Enable Eureka Client

Add the @EnableDiscoveryClient annotation to the main application class.

package com.example.inventoryservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class InventoryServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(InventoryServiceApplication.class, args);
    }
}

5.4 Create Inventory Model

Create a simple Inventory model.

package com.example.inventoryservice;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Inventory {
    @Id
    private String productId;
    private int quantity;

    // Getters and setters
}

5.5 Create Inventory Repository

Create a repository interface to manage Inventory entities.

package com.example.inventoryservice;

import org.springframework.data.jpa.repository.JpaRepository;

public interface InventoryRepository extends JpaRepository<Inventory, String> {
}

5.6 Create Inventory Service

Create a service to handle inventory-related business logic.

package com.example.inventoryservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class InventoryService {

    @Autowired
    private InventoryRepository inventoryRepository;

    public List<Inventory> getAllInventory() {
        return inventoryRepository.findAll();
    }

    public Inventory getInventoryByProductId(String productId) {
        return inventoryRepository.findById(productId).orElse(null);
    }

    public Inventory updateInventory(String productId, int quantity) {
        Inventory inventory = inventoryRepository.findById(productId).orElseThrow(() -> new RuntimeException("Product not found"));
        inventory.setQuantity(quantity);
        return inventoryRepository.save(inventory);
    }
}

5.7 Create Inventory Controller

Create a controller to handle HTTP requests.

package com.example.inventoryservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/inventory")
public class InventoryController {

    @Autowired
    private InventoryService inventoryService;

    @GetMapping
    public List<Inventory> getAllInventory() {
        return inventoryService.getAllInventory();
    }

    @GetMapping("/{productId}")
    public Inventory getInventoryByProductId(@PathVariable String productId) {
        return inventoryService.getInventoryByProductId(productId);
    }

    @PutMapping("/{productId}")
    public Inventory updateInventory(@PathVariable String productId, @RequestParam int quantity) {
        return inventoryService.updateInventory(productId, quantity);
    }
}

Step 6: Run the Services

  1. Start the Eureka Server: Run the EurekaServerApplication class.
  2. Start the API Gateway: Run the ApiGatewayApplication class.
  3. Start the Product Service: Run the ProductServiceApplication class.
  4. Start the Order Service: Run the OrderServiceApplication class.
  5. Start the Inventory Service: Run the InventoryServiceApplication class.

Step 7: Test the E-Commerce Application

  1. Test the Product Service:

    • Add products using POST /products:
      {
        "id": "1",
        "name": "Product 1",
        "price": 100.0
      }
      
    • Retrieve products using GET /products.
  2. Test the Order Service:

    • Create orders using POST /orders:
      {
        "id": "1",
        "productId": "1",
        "quantity": 1
      }
      
    • Retrieve orders using GET /orders.
  3. Test the Inventory Service:

    • Update inventory using PUT /inventory/{productId}?quantity=10.
    • Retrieve inventory using GET /inventory.

Conclusion

You have successfully set up a basic e-commerce application using Spring Boot microservices architecture. This setup includes a Product Service, Order Service, Inventory Service, Eureka Server for service discovery, and an API Gateway. This example can be expanded with more features such as user management, payment processing, and more complex business logic.


Comments