Microservices E-Commerce

Welcome to our microservices-based e-commerce application, utilizing technologies such as Consul Discovery, Spring Cloud Config, Spring Cloud Gateway, Angular, and other specific services.

Architecture:

📌 1. CONFIG SERVICE: (Click to expand 🖱)
Consul registered services:
📌 2. CUSTOMER-SERVICE (Click to expand 🖱)
Entity Customer
@Entity
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class Customer {
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private String email;
}
Repository CustomerRepository
@RepositoryRestResource
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Données de test
@Bean
CommandLineRunner start(CustomerRepository customerRepository){
        return args -> {
                customerRepository.saveAll(List.of(
                        Customer.builder().name("Mohamed").email("med@gmail.com").build(),
                        Customer.builder().name("Hassan").email("hasan@gmail.com").build(),
                        Customer.builder().name("IMane").email("imane@gmail.com").build()
                ));
                customerRepository.findAll().forEach(System.out::println);
        };
}
Customer service Test
📌 3. GATEWAY-SERVICE (Click to expand 🖱)
Bean de configuration
Configuration de la Gateway
Test de la gateway
📌 4. INVENTORY-SERVICE (Click to expand 🖱)
Entity Product
@Entity
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class Product {
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private double price;
        private int quantity;
}
Repository ProductRepository
@RepositoryRestResource
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Données de test
@Bean
CommandLineRunner start(ProductRepository productRepository)
{
        return args -> {
                Random
                random = new Random();
                for (int i = 1;
                i < 10;
                i++
        )
                {
                        productRepository.saveAll(List.of(
                                Product.builder()
                                        .name("Laptop " + i)
                                        .price(1200 + Math.random() * 10000)
                                        .quantity(1 + random.nextInt(200)).build()
                        ));
                }

        };
}
Test de l'inventory service
📌 5. ORDER-SERVICE (Click to expand 🖱)
Entity Order
@Entity
@Table(name="orders")
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class Order {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Date createdAt;
    private OrderStatus status;
    private Long customerId;
    @Transient
    private Customer customer;
    @OneToMany(mappedBy = "order")
    private List<ProductItem> productItems;

    public double getTotal(){
        double somme=0;
        for(ProductItem pi:productItems){
            somme+=pi.getAmount();
        }
        return somme;
    }
}
Entity ProductItem
@Entity
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class ProductItem {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long productId;
    @Transient
    private Product product;
    private double price;
    private int quantity;
    private double discount;
    @ManyToOne
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Order order;
    public double getAmount(){
        return price*quantity*(1-discount);
    }
}
Customer Model
@Data
public class Customer {
    private Long id;
    private String name;
    private String email;
}
Product Model
@Data
public class Product {
    private Long id;
    private String name;
    private double price;
    private int quantity;
}
Repository OrderRepository
@RepositoryRestResource
public interface OrderRepository extends JpaRepository<Order, Long> {
    @RestResource(path = "/byCustomerId")
    List<Order> findByCustomerId(@Param("customerId") Long customerId);
}
Customer Rest Client
@FeignClient(name = "customer-service")
public interface CustomerRestClientService {
@GetMapping("/customers/{id}?projection=fullCustomer")
    public Customer customerById(@PathVariable Long id);
@GetMapping("/customers?projection=fullCustomer")
    public PagedModel<Customer> allCustomers();
}
Inventory Rest Client
@FeignClient(name = "inventory-service")
public interface InventoryRestClientService {
    @GetMapping("/products/{id}?projection=fullProduct")
    public Product productById(@PathVariable Long id);
    @GetMapping("/products?projection=fullProduct")
    public PagedModel<Product> allProducts();
}
Configuration
fullOrder
@GetMapping("/fullOrder/{id}")
public Order getOrder(@PathVariable Long id){
    Order order=orderRepository.findById(id).get();
    Customer customer=customerRestClientService.customerById(order.getCustomerId());
    order.setCustomer(customer);
    order.getProductItems().forEach(pi->{
        Product product=inventoryRestClientService.productById(pi.getProductId());
        pi.setProduct(product);
    });
    return order;
}
📌 6. BILLING-SERVICE avec consul config et vault (Click to expand 🖱)
Dependencies
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
Consul config
Controlleur de test
@RestController
public class ConsulConfigRestController {
    @Autowired
    private MyConsulConfig myConsulConfig;
    @Autowired
    private MyVaultConfig myVaultConfig;
    @Value("${token.accessTokenTimeout}")
    private long accessTokenTimeout;
    @Value("${token.refreshTokenTimeout}")
    private long refreshTokenTimeout;
}
Avec class de configuration
@RestController
public class ConsulConfigRestController {
    @Autowired
    private MyConsulConfig myConsulConfig;
    @Autowired
    private MyVaultConfig myVaultConfig;
    //@Value("${token.accessTokenTimeout}")
    //private long accessTokenTimeout;
    //@Value("${token.refreshTokenTimeout}")
    //private long refreshTokenTimeout;
    @GetMapping("/myConfig")
    public Map<String,Object> myConfig(){
        return Map.of("consulConfig",myConsulConfig, "vaultConfig",myVaultConfig);
    }
}
Configuration des secrets avec vault
📌 7. FRONTEND ANGULAR (Click to expand 🖱)
Customers list
Products list
Orders list
Order details