본문 바로가기
Spring Cloud

Spring Cloud(MSA) 실습 - 웹 쇼핑몰 2. 카달로그 서비스

by 장중앙 2021. 9. 16.

https://jangcenter.tistory.com/35에서 이어짐

 

Spring Cloud(MSA) 실습 - 웹 쇼핑몰 1. 기본 설정과 회원 서비스

실제 MSA를 위한 실습 MSA의 동작 학습/응용이 목적이기 때문에 상세한 기능 구현, 다자인은 신경쓰지 않고 RestController로 진행, MSA의 동작위주의 실습 시스템 구성 회원 서비스(User Microservice) 설계

jangcenter.tistory.com

 

카달로그 서비스(Catalogs Microservice) 설계

기능 apigateway-service URI Method
상품 목록 조회 /catalog-service/catalogs GET

 


카달로그 서비스 프로젝트 생성 및 기본설정

* h2의 버전 변경 자동으로 DB생성을 위해, modelmapper 의존성 추가

# porm.xml
.......		
        <dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
			<version>1.3.176</version>
		</dependency>
		
		<dependency>
			<groupId>org.modelmapper</groupId>
			<artifactId>modelmapper</artifactId>
			<version>2.3.8</version>
		</dependency>
	</dependencies>
.......

application.yml작성

server:
  port: 0

spring:
  application:
    name: catalog-service
  h2:
    console :
      enabled : true
      settings :
        web-allow-others: true
      path: /h2-console
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
  # 애플리케이션이 실행될때 초기데이터가 테이블에 들어갈 수 있도록 -> application.yml과 같은 위치에 data.sql파일 생성
  jpa :
    hibernate:
      ddl-auto: create-drop
    show-sql: true
    generate-ddl: true
    #스키마가 만들어지고 sql파일이 동작하게 해줌
    defer-datasource-initialization: true
      

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:8761/eureka

초기 데이터를 위해 application.yml과 같은 위치에 data.sql파일 생성

# data.sql

insert into catalog(product_id, product_name, stock, unit_price) values ('CAT_01', 'Milk', 10000, 1000);
insert into catalog(product_id, product_name, stock, unit_price) values ('CAT_02', 'Salt', 20000, 1500);
insert into catalog(product_id, product_name, stock, unit_price) values ('CAT_03', 'Water', 30000, 2000);

 

H2 Database 연동 및 데이터 확인

user-service에 할당된 포트를 확인 후 h2-console로 접속(localhost:{portnum}/h2-console)

* 할당된 포트는 discovery-service의 Eureka에서 확인가능

data.sql에 작성한 sql코드가 정상 작동되어 초기 데이터가 저장되어 있음

 

catalog-service를 apigateway-service에 등록

어플리케이션 이름으로 접근/라우팅을 위해 apigateway-service에 등록

apigateway-service의 application.yml에 catalog-service의 라우팅 정보를 추가

# apigateway-service/application.yml
....
      routes:
        ....
        - id: catalog-service
          predicates:
            - Path=/catalog-service/**
          uri: lb://CATALOG-SERVICE
....

catalog-service 기능 구현

DB를 위한 VO, DTO, JPA 클래스

VO 패키지

// ResponseCatalog.java
// 저장된 상품정보 데이터로 요청에 대한 응답
package com.example.MSA_web.vo;

import java.util.Date;

import com.fasterxml.jackson.annotation.JsonInclude;

import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseCatalog {
	private String productId;
	private String productName;
	private Integer unitPrice;
	private Integer stock;
	private Date createdAt;

}

DTO 패키지

// CatalogDto.java
// 제품 데이터 controller, service, repository간의 이동을 위해
package com.example.MSA_web.dto;

import lombok.Data;

@Data
public class CatalogDto {
	private String productId;
	private Integer qty;
	private Integer unitPrice;
	private Integer totalPrice;
	private String orderId;
	
	private String userId;
}

JPA 패키지

// CatalogEntity.java
// 실제 DB의 데이터 사용
package com.example.MSA_web.jpa;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.ColumnDefault;

import lombok.Data;

@Data
@Entity
@Table(name="catalog")
public class CatalogEntity {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	@Column(nullable=false, length=120, unique=true)
	private String productId;
	
	@Column(nullable=false)
	private String productName;
	
	@Column(nullable=false)
	private Integer stock;
	
	@Column(nullable=false)
	private Integer unitPrice;

	@Column(nullable = false, updatable = false, insertable = false)
	@ColumnDefault(value = "CURRENT_TIMESTAMP")
	private Date createdAt;
}

-------------------------------------------------------------------------------------------
// CatalogRepository
// DB 데이터의 사용을 위해
package com.example.MSA_web.jpa;

import org.springframework.data.repository.CrudRepository;

public interface CatalogRepository extends CrudRepository<CatalogEntity, Long>{
	CatalogEntity findByProductId(String productId);
}

 

모듈 기능구현

controller

// CatalogController.java
package com.example.MSA_web.controller;

import java.util.ArrayList;
import java.util.List;
import org.springframework.core.env.Environment;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.MSA_web.jpa.CatalogEntity;
import com.example.MSA_web.service.CatalogService;
import com.example.MSA_web.vo.ResponseCatalog;

@RestController
@RequestMapping("/catalog-service")
public class CatalogController {
	Environment env;
	CatalogService catalogService;

	@Autowired
	public CatalogController(Environment env, CatalogService catalogService) {
		this.env = env;
		this.catalogService = catalogService;
	}

	@GetMapping("/health_check")
	public String healthCheck() {
		// 할당받은 포트번호 출력
		return String.format("OK ... Port num = %s", env.getProperty("local.server.port"));
	}

	@GetMapping("/catalogs")
	public ResponseEntity<List<ResponseCatalog>> getCatalogs() {//모든 상품정보를 출력
		Iterable<CatalogEntity> catalogList = catalogService.getAllCatalogs();

		// CatalogEntity ->ResponseCatalog
		List<ResponseCatalog> resultList = new ArrayList<>();
		catalogList.forEach(v -> {
			resultList.add(new ModelMapper().map(v, ResponseCatalog.class));
		});
		return ResponseEntity.status(HttpStatus.OK).body(resultList);
	}
}

 

댓글