‡๐Ÿ‘ฉ‍๐Ÿ’ป ‡/ºSpring

[Spring] ๊ฒฐ์ œ ์„œ๋น„์Šค | ํฌํŠธ์› ์—ฐ๊ฒฐํ•˜๊ธฐ

Trudy | ์†ก์—ฐ 2024. 1. 2. 19:26

๊ฒฐ์ œ ์„œ๋น„์Šค ํ”Œ๋žซํผ PortOne

PortOne์€ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ์™€ ๊ด€๋ จ๋œ ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ธฐ์—… ๋˜๋Š” ํ”Œ๋žซํผ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์€ ๋‹ค์–‘ํ•œ ๊ฒฐ์ œ ์ˆ˜๋‹จ์„ ์ œ๊ณตํ•˜๊ณ , ์˜จ๋ผ์ธ ์ƒ๊ฑฐ๋ž˜๋‚˜ ๋‹ค๋ฅธ ๋””์ง€ํ„ธ ๊ฒฐ์ œ ํŠธ๋žœ์žญ์…˜์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” API, ์†Œํ”„ํŠธ์›จ์–ด ๋ฐ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

PortOne์€ ๋ณด์•ˆ, ์‹ ๋ขฐ์„ฑ, ๋‹ค์–‘ํ•œ ๊ฒฐ์ œ ๋ฐฉ๋ฒ• ์ง€์› ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ”๊ณ  ์žˆ์œผ๋ฉฐ, ์ƒ์ธ๋“ค์ด ์•ˆ์ „ํ•˜๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

์„œ๋น„์Šค์˜ ์„ธ๋ถ€์ ์ธ ๊ธฐ๋Šฅ์ด๋‚˜ ์ œ๊ณต๋˜๋Š” API์˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ๋“ฑ ์•„๋ž˜  ๊ณต์‹ ์›น์‚ฌ์ดํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๊ฐœ๋ฐœํ•˜๋ฉด ๋œ๋‹ค. 

 

https://portone.io/korea/ko

 

ํฌํŠธ์›, ์˜จ๋ผ์ธ ๋น„์ฆˆ๋‹ˆ์Šค๋ฅผ ์œ„ํ•œ ํ†ตํ•ฉ ๊ฒฐ์ œ ์†”๋ฃจ์…˜

์ฝ”๋“œ ํ•œ ์ค„๋กœ ์„ธ์ƒ ๋ชจ๋“  ๋ฐฉ์‹์˜ ๊ฒฐ์ œ๋ฅผ ๊ฒฝํ—˜ํ•ด๋ณด์„ธ์š”

portone.io


๊ฒฐ์ œ๋Œ€ํ–‰์‚ฌ ์„ค์ • ๋ฐ ์ถ”๊ฐ€


PG ์ƒ์ ์•„์ด๋”” (CID)

๊ฒฐ์ œํ•˜๊ธฐ ๋ฒ„ํŠผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•œ html ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ–ˆ๋‹ค. 

์ด๋•Œ init(๊ฐ€๋งน์  ์‹๋ณ„์ฝ”๋“œ)์™€ pg: {๋“ฑ๋กํ•  pg์‚ฌ}.{pg์ƒ์ ์•„์ด๋””} ๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ์–ด์•ผ ํ–ˆ๋‹ค. 

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- jQuery -->
    <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js" ></script>
    <!-- iamport.payment.js -->
    <script type="text/javascript" src="https://cdn.iamport.kr/js/iamport.payment-1.2.0.js"></script>
    <script>
        var IMP = window.IMP; 

	//๊ฐ€๋งน์  ์‹๋ณ„์ฝ”๋“œ ์ž…๋ ฅ
        IMP.init("imp62836256"); 
      
        var today = new Date();   
        var hours = today.getHours(); // ์‹œ
        var minutes = today.getMinutes();  // ๋ถ„
        var seconds = today.getSeconds();  // ์ดˆ
        var milliseconds = today.getMilliseconds();
        var makeMerchantUid = hours +  minutes + seconds + milliseconds;
        
        function requestPay() {
            IMP.request_pay({
		//๋“ฑ๋กํ•  pg์‚ฌ.PG์ƒ์ ์•„์ด๋”” 
                pg : 'kakaopay.TC0ONETIME',

                pay_method : 'card',
                merchant_uid: "IMP"+makeMerchantUid, 
                name : '๋‹น๊ทผ 10kg',
                amount : 50000,
                buyer_email : 'Iamport@chai.finance',
                buyer_name : '์•„์ž„ํฌํŠธ ๊ธฐ์ˆ ์ง€์›ํŒ€',
                buyer_tel : '010-1234-5678',
                buyer_addr : '์„œ์šธํŠน๋ณ„์‹œ ๊ฐ•๋‚จ๊ตฌ ์‚ผ์„ฑ๋™',
                buyer_postcode : '123-456',
                display: {
                    card_quota: [3]  // ํ• ๋ถ€๊ฐœ์›” 3๊ฐœ์›”๊นŒ์ง€ ํ™œ์„ฑํ™”
                }
            }, function (rsp) { // callback
                if (rsp.success) {
                    $.ajax({
						type: 'GET',
						url: 'http://localhost:8080/validation?impUid='+rsp.imp_uid
					}).done(function(data) {
						console.log(data);
					})
				
                } else {
                    console.log(rsp);
                }
            });
        }
    </script>
    <meta charset="UTF-8">
    <title>Sample Payment</title>
</head>
<body>
    <button onclick="requestPay()">๊ฒฐ์ œํ•˜๊ธฐ</button> <!-- ๊ฒฐ์ œํ•˜๊ธฐ ๋ฒ„ํŠผ ์ƒ์„ฑ -->
</body>
</html>

 

PG์ƒ์  ์•„์ด๋””๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค. 

 


 

CORS Error

 

ํ”„๋ก ํŠธ์™€ ๋ฐฑ์˜ url์ด ๋‹ฌ๋ผ์„œ ๋‚˜๋Š” error์ด๋‹ค. 

@RestController์„ ์ด์šฉํ•ด์„œ front์™€ back์„ ๋ถ„๋ฆฌํ•ด์„œ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ๋‹ค. 

์•„๋ž˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ”„๋ก ํŠธ๋งŒ ๋งŒ๋“ค์–ด์„œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ๋ฐฑ์—”๋“œ์— ๋ถ™์–ด์„œ ์š”์ฒญํ•˜๋ฉด ํฐ ๋ฌธ์ œ๊ฐ€ ์ดˆ๋ž˜๋  ์ˆ˜ ์žˆ๋‹ค. 

 

์ด๊ฑธ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ฐฑ์—”๋“œ์—์„œ ํŠน์ • ํ”„๋ก ํŠธ์„œ๋ฒ„์˜ ์š”์ฒญ๋งŒ ๋ฐ›๋„๋ก ์„ค์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

๊ฒฐ๋ก ์€ ๋ฐฑ์—”๋“œ์— ํŠน์ • ํ”„๋ก ํŠธ์—”๋“œ๋งŒ์„ ํ—ˆ์šฉํ•˜๋Š” ์„ค์ •์„ ํ•˜๋ฉด ๋œ๋‹ค.

 

์ด ๋ฌธ์ œ๋Š” @CrossOrigin() ์œผ๋กœ ํ—ˆ์šฉํ•  ํ”„๋ก ํŠธ ์„œ๋ฒ„๋ฅผ ์ง€์ •ํ•จ์œผ๋กœ์จ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. 

//@CrossOrigin ์œผ๋กœ ํŠน์ • ํ”„๋ก ํŠธ๋งŒ ์—ฐ๊ฒฐ ํ•˜๋„๋ก ์„ค์ •!! CORS ์—๋Ÿฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•จ 
// *๋กœ ํ–ˆ์œผ๋‹ˆ ๋ชจ๋‘ ํ—ˆ์šฉํ•ด ์ฃผ๊ฒ ๋‹ค.
@RestController
@CrossOrigin("*")
public class OrderController {
 	...
}

๊ฒฐ์ œ ์ทจ์†Œ(ํ™˜๋ถˆ)

 

https://developers.portone.io/api/rest-v1/payment?v=v1#post%20%2Fpayments%2Fcancel

์œ„ ๋ฉ”๋‰ด์–ผ์„ ์ฐธ๊ณ ํ•˜์—ฌ ๊ฐœ๋ฐœํ•˜๋ฉด ๋œ๋‹ค. 

POST ๋ฐฉ์‹์œผ๋กœ /payments/cancel๋กœ Https์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค. 

์ฃผ์˜ํ•  ์ ์€ BODY์˜ ๋ชจ๋“  ๋ถ€๋ถ„์ด Optional๋กœ ์ฃผ์–ด์ ธ์žˆ์ง€๋งŒ, imp_uid์™€ merchant_uid ๋‘˜ ์ค‘ ํ•˜๋‚˜๋Š” ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.

 

OrderController.java

private void paymentCancel(String token, String impUid, String amount, String reason) throws IOException {
        URL url = new URL("https://api.iamport.kr/payments/cancel");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        conn.setRequestMethod("POST");

        // ์š”์ฒญ์˜ Content-Type, Accept, Authorization ํ—ค๋” ์„ค์ •
        conn.setRequestProperty("Content-type", "application/json");
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Authorization", token);

        // ํ•ด๋‹น ์—ฐ๊ฒฐ์„ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ(์š”์ฒญ)์œผ๋กœ ์‚ฌ์šฉ
        conn.setDoOutput(true);

        // JSON ๊ฐ์ฒด์— ํ•ด๋‹น API๊ฐ€ ํ•„์š”๋กœํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€.
        JsonObject json = new JsonObject();
        json.addProperty("imp_uid", impUid);
        json.addProperty("reason", reason);

        // ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ํ•ด๋‹น conn์— ์š”์ฒญ
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
        bw.write(json.toString());
        bw.flush();
        bw.close();

        // ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ conn ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต ๋ฐ˜ํ™˜
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        Gson gson = new Gson();
        String response = gson.fromJson(br.readLine(), Map.class).toString();

        System.out.println(response);

        br.close();
        conn.disconnect();

        System.out.println("๊ฒฐ์ œ ์ทจ์†Œ ์™„๋ฃŒ: ์ฃผ๋ฌธ๋ฒˆํ˜ธ " + impUid);

    }

์ „์ฒด ์ฝ”๋“œ 

https://github.com/SongYeonBaek/be02-shopping-mall-practice

 

GitHub - SongYeonBaek/be02-shopping-mall-practice

Contribute to SongYeonBaek/be02-shopping-mall-practice development by creating an account on GitHub.

github.com