generated from pricelees/issue-pr-template
<!-- 제목 양식 --> <!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) --> ## 📝 관련 이슈 및 PR **PR과 관련된 이슈 번호** - #7 ## ✨ 작업 내용 <!-- 어떤 작업을 했는지 알려주세요! --> 1. 808c6675 에서 작업했던 정상 / 오류를 통합하는 객체를 사용하려 했으나, Swagger-UI상에서 응답 형식에 null 필드가 포함되는 문제로 다시 정상 / 오류 별도로 분리 2. Swagger-UI(문서화, 명세) 관련 코드는 인지하기 쉽도록 ../web -> ../docs 패키지로 이전 3. 현재까지 코틀린으로 마이그레이션 된 서비스를 대상으로, 응답에 ResponseEntity를 적용하고 \@ResponseStatus 제거 ## 🧪 테스트 <!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! --> 예정으로는 Issue에 작성했던 테스트까지 처리하려고 했으나, 테스트는 바로 다음에 진행 예정 ## 📚 참고 자료 및 기타 <!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! --> Reviewed-on: #8 Co-authored-by: pricelees <priceelees@gmail.com> Co-committed-by: pricelees <priceelees@gmail.com>
99 lines
3.5 KiB
Java
99 lines
3.5 KiB
Java
package roomescape.payment.client;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Map;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.http.HttpStatusCode;
|
|
import org.springframework.http.MediaType;
|
|
import org.springframework.http.client.ClientHttpResponse;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.web.client.RestClient;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
import roomescape.common.exception.ErrorType;
|
|
import roomescape.common.exception.RoomescapeException;
|
|
import roomescape.payment.dto.request.PaymentCancelRequest;
|
|
import roomescape.payment.dto.request.PaymentRequest;
|
|
import roomescape.payment.dto.response.PaymentCancelResponse;
|
|
import roomescape.payment.dto.response.PaymentResponse;
|
|
import roomescape.payment.dto.response.TossPaymentErrorResponse;
|
|
|
|
@Component
|
|
public class TossPaymentClient {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(TossPaymentClient.class);
|
|
|
|
private final RestClient restClient;
|
|
|
|
public TossPaymentClient(RestClient.Builder restClientBuilder) {
|
|
this.restClient = restClientBuilder.build();
|
|
}
|
|
|
|
public PaymentResponse confirmPayment(PaymentRequest paymentRequest) {
|
|
logPaymentInfo(paymentRequest);
|
|
return restClient.post()
|
|
.uri("/v1/payments/confirm")
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(paymentRequest)
|
|
.retrieve()
|
|
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(),
|
|
(req, res) -> handlePaymentError(res))
|
|
.body(PaymentResponse.class);
|
|
}
|
|
|
|
public PaymentCancelResponse cancelPayment(PaymentCancelRequest cancelRequest) {
|
|
logPaymentCancelInfo(cancelRequest);
|
|
Map<String, String> param = Map.of("cancelReason", cancelRequest.cancelReason());
|
|
|
|
return restClient.post()
|
|
.uri("/v1/payments/{paymentKey}/cancel", cancelRequest.paymentKey())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(param)
|
|
.retrieve()
|
|
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(),
|
|
(req, res) -> handlePaymentError(res))
|
|
.body(PaymentCancelResponse.class);
|
|
}
|
|
|
|
private void logPaymentInfo(PaymentRequest paymentRequest) {
|
|
log.info("결제 승인 요청: paymentKey={}, orderId={}, amount={}, paymentType={}",
|
|
paymentRequest.paymentKey(), paymentRequest.orderId(), paymentRequest.amount(),
|
|
paymentRequest.paymentType());
|
|
}
|
|
|
|
private void logPaymentCancelInfo(PaymentCancelRequest cancelRequest) {
|
|
log.info("결제 취소 요청: paymentKey={}, amount={}, cancelReason={}",
|
|
cancelRequest.paymentKey(), cancelRequest.amount(), cancelRequest.cancelReason());
|
|
}
|
|
|
|
private void handlePaymentError(ClientHttpResponse res)
|
|
throws IOException {
|
|
HttpStatusCode statusCode = res.getStatusCode();
|
|
ErrorType errorType = getErrorTypeByStatusCode(statusCode);
|
|
TossPaymentErrorResponse errorResponse = getErrorResponse(res);
|
|
|
|
throw new RoomescapeException(errorType,
|
|
String.format("[ErrorCode = %s, ErrorMessage = %s]", errorResponse.code(), errorResponse.message()),
|
|
statusCode);
|
|
}
|
|
|
|
private TossPaymentErrorResponse getErrorResponse(ClientHttpResponse res) throws IOException {
|
|
InputStream body = res.getBody();
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
TossPaymentErrorResponse errorResponse = objectMapper.readValue(body, TossPaymentErrorResponse.class);
|
|
body.close();
|
|
return errorResponse;
|
|
}
|
|
|
|
private ErrorType getErrorTypeByStatusCode(HttpStatusCode statusCode) {
|
|
if (statusCode.is4xxClientError()) {
|
|
return ErrorType.PAYMENT_ERROR;
|
|
}
|
|
return ErrorType.PAYMENT_SERVER_ERROR;
|
|
}
|
|
}
|