해당 프로젝트는 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 사용법
위의 링크에서 가입을 진행하자.
가입 후 왼쪽의 결제 연동 메뉴에서 가맹점 식별코드, REST API KEY, Secret Key를 확인할 수 있다.
테스트 연동을 추가하여 카카오페이를 추가하였다.
아래의 아임포트 공식 깃허브에서 관련 JavaScript 코드들을 사용할 수 있다.
사용하기
모달 창을 이용하여 결제를 진행 시킬 예정이다. 하여 모달 창에 아래 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 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!