[Spring Boot JPA] 카카오페이 단건결제 구현하기
이를 구현하기 위해서는 먼저 카카오 디벨로퍼스에서 내 애플리케이션 만들기를 해야 합니다.
단건 결제의 구현 순서는 결제 준비하기 -> 결제 승인하기 입니다.
0. 기본값 설정하기
그 전에 필요한 APP_ADMIN_KEY와 CID 값을 .yml에 넣어 숨깁니다.
kakaopay:
admin-key: XXXXX
cid: TC0ONETIME
admin-key값은 카카오 디벨로퍼스에서 내 애플리케이션 만들기를 통해 얻을 수 있습니다.
그 다음에 위의 값들을 사용하기 위해 Component로 설정합니다.
@Component
public class KakaoPayProperties {
public static String adminKey;
public static String cid;
public static String readyUrl;
public static String approveUrl;
@Value("${kakaopay.admin-key}")
public void setAdminKey(String adminKey) {
KakaoPayProperties.adminKey = adminKey;
}
@Value("${kakaopay.cid}")
public void setCid(String cid) {
KakaoPayProperties.cid = cid;
}
@Value("${kakaopay.ready-url}")
public void setReadyUrl(String readyUrl) {
KakaoPayProperties.readyUrl = readyUrl;
}
@Value("${kakaopay.approve-url}")
public void setApproveUrl(String approveUrl) {
KakaoPayProperties.approveUrl = approveUrl;
}
}
1. 결제 준비하기
PayService
public ResponseDto getKakaoPayReady(RequestDto request) {
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(this.getReadyParameters(request), this.getHeaders());
try {
RestTemplate restTemplate = new RestTemplate();
ResponseDto response = restTemplate.postForObject(
KakaoPayProperties.readyUrl,
requestEntity,
ResponseDto.class
);
return response;
} catch (HttpClientErrorException e) {
throw new HttpClientErrorException(e.getStatusCode(), e.getMessage());
}
}
private HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
String auth = "KakaoAK " + KakaoPayProperties.adminKey;
httpHeaders.set("Authorization", auth);
httpHeaders.set("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
return httpHeaders;
}
private MultiValueMap<String, String> getReadyParameters(RequestDto request) {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("cid", KakaoPayProperties.cid);
parameters.add("partner_order_id", request.partnerOrderId());
parameters.add("partner_user_id", request.partnerUserId());
parameters.add("item_name", request.getName());
parameters.add("quantity", request.getQuantity);
parameters.add("total_amount", String.valueOf(request.getPrice()));
parameters.add("vat_amount", request.vatAmount());
parameters.add("tax_free_amount", request.taxFreeAmount());
parameters.add("approval_url", request.approvalUrl());
parameters.add("cancel_url", request.cancelUrl());
parameters.add("fail_url", request.failUrl());
return parameters;
}
1. getHeader 함수를 통해 통신에 필요한 헤더를 설정합니다.
2. getReadyParameters 함수를 통해 통신에 필요한 request 값들을 설정해줍니다.
3. 위의 값을 이용하여 통신합니다.
해당 과정에서 발생할 수 있는 에러가 있기에 HttpClientException을 통해 에러를 던집니다.
+) 위에서 approve_url에 대해 [GET API]를 만들면 쉽게 pg_token을 받을 수 있습니다.
해당 과정을 통해 다양한 url을 받을 수 있으며 해당 url로 접근하게 되면 밑의 사진과 같이 연결됩니다.
여기서 tid값을 저장해주세요!
하지만 준비 단계일 뿐이기에 결제 버튼을 눌러도 결제가 이뤄지지 않습니다.
2. 결제 승인하기
request 값으로는 앞의 준비과정에서 얻었던 tid값, pg_token이란 값을 추가적으로 주어야합니다.
tid값은 준비과정에서 resposne로 받습니다.
pg_token은 준비 과정 후에 approve_url을 통해서 얻을 수 있습니다.
준비 과정에서 request로 주는 approve_url을 /pay/approve로 설정하여 밑의 경로로 이어지도록 설정하였습니다.
PayController
@GetMapping("/pay/approve")
public ResponseEntity<ApiResponse> getPgToken(@RequestParam("pg_token") String pgToken) {
return ResponseEntity.ok(ApiResponse.success(SUCCESS_GET_PGTOKEN.getMessage(), pgToken));
}
이를 통해 pg_token을 얻을 수 있습니다.
이제 얻은 tid. pg_token값과 기존 갖고 있던 값들을 통해 통신을 시작합니다.
PayService
private MultiValueMap<String, String> getApproveParameters(RequestDto request) {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("cid", KakaoPayProperties.cid);
parameters.add("partner_order_id", request.partnerOrderId());
parameters.add("partner_user_id", request.partnerUserId());
parameters.add("tid", request.tid());
parameters.add("pg_token", request.pgToken());
return parameters;
}
public CakeApproveResponseDto getKakaoPayApprove(RequestDto request) {
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(this.getApproveParameters(request), this.getHeaders());
RestTemplate restTemplate = new RestTemplate();
try {
ResponseDto response = restTemplate.postForObject(
KakaoPayProperties.approveUrl,
requestEntity,
ResponseDto.class
);
return response;
} catch (HttpClientErrorException e) {
throw new HttpClientErrorException(e.getStatusCode(), e.getMessage());
}
}
아까 준비 과정과 비슷하게 해당 파라미터를 설정하는 함수와 통신을 담당하는 함수를 설정하였습니다.
이 과정을 최종적으로 마치게 되면
구매한 계정으로 결제가 완료되었다는 카톡을 받을 수 있습니다.