콘서트 티켓팅 사이트를 개발하면서 티켓을 예매하기 위해 결제 시스템이 필요했습니다. 여러 결제 시스템을 고려해보면서 친숙하면서 직관적인 카카오 페이를 선택하게 되었습니다.

const paymentData = {
cid: user_cid,
partner_order_id: partner_order_id,
partner_user_id: nickName,
item_name: "포인트 충전",
quantity: 1,
total_amount: total_amount,
tax_free_amount: 0,
approval_url: success_url,
cancel_url: fail_url,
fail_url: fail_url,
};
const preparePayment = async (paymentData) => {
const response = await $.post(
chargeRequest,
paymentData
);
if (response.status === 200) {
// PC에서 결제 진행
const tid = response.data.result.tid;
localStorage.setItem("tid", tid);
window.location.href = response.data.result.next_redirect_pc_url;
} else {
alert(ErrorMessage);
}
return response.data;
};
const data = {
cid: "TC0ONETIME",
tid: tid,
partner_order_id: partner_order_id,
partner_user_id: nickName,
pg_token: pg_token,
};
// 결제 승인 API를 호출합니다.
$.post(`/payment-service/api/v1/reservation/approve/${id}`, data)
.then((response) => {
if (response.status === 200) {
// 결제 승인 성공 처리
alert("충전이 완료되었습니다!");
$.get(`/user-service/api/v1/user/point/${id}`).then((res) => {
setPoint(res.data);
window.location.href = home_redirect;
});
} else {
// 결제 승인 실패 처리
alert("충전을 실패하였습니다.");
window.location.href = home_redirect;
}
})
.catch((error) => {
alert("문제가 발생하였습니다.");
window.location.href = home_redirect;
});
@Operation(summary = "결제 준비")
@PostMapping(value = "/charge")
public ResponseEntity<?> payment(@RequestBody KakaoPayReqDto request) {
KakaoPayResDto response = kakaoPayService.requestPayment(request);
log.info("KakaoPayResDto : {}", response);
return Response.makeResponse(HttpStatus.OK, "결제 준비 완료", response);
}
@Operation(summary = "결제 승인")
@PostMapping("/approve/{userId}")
public ResponseEntity<?> approvePayment(@PathVariable long userId, @RequestBody KakaoPayApproveReqDto requestDto) {
KakaoPayApproveResDto response = kakaoPayService.approvePayment(userId, requestDto);
log.info("KakaoPayApproveResDto : {}", requestDto);
return Response.makeResponse(HttpStatus.OK, "결제 승인 완료", response);
}
HttpEntity<MultiValueMap>에 담아 카카오 페이 서버에 전달합니다. @Override
public KakaoPayResDto requestPayment(KakaoPayReqDto request) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "KakaoAK " + APP_KEY);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("cid", request.getCid());
params.add("partner_order_id", request.getPartnerOrderId());
params.add("partner_user_id", request.getPartnerUserId());
params.add("item_name", request.getItemName());
params.add("quantity", Integer.toString(request.getQuantity()));
params.add("total_amount", Integer.toString(request.getTotalAmount()));
params.add("tax_free_amount", Integer.toString(request.getTaxFreeAmount()));
params.add("approval_url", request.getApprovalUrl());
params.add("cancel_url", request.getCancelUrl());
params.add("fail_url", request.getFailUrl());
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<KakaoPayResDto> responseEntity = restTemplate.postForEntity(HOST + "/v1/payment/ready", requestEntity, KakaoPayResDto.class);
log.info("data : {}", responseEntity);
return responseEntity.getBody();
}
@Override
public KakaoPayApproveResDto approvePayment(long userId, KakaoPayApproveReqDto request) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "KakaoAK " + APP_KEY);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("pg_token", request.getPgToken());
params.add("cid", request.getCid());
params.add("tid", request.getTid());
params.add("partner_order_id", request.getPartnerOrderId());
params.add("partner_user_id", request.getPartnerUserId());
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<KakaoPayApproveResDto> responseEntity = restTemplate.postForEntity(HOST + "/v1/payment/approve",
requestEntity, KakaoPayApproveResDto.class);
KakaoPayApproveResDto response = responseEntity.getBody();
if (response == null)
throw new BaseException(ErrorMessage.FAIL_PAYMENT);
// 포인트 충전하기
AmountReqDto amountReqDto = new AmountReqDto();
amountReqDto.setUserId(userId);
amountReqDto.setAmount(response.getAmount().getTotal());
userServerClient.amount(amountReqDto);
return response;
}

Pg사 결제창이 뜨고 x 버튼을 누르면 전 페이지로 돌아가야되는데 이 부분은 어떻게 구현하셨을까요?