[SpringCloud MSA]Catalogs and Orders Microservice

zzarbttoo·2021년 9월 9일
0

이 글은 인프런 강의 "Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)"를 정리한 글입니다. 문제/오류가 있을 시 댓글로 알려주시면 감사드리겠습니다

강의의 모든 부분을 정리하는 것이 아니고 비슷한 부분은 생략합니다


ApiGateway-Service

application.yml
server:
  port: 8000

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url :
      defaultZone: http://localhost:8761/eureka
spring:
  application:
    name: apigateway-service
  cloud:
    gateway:
      default-filters:
        - name : GlobalFilter # Component 이름
          args :
            baseMessage : Spring Cloud Gateway Global Filter
            preLogger : true
            postLogger : true
      routes:
        - id: first-service
          uri: lb://MY-FIRST-SERVICE
          predicates:
            - Path=/first-service/**
          filters:
            - CustomFilter
        - id: second-service
          uri: lb://MY-SECOND-SERVICE
          predicates:
            - Path=/second-service/**
          filters:
            - name: CustomFilter
            - name: LoggingFilter
              args:
                baseMessage: Hi, there
                preLogger: true
                postLogger: true
        - id: catalog-service
          uri: lb://CATALOG-SERVICE
          predicates:
            - Path=/catalog-service/**
          filters:
            - CustomFilter
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user-service/**
          filters:
            - CustomFilter
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/order-service/**
          filters:
  • catalog-service, user-service, order-service에 대해서 라우팅 기능을 추가한다


UserService

uri 값이 달라 apigateway를 사용할 때와 안할 때의 차이가 난다

controller
@RestController
@RequestMapping("/user-service/")
public class UserController {
...
}
  • controller 상단에 @RequestMapping("/user-service/")로 바꿔준다

@RestController
@RequestMapping("/user-service/")
public class UserController {

... 생략

    @GetMapping("/health_check")
    public String status(){
        //포트번호를 출력할 수 있도록 변경
        return String.format("It's Working in User Service on Port %s", env.getProperty("local.server.port"));
    }

	
    // 회원가입
    @PostMapping("/users")
    public ResponseEntity<ResponseUser> createUser(@RequestBody RequestUser user){
	...
    }

    // userList 
    @GetMapping("/users")
    public ResponseEntity<List<ResponseUser>> getUsers(){

        Iterable<UserEntity> userList = userService.getUserByAll();

        List<ResponseUser> result = new ArrayList<>();

        userList.forEach(v -> {
            result.add(new ModelMapper().map(v, ResponseUser.class));

        });

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }
	
    //userId 를 전달하면 세부사항을 전달하도록 함
    @GetMapping("/users/{userId}")
    public ResponseEntity<ResponseUser> getUser(@PathVariable("userId") String userId){

        UserDto userDto= userService.getUserByUserId(userId);

        ResponseUser returnValue = new ModelMapper().map(userDto, ResponseUser.class);

        return ResponseEntity.status(HttpStatus.OK).body(returnValue);
    }

}
  • 같은 uri이지만 호출을 하는 Http Method에 따라 다른 값을 전달해주도록 한다

UserDto, ResponseUser

@Data
public class UserDto {

... 생략
private List<ResponseOrder> orders;

}

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseUser {

... 생략
    private List<ResponseOrder> orders;

}
  • UserDto, ResponseUser에 List orders를 추가한다(Entity에는 추가하지 않는다)
  • Response Json이 null이면 반환하지 않도록 한다

ResponseOrder
package com.zzarbttoo.userservice.vo;

import lombok.Data;

import java.util.Date;

@Data
public class ResponseOrder {

    private String productId;
    private Integer qty;
    private Integer unitPrice;
    private Integer totalPrice;
    private Date createAt;

    private String orderId;

}
  • ResponseOrder(order service가 아니기 때문에 공개된 정보인 ResponseOrder을 이용) list 포함
  • order service의 ResponseOrder과 내용이 같아야한다

UserServiceImpl(UserService에도 function 생성)
@Service
public class UserServiceImpl implements UserService{

... 생략

    @Override
    public UserDto getUserByUserId(String userId) {

        UserEntity userEntity = userRepository.findByUserId(userId);

        if(userEntity == null){
            //spring security
            throw new UsernameNotFoundException("User not found");
        }

        UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);

        List<ResponseOrder> orders = new ArrayList<>();
        userDto.setOrders(orders);

        return userDto;
    }

    @Override
    public Iterable<UserEntity> getUserByAll() {
        return userRepository.findAll();
    }
}
  • userId로 userEntity를 찾을 수 있도록 함(없을 경우 에러 발생)

UserRepository
package com.zzarbttoo.userservice.jpa;

import org.springframework.data.repository.CrudRepository;

//CRUD 작업을 하기 때문에 CrudRepository 상속
//Entity 정보 입력, 기본키 classType 입력
public interface UserRepository extends CrudRepository<UserEntity, Long> {

    UserEntity findByUserId(String userId);


}
  • id 값으로 UserEntity를 찾을 수 있도록 함
  • findBy~ 형태로 select where 을 할 수 있음

| 실행


Catalog-service

application.yml
... 생략 
  
spring:
  application:
    name: catalog-service
  h2:
    console:
      enabled: true
      settings:
        web-allow-others: true
      path: /h2-console
  jpa:
    hibernate:
      ddl-auto : create-drop
    show-sql : true
    generate-ddl : true
    database: h2
  datasource:
    driver-class-name: org.h2.Driver
    url : jdbc:h2:mem:testdb

... 

#logging level 지정
logging:
  level:
    com.zzarbttoo.catalogservice : DEBUG  
  • table을 자동으로 create하거나 drop하고, 시작과 동시에 아래의 sql 값을 실행하도록 함 (hibernate ddl-auto create-drop)
  • logger level을 설정함(DEBUG 출력 가능), 로그량 줄일 수 있음
data.sql
insert into catalog(product_id, product_name, stock, unit_price)
values('CATALOG-001', 'Berlin', 100, 1500);
insert into catalog(product_id, product_name, stock, unit_price)
values('CATALOG-002', 'Tokyo', 110, 1000);
insert into catalog(product_id, product_name, stock, unit_price)
values('CATALOG-003', 'Stockholm', 120, 2000);  
  • 세개의 물품을 카탈로그에 넣고 시작
DTO, Entity

| 실행

  • table이 생성되는 것을 console에서 확인할 수 있다
  • catalog들이 미리 등록이 되어 있는 것을 확인할 수 있다

Order Service

application.yml
... 생략
  
spring:
  application:
    name: order-service
  h2:
    console:
      enabled: true
      settings:
        web-allow-others: true
      path: /h2-console
  jpa:
    hibernate:
      ddl-auto : update #초기 데이터를 추가하지 않을 것
    database: h2
  datasource:
    driver-class-name: org.h2.Driver
...
  • 초기 데이터를 추가할 것이 아니기 때문에 ddl-auto를 update로 설정

OrderController
@Slf4j
@RestController
@RequestMapping("/order-service")
public class OrderController {

    Environment env;
    OrderService orderService;

    @Autowired
    public OrderController(Environment env, OrderService orderService) {
        this.env = env;
        this.orderService = orderService;
    }

    @GetMapping("/health_check")
    public String status(){
        //포트번호를 출력할 수 있도록 변경
        return String.format("It's Working in Catalog Service on Port %s", env.getProperty("local.server.port"));
    }

    //http://127.0.0.1:0/order-service/{user_id}/orders/
    @PostMapping("/{userId}/orders")
    public ResponseEntity<ResponseOrder> createOrder(@PathVariable("userId") String userId, @RequestBody RequestOrder requestOrder){

        log.info("requestOrder ::: " + requestOrder.toString());

        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

        OrderDto orderDto = mapper.map(requestOrder, OrderDto.class);

        log.info("orderDto ::: " + orderDto.toString());

        orderDto.setUserId(userId);
        OrderDto createdOrder = orderService.createOrder(orderDto);

        ResponseOrder responseOrder = mapper.map(createdOrder, ResponseOrder.class);

        log.info("responseOrder ::: " + responseOrder);

        return ResponseEntity.status(HttpStatus.CREATED).body(responseOrder);

    }

    @GetMapping("/{userId}/orders")
    public ResponseEntity<List<ResponseOrder>> getOrder(@PathVariable("userId") String userId){
        Iterable<OrderEntity> orderList = orderService.getOrdersByUserId(userId);

        List<ResponseOrder> result = new ArrayList<>();
        orderList.forEach(v -> {
            result.add(new ModelMapper().map(v, ResponseOrder.class));
        });

        return ResponseEntity.status(HttpStatus.OK).body(result);


    }

}
  • {userId}/orders를 get방식으로 보낼 경우 특정 회원이 주문한 것들의 목록을 보여준다
  • post 방식으로 보낼 경우 새로운 주문을 추가한다
profile
나는야 누워있는 개발머신

0개의 댓글