카테고리:

업데이트:

1. 들어가기

이전 포스트에서는 템플릿 메서드 패턴을 이용해 서비스를 분리해보았습니다.

이번에는 분리한 서비스를 클라이언트의 요청에 맞게 처리하도록 연결해봅시다.

2. Controller 중복 제거

분리한 서비스와 연결하기에 앞서 Controller 코드를 봅시다.

  @RestController
  @RequestMapping("/easy-pay")
  public class EasyPayController {

    // 토스페이 요청 API
    @PostMapping("/request/toss")
    public JSONObject createTossPay() { ... }

    // 토스페이 승인 API
    @PostMapping("/approve/toss")
    public JSONObject approveTossPay(@RequestBody TossPay tossPay) { ... }

    // 카카오페이 요청 API
    @PostMapping("/request/kakao")
    public JSONObject createKakaoPay() { ... }

    // 카카오페이 승인 API
    @PostMapping("/approve/kakao")
    public JSONObject approveKakaoPay(@RequestBody TossPay tossPay) { ... }
  }

요청 API와 승인 API 코드가 각 간편결제마다 중복되어 있는 것을 볼 수 있습니다.

공통 메서드를 만들어 간편결제를 추가하더라도 Controller 코드는 수정하지 않도록 변경해보겠습니다.

요청 API는 request/toss & kakao, 승인 API는 approve/toss & kakao이므로

URL을 액션/간편결제 식으로 공통 메서드를 만들 수 있겠네요.

그럼 PathVariable 어노테이션을 사용해 다음과 같이 변경할 수 있습니다.

  @RestController
  @RequestMapping("/easy-pay")
  public class EasyPayController {

    // 간편결제 요청
    @PostMapping("/request/{type}")
    public JSONObject request(@PathVariable String type, @RequestBody EasyPay easyPay) { ... }

    // 간편결제 승인
    @PostMapping("/approve/{type}")
    public JSONObject approve(@PathVariable String type, @RequestBody EasyPay easyPay) { ... }
  }

이렇게 작성하면 어떤 간편 결제가 추가되더라도 Controller 코드는 수정할 필요가 없습니다.

3. Controller와 Service 연결

그럼, 이제는 리팩토링한 Controller와 분리했던 Service를 연결해봅시다.

Controller의 공통 메서드는 type을 통해 어떤 간편결제 서비스를 사용해야 하는지 알 수 있습니다.

그러므로 type에 해당하는 Service 타입을 Bean에서 들고 오면 되겠네요.

enum을 사용해 우리가 사용할 간편결제를 정의하고 매개변수로 Service 타입을 매핑시키겠습니다.

  @AllArgsConstructor
  public enum EasyPayType {
    TOSS(TossPayService.class),
    KAKAO(KakaoPayService.class);

    @Getter
    private Class<? extends EasyPayService> clazz;
  }

? extends EasyPayService

EasyPayService 인터페이스를 구현한 Service로 한정

그럼, 클라이언트 요청에 포함되어 있는 type 데이터를 enum으로 변환해주는 메서드를 만들어보겠습니다.

  private EasyPayType getPlatform(String type) {
    return EasyPayType.valueOf(type.toUpperCase());
  }

enum 데이터는 Java 네이밍 룰에 의해 대문자로 선언했기에 type을 대문자로 변경해야 합니다.

그 후, enum의 valueOf 메서드를 통해 우리가 매핑했던 서비스를 호출합니다.

만약, valueOf 메서드에 해당하는 값이 없다면 예외가 발생하는데

이때는 ExceptionHandler를 사용해 예외를 처리할 수 있습니다.

이번 포스트에서는 다루지 않겠습니다.

마지막으로 팩토리 메서드를 만들어 Bean에서 서비스를 호출하도록 합니다.

  @Component
  @RequiredArgsConstructor
  public class EasyPayFactory {

    // Spring Container
    private final ApplicationContext applicationContext;

    // 간편 결제 서비스 인스턴스 제공 메서드
    public EasyPayService getInstance(EasyPayType type) {
      return applicationContext.getBean(type.getClazz());
    }
  }

자, 그럼 이제 코드를 종합해보겠습니다.

  @RestController
  @RequiredArgsConstructor
  @RequestMapping("/easy-pay")
  public class EasyPayController {

    // 팩토리 메서드
    private final EasyPayFactory easyPayFactory;

    // 간편결제 요청
    @PostMapping("/request/{type}")
    public JSONObject request(@PathVariable String type, @RequestBody EasyPay easyPay) { 
      return easyPayFactory.getInstance(getPlatform(type)).requestPay(easyPay);
    }

    // 간편결제 승인
    @PostMapping("/approve/{type}")
    public JSONObject approve(@PathVariable String type, @RequestBody EasyPay easyPay) {
      return easyPayFactory.getInstance(getPlatform(type)).approvePay(easyPay);
    }

    // 클라이언트 type 데이터를 enum 타입으로 변환하는 메서드
    private EasyPayType getPlatform(String type) {
      return EasyPayType.valueOf(type.toUpperCase());
    }
  }

다음 포스트에서는 Feign Client를 통해 HTTP 통신을 비즈니스 로직에서 분리해보겠습니다.

비즈니스 로직에서 HTTP 통신 분리

            
              📕 개인 기록용 블로그입니다.
              😊 오타나 잘못된 정보가 있을 경우 댓글이나 메일로 말씀해주시면 바로 수정하겠습니다! 😊
          

댓글남기기