지난번 포스팅에 이어 작성하겠다!
https://sweeeetgoguma.tistory.com/entry/20220529-%E3%80%8C%EA%B2%B0%EC%A0%9C-API%E3%80%8D
카카오페이 Rest API를 이용해 결제 준비에 필요한 객체를 설계하는 것까지 완료했다. 카카오 페이 프로세스에 따라 준비와 결제 및 승인을 위한 통신 객체를 생성해야 한다. 이 과정 속에서 수많은 삽질이 있었다. 사실 삽질이라기보다도 내가 정확히 개념을 이해하지 못하고 API를 적용시킨 것이다. API를 끌어다 쓰는 것은 만만한 게 아닌 것 같다.
이제 결제 승인까지의 과정을 나열해 보겠다.
이번 결제 과정은 장바구니를 통한 주문 및 결제로 진행해보겠다.
Postman tool 사용
1. 결제 준비
결제를 위한 데이터를 내 서버에 넘기며, 내 서버에서 카카오페이로 필요한 파라미터들을 담아 요청하는 일이다.
우선 로그인 먼저 해보자!
로그인을 요청하면 토큰 값을 data로 받는다.
=> 토큰 값 저장
장바구니 상품 추가
=> 현재 장바구니가 없다.
상품을 추가해보자.
=> 장바구니 목록 조회
이제 이 장바구니 상품을 가지고 결제 준비를 해보겠다
우선 내 서버로 결제 요청을 보낸다.
@Auth(role = Auth.Role.BASIC_USER)
@PostMapping("/cart")
public Message cartOrderAction(HttpServletRequest request) throws UnsupportedEncodingException {
Cookie[] cookies = request.getCookies();
Optional<Cookie> cartCookie = CookieUtil.getCartCookie(cookies);
if (cartCookie.isEmpty()) {
return new Message
.Builder(EMPTY_CART_DATA)
.httpStatus(HttpStatus.BAD_REQUEST)
.build();
}
String url = kakaoPayService.getCartKakaoPayUrl(CookieUtil.getItemNoArr(cartCookie.get()),
request,
CookieUtil.getTotalAmount(cartCookie.get()));
if (url == null) {
return getFailedPayMessage();
}
return new Message
.Builder(url)
.httpStatus(HttpStatus.OK)
.message(PAY_URI_MSG)
.build();
}
public String getCartKakaoPayUrl(String[] productNoArr, HttpServletRequest request, int totalAmount) {
/* 서버로 요청할 헤더*/
HttpHeaders headers = new HttpHeaders();
setHeaders(headers);
user = userService.findById((String) request.getAttribute("tokenUserId"));
itemName = productService.findByNumber(Integer.parseInt(productNoArr[0])).getProductName() + " 그 외 " + (productNoArr.length - 1) + "개";
orderId = user.getUserId() + ", " + itemName;
userId = user.getUserId();
this.totalAmount = totalAmount;
/* 서버로 요청할 body */
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
setParams(params, request);
params.add("partner_order_id", orderId);
params.add("partner_user_id", userId);
params.add("item_name", itemName);
params.add("item_code", String.join(", ", productNoArr));
params.add("quantity", String.valueOf(productNoArr.length));
params.add("total_amount", String.valueOf(totalAmount));
params.add("tax_free_amount", String.valueOf(TAX_FREE_AMOUNT));
return getPayUrl(headers, params);
}
private void setHeaders(HttpHeaders headers) {
restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
headers.add("Authorization", "KakaoAK " + ADMIN_KEY);
headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
}
private void setParams(MultiValueMap<String, String> params, HttpServletRequest request) {
params.add("cid", TEST_CID);
params.add("approval_url", getUrl(request) + APPROVAL_URI);
params.add("cancel_url", getUrl(request) + CANCEL_URI);
params.add("fail_url", getUrl(request) + FAIL_URI);
}
private String getPayUrl(HttpHeaders headers, MultiValueMap<String, String> params) {
HttpEntity<MultiValueMap<String, String>> body = new HttpEntity<>(params, headers);
try {
/* 서버 요청 후 응답 객체 받기 */
kakaoPayReadyDTO = restTemplate.postForObject(HOST + KAKAO_PAY_READY,
body, KakaoPayReadyDTO.class);
return kakaoPayReadyDTO != null ? kakaoPayReadyDTO.getNext_redirect_pc_url() : null;
} catch (RestClientException e) {
log.error(e.getMessage());
}
return null;
}
private String getUrl(HttpServletRequest request) {
return request.getRequestURL().toString().replace(request.getRequestURI(), "");
}
public class KakaoPayReadyVO {
private String tid, next_redirect_pc_url;
private Date created_at;
@ConstructorProperties({"tid","next_redirect_pc_url","created_at"})
public KakaoPayReadyVO(String tid, String next_redirect_pc_url, Date created_at) {
this.tid = tid;
this.next_redirect_pc_url = next_redirect_pc_url;
this.created_at = created_at;
}
=> 요청을 하면 카카오 페이는 이 객체를 통해 파라미터를 json 형태에서 객체로 변환해 응답해준다. 저기 있는 next_redirect_url이 결제 요청 url!
2. 결제 승인
이제 저 URL로 브라우저에서 요청해보자!
=> 브라우저에서 요청을 하면 데모 QR 코드가 뜬다. 이것을 휴대폰으로 결제해보자
=> 휴대폰으로 테스트 결제를 마치고 나면 결제 성공 URL로 리다이렉트 된다.
하지만 나는 RESTAPI 만을 설계하고 있기 때문에 따로 보여줄 Front가 없다. 그래서 Postman에서 저 URL로 요청을 해보겠다.
=> 이렇게 결제 승인 및 결제 정보를 종합적으로 얻을 수 있다.
이제 이 것을 객체를 통해 DB에 저장을 할 수 있을 것 같다.
리팩토링!
반응형
'📕 Spring Framework > Spring Project' 카테고리의 다른 글
2022.06.07 「프로젝트 중간 점검」 (0) | 2022.06.07 |
---|---|
2022.06.02 「DB 동시성 문제」 (0) | 2022.06.02 |
2022.05.29 「결제 API」 (0) | 2022.05.29 |
2022.05.28 「쿠키 수정」 (0) | 2022.05.28 |
2022.05.26 「트래픽이 몰렸을 경우」 (0) | 2022.05.26 |