Spring

[Spring] Day16 결제 API (Code)

jnk1m 2022. 4. 7. 16:07

1. 

package com.board.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.board.service.KakaoPayService;

@Controller
@RequestMapping("/kakao/*")
public class KakaoController {
	@Autowired
	private KakaoPayService service;
	
	

	@GetMapping("kakaoPay")
	public void kakaoPayGet() {
		System.out.println("kakaoPay 요청");
	}
	@PostMapping("kakaoPay")
	public String kakaoPay() {
		System.out.println("kakao pay post 요청 ");
		//자바를 통해서 kakao api에서 제공한 주소로 http 요청하자 
		String responseURL = service.kakaoPayReady();
		
		//서비스 처리 결과 중 카카오 페이지 준비 결과에 따른 이동할 페이지 주소로 redirect 해주기
		return "redirect:" + responseURL; //주소 연결 	
	}
	
	
	
	//준비 요청 성공 시 실행될 요청 메서드 
	//파라미터로 넘어오는 pg_token을 받고  
	@GetMapping("kakaoPaySuccess")
	public void kakaoPaySuccess(@RequestParam("pg_token") String pg_token, Model model) {
		System.out.println("kakaoPaySuccess");
		System.out.println("pg_token" + pg_token);
		
		//결제 승인 요청 (pg_token 전달하면서)
		model.addAttribute("payInfo", service.kakaoPayApprove(pg_token)); 
		
	}
}

 

 

2. /kakaoPay

package com.board.service;

import com.board.domain.KakaoPayApprovalVO;

public interface KakaoPayService {

	//결제 준비 처리
	public String kakaoPayReady();
	
	//결제 승인 요청 처리
	public KakaoPayApprovalVO kakaoPayApprove(String pg_token);
	
}

-

package com.board.service;

import java.net.URI;
import java.net.URISyntaxException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.board.domain.KakaoPayApprovalVO;
import com.board.domain.KakaoPayReadyVO;

@Service
public class KakaoPayServiceImpl implements KakaoPayService {
	
	//HTTP RESP 요청해주는 기능을 가진 클래스: 빈으로 등록해서 얻어다 쓰자. 
	@Autowired
	private RestTemplate restTemplate;
	
	private KakaoPayReadyVO readyVO ;

	@Override
	public String kakaoPayReady() {
		System.out.println("!!ready!!");
		//카카오 결제 준비 처리 요청
		
		//1. 요청 시 필요한 헤더 정보
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "KakaoAK "+ "bc8dcbd5277002466c5eca4bc49f2f21");
		//카카오 서버에게 난 JSON 형태로 응답 받고 싶어~라는 정보를 주는 것. 
		headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
		headers.add("Content-type", MediaType.APPLICATION_FORM_URLENCODED_VALUE+";charset=utf-8"); //application/x-www-form-urlencoded;charset=utf-8와 동일한 것
				
		
		//2. 카카오 서버로 요청할 때 보내줄 데이터 BODY 준비
		MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
		params.add("cid", "TC0ONETIME"); //가맹점 코드 (테스트는 TC0ONETIME 으로 사용)
		params.add("partner_order_id", "202204070001"); //우리 사이트에서 생성한 주문 고유 번호 
		params.add("partner_user_id","pikachu"); //결제하는 사용자 id
		params.add("item_name", "chocochip cookies"); //상품명
		params.add("item_code", "P00012"); //상품 코드 
		params.add("quantity","1"); //상품 수량 
		params.add("total_amount","1000"); //상품 총액
		params.add("tax_free_amount","0"); //비과세 상품 금액
		params.add("approval_url", "http://localhost:8080/kakao/kakaoPaySuccess"); //결제 성공시 redirect할 주소
		params.add("cancel_url", "http://localhost:8080/kakao/kakaoPayCancel"); //결제 취소시 redirect할 주소
		params.add("fail_url", "http://localhost:8080/kakao/kakaoPayFail"); //결제 실패시 redirect할 주소 
		
		//헤더와 바디 합치기
		HttpEntity<MultiValueMap<String, String>> body 
		= new HttpEntity<MultiValueMap<String,String>>(params, headers);
		
		//3. 요청
		//매개변수: 1. 요청 주소 2. 요청 headers + body 3. 응답 받을 타입
		try {
			readyVO = 
			restTemplate.postForObject(new URI("https://kapi.kakao.com/v1/payment/ready"),body, KakaoPayReadyVO.class);
			System.out.println("!! KakaoPayReadyVO 출력 확인: "+ readyVO);
			//응답으로 받은 redirect: 이동할 주소 리턴 
			return readyVO.getNext_redirect_pc_url();
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
		//위에서 정상적으로 처리 안되면 이동할 주소 예시로 넣기
		return "/mypage/cart"; //지금은 임의로 작성 
	}

	//결제 승인 처리 메서드 
	@Override
	public KakaoPayApprovalVO kakaoPayApprove(String pg_token) {
		
		//헤더 정보
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "KakaoAK "+ "bc8dcbd5277002466c5eca4bc49f2f21");
		headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
		headers.add("Content-type", MediaType.APPLICATION_FORM_URLENCODED_VALUE+";charset=utf-8"); //application/x-www-form-urlencoded;charset=utf-8와 동일한 것
		
		//바디 파라미터
		MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
		params.add("cid", "TC0ONETIME");
		params.add("tid", readyVO.getTid());
		params.add("partner_order_id", "202204070001");
		params.add("partner_user_id","pikachu");
		params.add("pg_token", pg_token);
		params.add("total_amount","1000");
		
		//헤더, 바디 합치기
		HttpEntity<MultiValueMap<String, String>> body 
		= new HttpEntity<MultiValueMap<String,String>>(params, headers);
		
		//요청 
		try {
			KakaoPayApprovalVO approvalVO = 
			restTemplate.postForObject(new URI("https://kapi.kakao.com/v1/payment/approve"),
					body, KakaoPayApprovalVO.class);
			System.out.println("!approvalVO! "+ approvalVO);
			return approvalVO; //응답으로 받은 정보 리턴
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		return null; //위에 처리 안되면 null 리턴
		
	}

	 
}

 

3.

package com.board.domain;

import java.util.Date;

import lombok.Data;

@Data
public class KakaoPayApprovalVO {

	private String aid;
	private String tid;
	private String cid;
	private String sid;
	private String partner_order_id;
	private String partner_user_id;
	private String payment_method_type;
	private AmountVO amount;
	private CardInfoVO card_info;
	private String item_name;
	private String item_code;
	private Integer quantity;
	private Date created_at;
	private Date approved_at;
	private String payload;
}

 

 

4.

package com.board.domain;

import java.util.Date;

import lombok.Data;

//카카오 결제 준비에서 요청하고 응답 받을 데이터들의 VO
@Data
public class KakaoPayReadyVO {

	private String tid; //결제 고유 번호 
	private String next_redirect_app_url; //모바일 앱인 경우 결제 페이지 redirect url
	private String next_redirect_mobile_url; // 모바일 웹인 경우
	private String next_redirect_pc_url;	//pc 웹일 경우 요청 메세지 보내기 위한 사용자 정보 입력 화면 redirect url
	private Date created_at; 
}

 

 

5.

package com.board.domain;

import lombok.Data;

@Data
public class AmountVO {
	private Integer total;
	private Integer tax_free;
	private Integer vat;
	private Integer point;
	private Integer discount;

}

 

 

6.

package com.board.domain;

import lombok.Data;

@Data
public class CardInfoVO {
	private String purchase_corp, purchase_corp_code;
	private String issuer_corp, issuer_corp_code;
	private String kakaopay_purchase_corp, kakaopay_purchase_corp_code;
	private String kakaopay_issuer_corp, kakaopay_issuer_corp_code;
	private String bin, card_type, install_month; 
	private String approved_id, card_mid, interest_free_install, card_item_code; 

}

 

 

7.

<%@ 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>
</head>
<body>
	<h1>카카오 테스트</h1>
	<form action="/kakao/kakaoPay" method="post">
	<%--결제할 상품과 금액 등의 정보 추가 --%>
	<button>결제하기</button>
	</form>

</body>
</html>

 

 

8.

package com.board.domain;

import java.util.Date;

import lombok.Data;

@Data
public class KakaoPayApprovalVO {

	private String aid;
	private String tid;
	private String cid;
	private String sid;
	private String partner_order_id;
	private String partner_user_id;
	private String payment_method_type;
	private AmountVO amount;
	private CardInfoVO card_info;
	private String item_name;
	private String item_code;
	private Integer quantity;
	private Date created_at;
	private Date approved_at;
	private String payload;
}

 

 

9.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>success</title>
</head>
<body>
<h1>카카오 페이 성공</h1>

<%--결제 승인 요청 후 응답 받는 내용 확인 차 view에 출력 --%>
<p>요청 고유 번호: ${payInfo.aid}</p>
<p>결제 고유 번호: ${payInfo.tid}</p>
<p>가맹점 코드: ${payInfo.cid}</p>
<p>가맹점 주문 코드: ${partner_order_id}</p>
<p>가맹점 회원: ${partner_user_id}</p>
<p>결제 수단: ${payment_method_type}</p>
<p>결제 금액: ${payInfo.amount}</p>


</body>
</html>