refactor: PaymentConfig의 빈 타입을 RestClient -> RestClient.Builder으로 롤백 및 테스트 전용 property 추가

This commit is contained in:
이상진 2025-07-16 11:16:17 +09:00
parent 635f015b3c
commit 51b0877508
4 changed files with 38 additions and 39 deletions

View File

@ -15,21 +15,19 @@ import java.util.*
class PaymentConfig {
@Bean
fun paymentClient(
fun tossPaymentClientBuilder(
paymentProperties: PaymentProperties,
restClientBuilder: RestClient.Builder
): RestClient {
): RestClient.Builder {
val settings: ClientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults().also {
it.withReadTimeout(Duration.ofSeconds(paymentProperties.readTimeout.toLong()))
it.withConnectTimeout(Duration.ofSeconds(paymentProperties.connectTimeout.toLong()))
}
val requestFactory = ClientHttpRequestFactoryBuilder.jdk().build(settings)
return restClientBuilder
return RestClient.builder()
.baseUrl(paymentProperties.apiBaseUrl)
.defaultHeader("Authorization", getAuthorizations(paymentProperties.confirmSecretKey))
.requestFactory(requestFactory)
.build()
}
private fun getAuthorizations(secretKey: String): String {

View File

@ -16,58 +16,55 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import roomescape.common.exception.ErrorType;
import roomescape.common.exception.RoomescapeException;
import roomescape.payment.web.dto.request.PaymentCancelRequest;
import roomescape.payment.web.dto.request.PaymentRequest;
import roomescape.payment.web.dto.response.PaymentCancelResponse;
import roomescape.payment.web.dto.response.PaymentResponse;
import roomescape.payment.web.dto.response.TossPaymentErrorResponse;
import roomescape.payment.web.PaymentApprove;
import roomescape.payment.web.PaymentCancel;
@Component
public class TossPaymentClient {
private static final Logger log = LoggerFactory.getLogger(TossPaymentClient.class);
private final RestClient paymentClient;
private final RestClient tossPaymentClient;
public TossPaymentClient(RestClient paymentClient) {
this.paymentClient = paymentClient;
public TossPaymentClient(RestClient.Builder tossPaymentClientBuilder) {
this.tossPaymentClient = tossPaymentClientBuilder.build();
}
public PaymentResponse confirmPayment(PaymentRequest paymentRequest) {
public PaymentApprove.Response confirmPayment(PaymentApprove.Request paymentRequest) {
logPaymentInfo(paymentRequest);
return paymentClient.post()
return tossPaymentClient.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);
.body(PaymentApprove.Response.class);
}
public PaymentCancelResponse cancelPayment(PaymentCancelRequest cancelRequest) {
public PaymentCancel.Response cancelPayment(PaymentCancel.Request cancelRequest) {
logPaymentCancelInfo(cancelRequest);
Map<String, String> param = Map.of("cancelReason", cancelRequest.cancelReason());
Map<String, String> param = Map.of("cancelReason", cancelRequest.cancelReason);
return paymentClient.post()
.uri("/v1/payments/{paymentKey}/cancel", cancelRequest.paymentKey())
return tossPaymentClient.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);
.body(PaymentCancel.Response.class);
}
private void logPaymentInfo(PaymentRequest paymentRequest) {
private void logPaymentInfo(PaymentApprove.Request paymentRequest) {
log.info("결제 승인 요청: paymentKey={}, orderId={}, amount={}, paymentType={}",
paymentRequest.paymentKey(), paymentRequest.orderId(), paymentRequest.amount(),
paymentRequest.paymentType());
paymentRequest.paymentKey, paymentRequest.orderId, paymentRequest.amount,
paymentRequest.paymentType);
}
private void logPaymentCancelInfo(PaymentCancelRequest cancelRequest) {
private void logPaymentCancelInfo(PaymentCancel.Request cancelRequest) {
log.info("결제 취소 요청: paymentKey={}, amount={}, cancelReason={}",
cancelRequest.paymentKey(), cancelRequest.amount(), cancelRequest.cancelReason());
cancelRequest.paymentKey, cancelRequest.amount, cancelRequest.cancelReason);
}
private void handlePaymentError(ClientHttpResponse res)
@ -77,7 +74,7 @@ public class TossPaymentClient {
TossPaymentErrorResponse errorResponse = getErrorResponse(res);
throw new RoomescapeException(errorType,
String.format("[ErrorCode = %s, ErrorMessage = %s]", errorResponse.code(), errorResponse.message()),
String.format("[ErrorCode = %s, ErrorMessage = %s]", errorResponse.code, errorResponse.message),
statusCode);
}

View File

@ -19,10 +19,8 @@ import org.springframework.test.web.client.MockRestServiceServer;
import roomescape.common.exception.ErrorType;
import roomescape.common.exception.RoomescapeException;
import roomescape.payment.SampleTossPaymentConst;
import roomescape.payment.web.dto.request.PaymentCancelRequest;
import roomescape.payment.web.dto.request.PaymentRequest;
import roomescape.payment.web.dto.response.PaymentCancelResponse;
import roomescape.payment.web.dto.response.PaymentResponse;
import roomescape.payment.web.PaymentApprove;
import roomescape.payment.web.PaymentCancel;
@RestClientTest(TossPaymentClient.class)
class TossPaymentClientTest {
@ -46,12 +44,12 @@ class TossPaymentClientTest {
.body(SampleTossPaymentConst.confirmJson));
// when
PaymentRequest paymentRequest = SampleTossPaymentConst.paymentRequest;
PaymentResponse paymentResponse = tossPaymentClient.confirmPayment(paymentRequest);
PaymentApprove.Request paymentRequest = SampleTossPaymentConst.paymentRequest;
PaymentApprove.Response paymentResponse = tossPaymentClient.confirmPayment(paymentRequest);
// then
assertThat(paymentResponse.paymentKey()).isEqualTo(paymentRequest.paymentKey());
assertThat(paymentResponse.orderId()).isEqualTo(paymentRequest.orderId());
assertThat(paymentResponse.paymentKey).isEqualTo(paymentRequest.paymentKey);
assertThat(paymentResponse.orderId).isEqualTo(paymentRequest.orderId);
}
@Test
@ -67,12 +65,12 @@ class TossPaymentClientTest {
.body(SampleTossPaymentConst.cancelJson));
// when
PaymentCancelRequest cancelRequest = SampleTossPaymentConst.cancelRequest;
PaymentCancelResponse paymentCancelResponse = tossPaymentClient.cancelPayment(cancelRequest);
PaymentCancel.Request cancelRequest = SampleTossPaymentConst.cancelRequest;
PaymentCancel.Response paymentCancelResponse = tossPaymentClient.cancelPayment(cancelRequest);
// then
assertThat(paymentCancelResponse.cancelStatus()).isEqualTo("DONE");
assertThat(paymentCancelResponse.cancelReason()).isEqualTo(cancelRequest.cancelReason());
assertThat(paymentCancelResponse.cancelStatus).isEqualTo("DONE");
assertThat(paymentCancelResponse.cancelReason).isEqualTo(cancelRequest.cancelReason);
}
@Test

View File

@ -25,3 +25,9 @@ security:
secret-key: daijawligagaf@LIJ$@U)9nagnalkkgalijaddljfi
access:
expire-length: 1800000 # 30 분
payment:
api-base-url: https://api.tosspayments.com
confirm-secret-key: test_gsk_docs_OaPz8L5KdmQXkzRz3y47BMw6
read-timeout: 3
connect-timeout: 30