Spring Boot Handbook

    Microservice: Setting Up the Inventory Management System

    Introduction#

    While a microservices architecture defines this system for the efficient governance of stock, orders, and products—with an emphasis on flexibility and scalability—each microservice attends to a respective function, ranging from product management to stock tracking and order processing; thus, it can be developed and deployed independently.

    Built-in Spring Boot and Spring Cloud, this system allows for inter-service communication, introduces fault tolerance, and realizes ease of maintenance. It is API-driven with RESTful APIs, deployed in Docker with a MySQL database and an API Gateway, to get real-time inventory snippets and perform business transactions seamlessly. The microservices approach itself stands for a scalable, resilient, and adaptive solution to use for modern inventory management.

    Microservice Architecture

    Building a Scalable E-Commerce Inventory Management System with Microservices using Spring Boot#

    1. Generate SpringBoot application:#

    1. Go to https://start.spring.io/ website
    2. Generate Order Service Application
    Generate Order Service Application
    • Generate Inventory Service Application
    Generate Inventory Service Application
    • Extract that zip files inside a folder (ecommerce).
    Extract that zip files inside a folder (ecommerce)
    • Open that folder (ecommerce) inside your ide (IntelliJ, VS Code, etc.). Don’t open the applications separately. Reload maven.
    Ide image
    • If you missed this symbol then you can add maven projects like this.
    Ide Image

    2. Make Changes Inside pom.xml For SpringBoot New Version:#

    Whenever we will use SpringBoot between <version>3.3.6</version> and <version>3.4.2</version> to enable Lombok we need to make some changes inside our pom.xml. Inside the plugins part of the XML file, we can see two plugins are there <artifactId>maven-compiler-plugin</artifactId> and <artifactId>spring-boot-maven-plugin</artifactId>. Inside the first plugin (<artifactId>maven-compiler-plugin</artifactId> ), we need to add the Lombok version.

    <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.36</version> --- add this only and reload your maven </path> </annotationProcessorPaths> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>

    3. Database Connection Configuration SpringBoot application:#

    Common Configuration: (inside application.properties/application.yml file) server.servlet.context-path=<any path> use any path

    server.port=<any port> use any unused port

    Database Configuration:

    spring.datasource.url=jdbc:postgresql://localhost:5432/<Database Name> use db name that you create inside your db.

    spring.datasource.username=<username> add your user name.

    spring.datasource.password=<password> add your password.

    spring.jpa.hibernate.ddl-auto=create-drop use any of (create-drop/update/create)

    spring.jpa.show-sql=true

    spring.jpa.properties.hibernate.format_sql=true

    The server.servlet.context-path in Spring Boot sets a base URL for all endpoints, helping to avoid conflicts, organize APIs, and manage multiple services efficiently. It is useful in microservices architectures, simplifies reverse proxy/load balancer configurations, and enables environment-specific deployments. Configuring it in application.properties or application.yml ensures structured and scalable API management.

    1. Inventory Service Database Configuration:
    Inventory Service Database Configuration
    1. Order Service Database Configuration:
    Order Service Database Configuration

    servlet.context-path=/api/v1 sets a base path for all endpoints, so URLs will be prefixed with /api/v1. For example, /users becomes http://localhost:8080/api/v1/users. This helps with API versioning and organization.

    1. Connect the database.
      1. If you are using dBeaver
    DBeaver image
    1. If you are using direct pgAdmin4. (After login with password).
    pgAdmin4 image

    4. Developing Microservices SpringBoot Application:#

    1. Developing the Inventory Service

    DTO/DAO Class:

    package com.codingshuttle.ecommerce.inventory_service.dtos; import lombok.Data; @Data public class ProductDto { private Long id; private String title; private Double price; private Integer stock; }

    Entity Class:

    package com.codingshuttle.ecommerce.inventory_service.entities; import jakarta.persistence.*; import lombok.*; @Entity @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Table(name = "products") public class ProductEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private Double price; private Integer stock; }

    Configuration Class: (For Model Mapper) We need model mapper dependency.

    <dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.2.0</version> </dependency>
    package com.codingshuttle.ecommerce.inventory_service.configs; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class Mapper { @Bean public ModelMapper getMapper(){ return new ModelMapper(); } }

    Repository Class:

    package com.codingshuttle.ecommerce.inventory_service.repositories; import com.codingshuttle.ecommerce.inventory_service.entities.ProductEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ProductRepo extends JpaRepository<ProductEntity,Long> { }

    Controller Class:

    package com.codingshuttle.ecommerce.inventory_service.controllers; import com.codingshuttle.ecommerce.inventory_service.dtos.ProductDto; import com.codingshuttle.ecommerce.inventory_service.services.ProductService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @Slf4j @RequiredArgsConstructor @RequestMapping("/products") //you have to add "/api/v1" before adding this endpoint public class ProductsController { private final ProductService productService; @GetMapping public ResponseEntity<List<ProductDto>> getAllProducts(){ log.info("Fetching all products via controller"); List<ProductDto> inventories = productService.getAllProducts(); return ResponseEntity.ok(inventories); } @GetMapping("/{id}") public ResponseEntity<ProductDto> getProductById(@PathVariable Long id){ log.info("Fetching product by id via controller"); ProductDto inventory = productService.getProductById(id); return ResponseEntity.ok(inventory); } }

    Service Class:

    package com.codingshuttle.ecommerce.inventory_service.services; import com.codingshuttle.ecommerce.inventory_service.dtos.ProductDto; import com.codingshuttle.ecommerce.inventory_service.entities.ProductEntity; import com.codingshuttle.ecommerce.inventory_service.repositories.ProductRepo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.modelmapper.ModelMapper; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service @Slf4j @RequiredArgsConstructor public class ProductService { private final ProductRepo productRepo; private final ModelMapper modelMapper; public List<ProductDto> getAllProducts() { log.info("Fetching all inventory items"); List<ProductEntity> inventories = productRepo.findAll(); return inventories.stream() .map(productEntity -> modelMapper.map(productEntity,ProductDto.class)) //.collect(Collectors.toList()); .toList(); } public ProductDto getProductById(Long id) { log.info("Fetching Product with Id: {}",id); Optional<ProductEntity> inventory = productRepo.findById(id); return inventory.map(item -> modelMapper.map(item,ProductDto.class)) .orElseThrow(()->new RuntimeException("Inventory not found")); } }
    1. Developing the Order Service

    DTO/DAO Class:

    package com.codingshuttle.ecommerce.order_service.dtos; import com.codingshuttle.ecommerce.order_service.entities.OrderItemsEntity; import lombok.Data; import java.util.List; @Data public class OrderRequestDto { private Long id; private List<OrderItemsEntity> items; private Double totalPrice; } package com.codingshuttle.ecommerce.order_service.dtos; import lombok.Data; @Data public class OrderRequestItemDto { private Long id; private Long productId; private Integer quantity; }

    Entity and Enum Class:

    package com.codingshuttle.ecommerce.order_service.entities; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @Entity @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Table(name = "orders") public class OrdersEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Double totalPrice; @Enumerated(EnumType.STRING) private OrderStatus orderStatus; @OneToMany(mappedBy = "order", cascade = CascadeType.ALL,orphanRemoval = true) private List<OrderItemsEntity> items; } package com.codingshuttle.ecommerce.order_service.entities; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Entity @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Table(name = "items") public class OrderItemsEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long productId; private Integer quantity; @ManyToOne @JoinColumn(name = "order_id") @JsonIgnore private OrdersEntity order; } package com.codingshuttle.ecommerce.order_service.entities.enums; public enum OrderStatus { CONFIRMED, CANCELLED, PENDING, DELIVERED }

    Configuration Class: (For Model Mapper) We need model mapper dependency.

    <dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.2.0</version> </dependency>
    package com.codingshuttle.ecommerce.order_service.configs; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class Mapper { @Bean public ModelMapper getMapper(){ return new ModelMapper(); } }

    Repository Class:

    package com.codingshuttle.ecommerce.order_service.repositories; import com.codingshuttle.ecommerce.order_service.entities.OrdersEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface OrderRepo extends JpaRepository<OrdersEntity,Long> { }

    Controller Class:

    package com.codingshuttle.ecommerce.order_service.controllers; import com.codingshuttle.ecommerce.order_service.dtos.OrderRequestDto; import com.codingshuttle.ecommerce.order_service.services.OrderService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequiredArgsConstructor @RequestMapping("/orders") @Slf4j public class OrderController { private final OrderService orderService; @GetMapping public ResponseEntity<List<OrderRequestDto>> getAllOrders(){ log.info("Fetching all orders via controller"); List<OrderRequestDto> orders = orderService.getAllOrders(); return ResponseEntity.ok(orders); } @GetMapping("/{id}") public ResponseEntity<OrderRequestDto> getOrderById(@PathVariable Long id){ log.info("Fetching order by id via controller"); OrderRequestDto order = orderService.getOrderById(id); return ResponseEntity.ok(order); } }

    Service Class:

    package com.codingshuttle.ecommerce.order_service.services; import com.codingshuttle.ecommerce.order_service.dtos.OrderRequestDto; import com.codingshuttle.ecommerce.order_service.entities.OrdersEntity; import com.codingshuttle.ecommerce.order_service.repositories.OrderRepo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.modelmapper.ModelMapper; import org.springframework.stereotype.Service; import java.util.List; @Service @Slf4j @RequiredArgsConstructor public class OrderService { private final OrderRepo orderRepo; private final ModelMapper modelMapper; public List<OrderRequestDto> getAllOrders(){ log.info("Fetching all orders"); List<OrdersEntity> orders = orderRepo.findAll(); return orders.stream() .map(order -> modelMapper.map(order, OrderRequestDto.class)) .toList(); } public OrderRequestDto getOrderById(Long id){ log.info("Fetching order by id"); OrdersEntity order = orderRepo.findById(id).orElseThrow(()->new RuntimeException("Order not found")); return modelMapper.map(order, OrderRequestDto.class); } }

    These are all simple crud operations codes.

    4. Running process#

    1. Go to the ‘service’ symbol > ‘+’ (add services) > ‘Run Configuration Type’.
    Ide image
    1. Tap on ‘Application’.
    Ide image
    Ide image

    You can right click on each service and you will able to run them.

    Conclusion#

    This article discusses the huge potential the microservices-based approach has toward scalability, real-time monitoring, and efficient operation in an Inventory Management System. Based on Spring Boot and REST APIs in conjunction with Docker and MySQL, the technological aspect of this solution ensures automation, fault tolerance, and cloud-native deployment for that flexible, reliable inventory management, prepared for future devices.

    Last updated on Mar 05, 2025