[Java Spring] 결제 시스템 (Iamport api) 활용기 1 - 자격증 공부를 위한 사이트 자바스 개발 회고록
자바스 개발 구축 환경
해당 프로젝트는 Spring Legacy Project로 sts-3.9 버전을 사용하였습니다.
주제
- 자격증을 공부하기 위해 정보를 얻고 싶은 취준생들을 위한 사이트이다.
- 자신이 원하는 자격증을 검색하여 교재, 동영상, 관심 있는 자격증을 등록할 수 있고, 홈페이지에 시험 d-day를 확인하도록 도와준다.
- 회원들끼리 정보를 공유할 수 있으며, 가까운 지역의 스터디카페를 추천해 준다.
나의 개발 파트
- 로그인(auth)
- 회원, 관리자 (등급 분배)
- 관리자
- 관리자 번호로 회원 등급 조절
- 회원 결제정보 확인, 취소
- 스터디카페 예약 시 결제
- 상품결제
- 결제수단 선택
- 결제 후 날짜변경
- 결제 취소
결제 api를 사용할 때 내가 고민을 많이 했던 부분과 참조한 부분을 정리하여 기록을 남기면 좋을 것 같다는 생각을 했다.
Iamport 회원가입부터 결제테스트, 상품(스터디카페) oracle db 연동, 상품 결제, oracle db 결제내역저장, 결제 취소 순으로 포스팅할 계획입니다.
아이엠포트 회원가입
온라인 비즈니스의 모든 결제를 한곳에서, 아임포트
결제의 시작부터 비즈니스의 성장까지 아임포트와 함께하세요
www.iamport.kr
아이엠 포트에 로그인 후 카카오페이를 활용하여 구현을 진행하기에 결제대행사를 카카오페이로 추가합니다.
그 후 구 관리자 콘솔로 이동합니다.
시스템설정 -> 내 정보에서 가맹점 식별코드, REST API키, RESET API secret을 확인할 수 있습니다.
그럼 아이엠포트 결제를 위한 준비 단계를 밟았습니다. 이제 String 개발 툴로 돌아가 api를 추가해 봅시다!+
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
해당 정보는 github에 올리면 안 되는 개인의 정보로 ignore 파일에 따로 관리하도록 합니다.
IamportClient를 활용해 iamport의 함수들로 (결제내역, 정보, 취소) 활용할 수 있었습니다.
function requestPay() {
// IMP.request_pay(param, callback) 결제창 호출
var uid = '';
IMP.init('가맹점 번호 자리입니다');
IMP.request_pay({ // param
pg: 'kakaopay',
pay_method: "card",
merchant_uid: createOrderNum(), //가맹점 주문번호 (아임포트를 사용하는 가맹점에서 중복되지 않은 임의의 문자열을 입력)
name: scName.textContent, //결제창에 노출될 상품명
amount: cdPay.textContent, //금액
buyer_email : email.textContent,
buyer_name : userName.textContent,
buyer_tel : phone.textContent.trim(),
}, function (rsp) { // callback
if (rsp.success) { // 결제 성공 시: 결제 승인 또는 가상계좌 발급에 성공한 경우
uid = rsp.imp_uid;
// 결제검증
$.ajax({
url: '/order/verify_iamport/' + rsp.imp_uid,
type: 'post'
}).done(function(data) {
// 결제를 요청했던 금액과 실제 결제된 금액이 같으면 해당 주문건의 결제가 정상적으로 완료된 것으로 간주한다.
if (cdPay.textContent == data.response.amount) {
// jQuery로 HTTP 요청
// 주문정보 생성 및 테이블에 저장
// 데이터를 json으로 보내기 위해 바꿔준다.
data = JSON.stringify({
"orderNum" : rsp.merchant_uid,
"productNum" : detailNum.textContent, //상품번호
"num" : userNum.value, // 회원번호
"productName" : rsp.name,
"orderDate" : new Date().getTime(),
"totalPrice" : rsp.paid_amount,
"imp_uid" : rsp.imp_uid,
"reserNum" : reserNum.textContent // 예약정보를 담고있는번호
});
jQuery.ajax({
url: "/order/complete",
type: "POST",
dataType: 'json',
contentType: 'application/json',
data : data
})
.done(function(res) {
if (res > 0) {
swal('주문정보 저장 성공')
createPayInfo(uid);
}
else {
swal('주문정보 저장 실패');
}
})
}
else {
alert('결제 실패');
}
})
} else {
swal("결제에 실패하였습니다.","에러 내용: " + rsp.error_msg,"error");
}
});
}
저와 같이 넘기는 정보가 결제 정보뿐만 아니라 해당 카페의 좌석, 날짜, 시간 등 넘겨줘야 하는 데이터가 추가적으로 있다면 데이터를 json으로 보내기 위해 변경하여 같이 넘겨주는 형식을 활용하시면 될 것 같습니다.
아이엠포트 api 를 사용해서 결제라는 시스템을 시도했을 때 바로 성공해서 좋았지만, 예외사항에 대해 한 번 더 고민해볼 필요가 있다고 생각했습니다.
현재 if문으로 한번 더 감싼이유는 html에서 금액을 조정했을 경우에 결제가 진행되면 안 되기 때문입니다.
그래서 서버에서 결제로 넘어오는 금액과 가격이 맞지 않는다면 결제를 취소하고, 맞다면 결제를 진행하는 방식을 사용했습니다.
백엔드에서 주문정보와 결제 정보를 저장할 때 결제 완료된 금액과 실제 계산되어야 할 금액이 다를 경우를 String 에서도 관리함으로써 이중으로 결제 금액을 관리하였습니다.
// 주문번호 만들기
function createOrderNum(){
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
let orderNum = year + month + day;
for(let i=0;i<10;i++) {
orderNum += Math.floor(Math.random() * 8);
}
return orderNum;
}
@ResponseBody
@RequestMapping(value = "/verify_iamport/{imp_uid}", method = RequestMethod.POST)
public IamportResponse<Payment> verifyIamportPOST(@PathVariable(value = "imp_uid") String imp_uid) throws IamportResponseException, IOException {
return client.paymentByImpUid(imp_uid);
}
지금까지 결제버튼까지의 코드를 이해하시고 활용하신다면 버튼 클릭 시 결제 큐알코드까지 확인하실 수 있으실 것 같습니다 !
다음 포스팅에는 테스트 결제 후 화면이동, 결제정보 저장, 결제 리스트 확인, 결제 취소(환불)에 대해 포스팅하겠습니다.