
해당 프로젝트는 2023/01/25 ~ 2023/03/12 내에 진행되는
아카데미 내 수강생들끼리 팀을 나누어 진행한 모의 프로젝트입니다.
팀원은 5명이었으며, 프로젝트 리더를 맡았습니다.
이전 글 목록
1) 주어진 RFP를 바탕으로 주제 선정 - Spring Project(OTT 서비스)
2) ERD 설계 - Spring Project(OTT 서비스)
3) 회원 가입 기능 구현 - Spring Project (OTT 서비스)
4) 로그인, 로그아웃 기능 구현 - Spring Project (OTT 서비스)
5) 상세 페이지 및 회원 정보 수정 - Spring Project (OTT 서비스)
6) CRUD를 한번에 → 게시판 만들기(QNA게시판) - Spring Project(Mybatis) (OTT 서비스)
7) 게시판 페이징 처리 - Spring Project (OTT 서비스)
8) 카카오 지도 API 사용하기 - Spring Project (OTT 서비스)
9) (네아로) 네이버 로그인 API 활용 사이트 로그인 및 회원가입 - SPRING Project(OTT 서비스)
10) 카카오 로그인 API 사용하기(내 사이트 로그인 및 회원가입) - Spring Project(OTT Service)
해당 프로젝트의 정책은 유저가 결제를 완료했을 때, 전체 영상에 대한 시청이 가능하다.
그렇기 때문에 결제처리가 반드시 필요했다.
아임포트(포트원) API 사용법
포트원, 온라인 비즈니스를 위한 통합 결제 솔루션
코드 한 줄로 세상 모든 방식의 결제를 경험해보세요
portone.io
위의 링크에서 가입을 진행하자.
가입 후 왼쪽의 결제 연동 메뉴에서 가맹점 식별코드, REST API KEY, Secret Key를 확인할 수 있다.
테스트 연동을 추가하여 카카오페이를 추가하였다.
아래의 아임포트 공식 깃허브에서 관련 JavaScript 코드들을 사용할 수 있다.
GitHub - iamport/iamport-manual: 아임포트(iamport) 결제연동을 위한 매뉴얼입니다.
아임포트(iamport) 결제연동을 위한 매뉴얼입니다. Contribute to iamport/iamport-manual development by creating an account on GitHub.
github.com
사용하기
모달 창을 이용하여 결제를 진행 시킬 예정이다. 하여 모달 창에 아래 script 코드를 추가 해 주었다.
<script type="text/javascript" src="https://cdn.iamport.kr/js/iamport.payment-1.1.5.js"></script>
그리고 모달창을 만들어 주었다.
pay_modal.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.iamport.kr/js/iamport.payment-1.1.5.js"></script>
<link rel="stylesheet" href="/resources/css/common/pay_modal.css">
</head>
<body>
<!-- ********************************모달 시작****************************** -->
<input class="inputMonthH" type="hidden">
<input class="sessionuserID" type="hidden" value="${sessionScope.user_id}">
<input class="amountValue" type="text">
<div class="popup"> <!-- 팝업처럼 하기 위한 배경 -->
<div class="pwrap"> <!-- 실제 팝업창 -->
<a class="closebtn">X</a> <!-- 비밀번호 변경창 닫기 버튼 -->
<div>
<h1>결제하기</h1><span>(1개월 결제 금액은 15000원 입니다.)</span>
</div>
<table>
<tr>
<td><a href="#" onclick="kakaopay()"><img src="/resources/img/user/iconKakao.svg"></a></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<div>
<h3 class="amount">결제 금액 : 0원</h3>
<p>개월 수를 선택 해 주세요</p>
<select onchange="monthSelect(this)">
<option value="0">선택하기</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
</div>
</div>
</div>
<!-- ****************************모달 끝 *******************************-->
<script src="/resources/js/common/pay_modal.js"></script>
<script src="/resources/js/api/kakao_payment.js"></script>
</body>
</html>
사용자가 선택 한 개월수 만큼의 결제를 진행 시킬 것이며, 결제 개월 수를 선택하지 않고 결제를 진행할 경우 이벤트를 통하여 결제를 막을 것이다.
pay_modal.js
/* 결제 모달 창 - 02.14 */
const closebtn = document.querySelector('.closebtn');
const popup = document.querySelector('.popup');
const inputH = document.querySelector('.inputMonthH') //결제 개월 수 입력받는 inputhidden
const amount = document.querySelector('.amount');
const amountV = document.querySelector('.amountValue');
function modal(){ //결제창 on-off
popup.style.display = 'block';
}
closebtn.addEventListener('click', function(){
popup.style.display = 'none';
});
//결제 개월 수 view에 hidden으로 출력
function monthSelect(e){
const paynum = (15000*e.value);
inputH.value = e.value;
amount.textContent = "결제 금액 : " + paynum + "원";
amountV.value = paynum;
}
kakao_payment.js
function kakaopay(){
if(inputH.value == null || inputH.value == 'none' || inputH.value == ""){
alert("결제 개월 수를 선택 해 주세요");
return;
}
console.log($('#userid'));
var IMP = window.IMP;
IMP.init('가맹점 식별 코드');
IMP.request_pay({
pg : 'kakaopay.CID',
pay_method : 'card',
merchant_uid : 'merchant_' + new Date().getTime(), //주문번호
name : 'GOOTTFLEX', //상품명
amount : $('.amountValue').val(), //가격
//customer_uid : buyer_name + new Date().getTime(), //해당 파라미터값이 있어야 빌링 키 발급 시도
buyer_email : $('.sessionuserID').val(), //구매자 이메일
buyer_name : 'buyer_name', //구매자 이름
buyer_tel : 'hp', //전화번호
buyer_addr : 'addr', //주소
buyer_postcode : '123-456' //우편번호
},function(data){
if(data.success){
var msg = "결제 완료";
msg += '고유ID : ' + data.imp_uid; //아임포트 uid는 실제 결제 시 결제 고유번호를 서버와 비교해서 결제처리하는데 필요없긴함.
msg += '// 상점 거래ID : ' + data.merchant_uid;
msg += '// 결제 금액 : ' + data.paid_amount;
msg += '// 카드 승인번호 : ' + data.apply_num;
$.ajax({
type : 'post',
url : '/paySuccess',
data : {"ID" : data.buyer_email, "amount" : data.paid_amount},
});
}else{
var msg = "결제 실패"
msg += "에러 내용" + rsp.error_msg;
}
alert(msg);
document.location.href="/video/list";
});
}
모달 창에서 받은 개월 수가 존재하지 않을 경우에 대한 이벤트를 생성했다.
결제가 완료될 때, msg 변수를 생성하여 유저에게 결제 완료에 대한 결제 내용을 출력 해 주었다.
또한 ajax를 이용하여 결제자의 ID와 결제 기간을 담아 Controller에 전송했다. 결제 처리를 위해서이다.
pg : 'kakaopay.CID',
위의 CID는 테스트 카카오페이 생성 시 생성 된 가맹점코드이며 나의 경우, CID를 뒤에 입력해 주지 않았을 경우 결제가 진행이 되지 않았다. 가맹점 식별 코드에는 내 식별 코드를 입력하자.
PayMentController
package com.test.test1.common;
(...생략...)
@Controller
public class PayMentController {
@Autowired
UserService userService;
private IamportClient api;
public PayMentController(){
//토큰 발급
this.api = new IamportClient("REST API Key","REST API Secret");
}
@ResponseBody
@RequestMapping(value="/verifyiamport/{imp_uid}", method=RequestMethod.POST)
public IamportResponse<Payment> paymentByImpUid(Model model, Locale locale, HttpSession session
, @PathVariable(value= "imp_uid") String imp_uid) throws IamportResponseException, IOException{
return api.paymentByImpUid(imp_uid);
}
//결제 완료 시 DB에 결제 완료 처리 - 02.15
//관리자 페이지 코드 추가 - 02.19
@RequestMapping(value="/paySuccess", method=RequestMethod.POST)
public void paySuccess(String amount,String ID) {
int tmp = Integer.parseInt(amount);
int months = tmp/15000; //개월 수로 치환 -> 기간 갱신을 위함
Map<String, Object> map = new HashMap<>();
map.put("ID", ID);
map.put("months", months);
if(userService.paidCheck(ID) == "Y") {
userService.rePaid(map);
}
else {
userService.paid(map); //첫 결제시 : map에 ID, 개월 수 넣고 DB갱신
}
userService.paidUpdate(months);//관리자페이지 일 결제 조회를 위해 추가 - 02.19
}
}
API Key와 Secret Key를 입력한 후 결제 토큰을 생성자를 통해 생성한다.
ajax를 이용해 받아온 ID와 amount를 가지고 USER 테이블에 결제 처리를 진행 할 것이다.
결제 유효기간이 남아있는 사용자와, 그렇지 않은 사용자로 나누어 update처리 해 주었다.
관리자 페이지의 경우 차후 포스팅 될 예정이다.
Service / Impl / Dao
//Service
void paid(Map<String, Object> map);
void rePaid(Map<String, Object> map);
String paidCheck(String ID);
//ServiceImpl
@Override
public void paid(Map<String, Object> map) {
userDao.paid(map);
}
@Override
public void rePaid(Map<String, Object> map) {
userDao.rePaid(map);
}
@Override
public String paidCheck(String ID) {
return userDao.paidCheck(ID);
}
//Dao
public void paid(Map<String, Object> map) {
sqlSessionTemplate.update("user.paid", map);
}
public void rePaid(Map<String, Object> map) {
sqlSessionTemplate.update("user.rePaid", map);
}
public String paidCheck(String ID) {
return sqlSessionTemplate.selectOne("user.paidCheck", ID);
}
user_SQL.xml
<update id="paid">
update USER
set SUBSCRIBE_YN="Y", PAID_M=PAID_M+${months}, EXPIRATION_DATE=(date_add(NOW(),interval ${months} month))
where USER_ID = (select U.USER_ID from (select USER_ID from USER where ID="${ID}") AS U);
</update>
<update id="rePaid">
update USER
set PAID_M=PAID_M+${months}, EXPIRATION_DATE=(date_add(NOW(),interval ${months} month))
where USER_ID = (select U.USER_ID from (select USER_ID from USER where ID="${ID}") AS U);
</update>
<select id="paidCheck" resultType="String">
select SUBSCRIBE_YN
from USER
where ID="${ID}"
</select>
결제 여부를 파악하여 결제 기간이 남았을 경우 기간만 업데이트 해 주고, 그렇지 않을 경우 결제 여부도 Y로 바꿔주었다.
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!