Skip to content

Latest commit

 

History

History
320 lines (265 loc) · 10 KB

File metadata and controls

320 lines (265 loc) · 10 KB

Lab 3: Creating the Product Service Microservice

Objective

Set up a ProductService microservice with Spring Boot. This microservice will handle product information and connect to its own MySQL database, following best practices in modularity and separation.


Steps

1. Open the Project in VS Code

  • Ensure the MicroservicesProject workspace is open in VS Code.

2. Create a ProductService Folder

  • Inside the workspace directory, create a new folder named ProductService.

3. Generate ProductService with Spring Initializr

  • Open the Command Palette (View > Command Palette or Ctrl+Shift+P).
  • Select Spring Initializr: Generate a Maven Project.
  • Configure the options as follows:
    • Group Id: com.microservices
    • Artifact Id: product-service
    • Name: ProductService
    • Add dependencies: Spring Web, MySQL Driver, Spring Data JPA, MySQL Driver.
    • Save the project in the ProductService folder.

3.1 Verify Dependencies in pom.xml

   <dependencies>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-data-jpa</artifactId>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
           </dependency>

           <dependency>
               <groupId>com.mysql</groupId>
               <artifactId>mysql-connector-j</artifactId>
               <scope>runtime</scope>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-test</artifactId>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>jakarta.persistence</groupId>
               <artifactId>jakarta.persistence-api</artifactId>
               <version>3.1.0</version>
           </dependency>
       </dependencies>

4. Configure ProductService Application Properties

  • In ProductService/src/main/resources, open application.properties.
  • Set up the following properties to configure the application’s port and MySQL database:
    server.port=8082
    spring.datasource.username=root
    spring.datasource.url=jdbc:mysql://localhost:3307/product_db
    spring.datasource.password=Test1234!
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true

5. Create Product Entity

  • In the com.microservices.product_service package, create a folder model and a new class called Product.java.
  • Define the Product entity:
    package com.microservices.product_service.model;
    
    import jakarta.persistence.Entity;
    import jakarta.persistence.GeneratedValue;
    import jakarta.persistence.GenerationType;
    import jakarta.persistence.Id;
    
    @Entity
    public class Product {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private String description;
        private double price;
    
        // Getters and Setters
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    }

6. Create the Product Repository

  • In the same package, create a folder repository and a new interface ProductRepository.java:
    package com.microservices.product_service.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import com.microservices.product_service.model.Product;
    
    public interface ProductRepository extends JpaRepository<Product, Long> {
    }
  • This repository will handle database operations for the Product entity.

7. Implement the Product Service Layer

  • Create a folder service and a class ProductService.java:

    package com.microservices.product_service.service;
    
    import com.microservices.product_service.model.Product;
    import com.microservices.product_service.repository.ProductRepository;
    import org.springframework.stereotype.Service;
    import java.util.List;
    
    @Service
    public class ProductService {
        private final ProductRepository productRepository;
    
        public ProductService(ProductRepository productRepository) {
            this.productRepository = productRepository;
        }
    
        public List<Product> getAllProducts() {
            return productRepository.findAll();
        }
    
        public Product createProduct(Product product) {
            return productRepository.save(product);
        }
    }

8. Develop the Product Controller

  • Create a folder controller and a class ProductController.java:
        package com.microservices.product_service.controller;
    
        import com.microservices.product_service.model.Product;
        import com.microservices.product_service.service.ProductService;
        import org.springframework.web.bind.annotation.*;
    
        import java.util.List;
    
        @RestController
        @RequestMapping("/api/products")
        public class ProductController {
            private final ProductService productService;
    
            public ProductController(ProductService productService) {
                this.productService = productService;
            }
    
            @GetMapping
            public List<Product> getAllProducts() {
                return productService.getAllProducts();
            }
    
            @PostMapping
            public Product createProduct(@RequestBody Product product) {
                return productService.createProduct(product);
            }
        }

9. Containerize ProductService with Docker

  • In the ProductService directory, create a Dockerfile:
    FROM openjdk:17
    EXPOSE 8082
    ADD target/product-service-0.0.1-SNAPSHOT.jar product-service.jar
    ENTRYPOINT ["java", "-jar", "product-service.jar"]
  • Do a build
    ./mvnw clean package   # Linux / Mac
  • Build the Docker image for ProductService:
    docker build -t product-service .

10. Add ProductService to Docker Compose

  • In the MicroservicesProject directory, open docker-compose.yml.
  • Add the following configuration for ProductService:
    version: '3.1'
    services:
    
    # MySQL for UserService
    mysql-user:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: Test1234!
      MYSQL_DATABASE: user_db
    ports:
      - "3306:3306"
    
    # MySQL for ProductService
    mysql-product:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: Test1234!
      MYSQL_DATABASE: product_db
    ports:
      - "3307:3306"  # Expose port 3307 on host, but map to 3306 in the container
    
    # UserService
    user-service:
    build: ./UserService
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql-user:3306/user_db
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: Test1234!
      SPRING_JPA_HIBERNATE_DDL_AUTO: update
    ports:
      - "8081:8081"
    depends_on:
      - mysql-user
    
    # ProductService
    product-service:
    build: ./ProductService
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql-product:3306/product_db
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: Test1234!
      SPRING_JPA_HIBERNATE_DDL_AUTO: update
    ports:
      - "8082:8082"
    depends_on:
      - mysql-product

11. Run Docker Compose

  • Start the MySQL container and ProductService together:
    docker-compose up -d

12. Test ProductService with Dockerized MySQL

  • Verify that ProductService can connect to its MySQL database.
  • Use Postman to test GET and POST endpoints with Docker running.

13. Implement Exception Handling in ProductService

  • Create a folder exception and a class ProductNotFoundException.java:
   package com.microservices.product_service.exception;

   public class ProductNotFoundException extends RuntimeException {
       public ProductNotFoundException(String message) {
           super(message);
       }
   }
  • Add custom exception handling in ProductController for resource not found cases:
    @ExceptionHandler(ProductNotFoundException.class)
    public ResponseEntity<String> handleProductNotFound(ProductNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
    }

14. Discuss Best Practices for Modularity and Separation

  • Emphasize the importance of keeping each service modular, with its own database and Docker configuration.

15. Summary of Lab

  • Review what was covered in this lab:
    • Created and configured ProductService.
    • Dockerized ProductService and connected it to a separate MySQL database.
    • Tested endpoints, exception handling, and confirmed modularity.

Extra Exercise (20 minutes):

  1. Additional Product Fields:

    • Add fields such as category, stockQuantity, and supplier to the Product entity.
    • Ensure they are included in the ProductController endpoints.
  2. Filter Products by Category:

    • Add a new endpoint in ProductController to filter products by category (e.g., GET /api/products/category/{category}).
    • Practice writing and testing a custom query for this.
  3. Docker Practice:

    • Build the Docker image for ProductService with a different tag version, like product-service:v2.
    • Verify that both versions of the container can run simultaneously and test accessing each.