2022. 1. 9. 20:49ㆍ스프링부트
온라인 비즈니스의 모든 결제를 한곳에서, 아임포트
결제의 시작부터 비즈니스의 성장까지 아임포트와 함께하세요
www.iamport.kr
아임포트에 회원가입을 하고 관리자 콘솔로 이동합니다


원하는 PG사를 선택하고 테스트모드를 ON해준 뒤 저장합니다
내 정보에서 가맹점식별코드, REST API키, RESET API secret을 확인 할 수 있습니다
결제가 필요한 order폴더의 order.jsp 아래에 아임포트 라이브러리를 추가합니다
<!-- iamport.payment.js --> <script type="text/javascript" src="https://cdn.iamport.kr/js/iamport.payment-1.1.8.js"></script>

order.js에서 기존의 payment 함수를 수정합니다
orderNum은 주문페이지로 이동할때 자바단에서 생성하였었는데 결제시 프론트에서 생성하도록 수정하였습니다
자바단에서 orderNum생성로직을 삭제해줍니다
payMethod가 신용카드일땐 paymentCard()를 호출하게 수정합니다

// 주문번호 만들기 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; }
// 카드 결제 function paymentCard(data) { // 모바일로 결제시 이동페이지 const pathName = location.pathname; const href = location.href; const m_redirect = href.replaceAll(pathName, ""); IMP.init("imp99151903"); IMP.request_pay({ // param pg: "html5_inicis", pay_method: data.payMethod, merchant_uid: data.orderNum, name: data.name, amount: data.amount, buyer_email: "", buyer_name: "", buyer_tel: data.phone, buyer_addr: data.deleveryAddress2 + " " + data.deleveryAddress3, buyer_postcode: data.deleveryAddress1, m_redirect_url: m_redirect, }, function (rsp) { // callback if (rsp.success) { // 결제 성공 시 로직, data.impUid = rsp.imp_uid; data.merchant_uid = rsp.merchant_uid; paymentComplete(data); } else { // 결제 실패 시 로직, } }); }
IMP.init에는 가맹점 식별코드를 적어줍니다

여기까지만 해도 결제는 되지만 html의 음식 가격을 조작했을 경우에도 그 가격 그대로 결제가 되버립니다
그래서 서버와 가격이 맞지 않을때 결제 성공시 응답받은 imp_uid로 결제를 취소해야합니다

주석 되있던 계산완료 함수를 주석해제 합니다
OrderInfo클래스에 아임포트 결제번호 주석을 해제합니다
private String impUid = ""; // 아임포트 결제번호 추가
OrderController에 결제 후 메서드를 추가합니다
// 카드 결제 성공 후 @PostMapping("/order/payment/complete") public ResponseEntity<String> paymentComplete(HttpSession session, OrderInfo orderInfo, long totalPrice) throws IOException { // 1. 아임포트 API 키와 SECRET키로 토큰을 생성 // 2. 토큰으로 결제 완료된 주문정보를 가져옴 // 3. 로그인하지 않았는데 사용포인트가 0 이상일경우 결제 취소 // 4. 로그인 사용자가 현재포인트보다 사용포인트가 많을 경우 결제 취소 // 5. DB에서 실제 계산되어야 할 가격가져오기 // 6. 결제 완료된 금액과 실제 계산되어야 할 금액이 다를경우 결제 취소 // 7. 결제에러시 결제 취소 return new ResponseEntity<>(HttpStatus.OK); }
1. 아임포트 API 키와 SECRET키로 토큰을 생성
2. 토큰으로 결제 완료된 주문정보를 가져옴
3. 로그인하지 않았는데 사용포인트가 0 이상일경우 결제 취소
4. 로그인 사용자가 현재포인트보다 사용포인트가 많을 경우 결제 취소
5. DB에서 실제 계산되어야 할 가격가져오기
6. 결제 완료된 금액과 실제 계산되어야 할 금액이 다를경우 결제 취소
7. 결제에러시 결제 취소
service패키지에 결제를 담당할 PaymentService를 생성합니다
application.properties에 REST API키와 SECRET 키를 추가합니다
imp_key=REST API키 imp_secret=SECRET 키
PaymentService
public interface PaymentService { String getToken() throws IOException; int paymentInfo(String imp_uid, String access_token); public void payMentCancle(String access_token, String imp_uid, String amount, String reason); }
PaymentServiceImp
@Service public class PaymentServiceImp implements PaymentService { @Value("${imp_key}") private String impKey; @Value("${imp_secret}") private String impSecret; public String getToken() throws IOException { HttpsURLConnection conn = null; URL url = new URL("https://api.iamport.kr/users/getToken"); conn = (HttpsURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-type", "application/json"); conn.setRequestProperty("Accept", "application/json"); conn.setDoOutput(true); JsonObject json = new JsonObject(); json.addProperty("imp_key", impKey); json.addProperty("imp_secret", impSecret); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); bw.write(json.toString()); bw.flush(); bw.close(); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); Gson gson = new Gson(); String response = gson.fromJson(br.readLine(), Map.class).get("response").toString(); System.out.println(response); String token = gson.fromJson(response, Map.class).get("access_token").toString(); br.close(); conn.disconnect(); return token; } public int paymentInfo(String imp_uid, String access_token) { return 0; } public void payMentCancle(String access_token, String imp_uid, String amount, String reason) { } }
컨트롤러에서 토큰이 생성되는지 확인해봅니다
@Autowired private PaymentService paymentService;
String token = paymentService.getToken(); System.out.println("토큰 : " + token);

이제 토큰으로 결제 정보를 가져오는 코드를 추가합니다
public int paymentInfo(String imp_uid, String access_token) throws IOException { HttpsURLConnection conn = null; URL url = new URL("https://api.iamport.kr/payments/" + imp_uid); conn = (HttpsURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Authorization", access_token); conn.setDoOutput(true); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); Gson gson = new Gson(); Response response = gson.fromJson(br.readLine(), Response.class); br.close(); conn.disconnect(); return response.getResponse().getAmount(); }
토큰으로 요청한 결제정보는 {"code":0,"message":null,"response":{"amount":6000, .... } 형태의 중첩 JSON형태입니다
이 JSON에서 필요한 값은 취소할 금액인 amount만 가져오면 됩니다
JSON을 파싱할 클래스 Response와 JsonInfo를 만드는데 PaymentServiceImp클래스 안에서만 사용하기 때문에
PaymentServiceImp 내부에 클래스를 생성합니다

각각의 조건에 맞게 코드를 추가합니다
// 카드 결제 성공 후 @PostMapping("/order/payment/complete") public ResponseEntity<String> paymentComplete(HttpSession session, OrderInfo orderInfo, long totalPrice, @AuthenticationPrincipal LoginService user) throws IOException { String token = paymentService.getToken(); System.out.println("토큰 : " + token); // 결제 완료된 금액 int amount = paymentService.paymentInfo(orderInfo.getImpUid(), token); try { // 주문 시 사용한 포인트 int usedPoint = orderInfo.getUsedPoint(); if (user != null) { int point = user.getUser().getPoint(); // 사용된 포인트가 유저의 포인트보다 많을 때 if (point < usedPoint) { paymentService.payMentCancle(token, orderInfo.getImpUid(), amount, "유저 포인트 오류"); return new ResponseEntity<String>("유저 포인트 오류", HttpStatus.BAD_REQUEST); } } else { // 로그인 하지않았는데 포인트사용 되었을 때 if (usedPoint != 0) { paymentService.payMentCancle(token, orderInfo.getImpUid(), amount, "비회원 포인트사용 오류"); return new ResponseEntity<String>("비회원 포인트 사용 오류", HttpStatus.BAD_REQUEST); } } CartList cartList = (CartList) session.getAttribute("cartList"); // 실제 계산 금액 가져오기 long orderPriceCheck = orderService.orderPriceCheck(cartList) - usedPoint; // 계산 된 금액과 실제 금액이 다를 때 if (orderPriceCheck != amount) { paymentService.payMentCancle(token, orderInfo.getImpUid(), amount, "결제 금액 오류"); return new ResponseEntity<String>("결제 금액 오류, 결제 취소", HttpStatus.BAD_REQUEST); } orderService.order(cartList, orderInfo, user); session.removeAttribute("cartList"); return new ResponseEntity<>("주문이 완료되었습니다", HttpStatus.OK); } catch (Exception e) { paymentService.payMentCancle(token, orderInfo.getImpUid(), amount, "결제 에러"); return new ResponseEntity<String>("결제 에러", HttpStatus.BAD_REQUEST); } }
결제 취소 코드를 추가합니다
public void payMentCancle(String access_token, String imp_uid, int amount, String reason) throws IOException { System.out.println("결제 취소"); System.out.println(access_token); System.out.println(imp_uid); HttpsURLConnection conn = null; URL url = new URL("https://api.iamport.kr/payments/cancel"); conn = (HttpsURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-type", "application/json"); conn.setRequestProperty("Accept", "application/json"); conn.setRequestProperty("Authorization", access_token); conn.setDoOutput(true); JsonObject json = new JsonObject(); json.addProperty("reason", reason); json.addProperty("imp_uid", imp_uid); json.addProperty("amount", amount); json.addProperty("checksum", amount); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); bw.write(json.toString()); bw.flush(); bw.close(); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); br.close(); conn.disconnect(); }
정상 결제일때

금액을 조작했을때

관리자 페이지에서도 관리자가 주문거부를 할수있게 OderMapper의 order쿼리에 IMP_UID를 추가합니다

'스프링부트' 카테고리의 다른 글
STOMP로 채팅 만들기 (0) | 2022.02.25 |
---|---|
스프링부트+jsp로 배달사이트 만들기-41 관리자가 주문취소시 환불하기 추가 (1) | 2022.01.20 |
sts4 깃 임포트 후 db 연결 에러 (0) | 2022.01.07 |
스프링부트+jsp로 배달사이트 만들기-39 비밀번호 찾기, 비밀번호 변경 (0) | 2022.01.04 |
스프링부트+jsp로 배달사이트 만들기-38 이메일보내기(아이디 찾기,비번찾기) (0) | 2021.12.29 |