๐ ์นด์นด์คํ์ด ๊ฒฐ์ ์ฐ๋ ์ ๋ฆฌ (React + Spring Boot ๋ฐฑ์๋)
1. ์ ์ฒด ๊ฒฐ์ ํ๋ฆ
- ๊ฒฐ์ ์ค๋น ์์ฒญ (
/api/payments/ready
)
- ํ๋ก ํธ์์
courseId
์ ๋ฌ
- ๋ฐฑ์๋๊ฐ ์นด์นด์คํ์ด API ํธ์ถ โ
next_redirect_pc_url
์๋ต
- ํ๋ก ํธ์์ ํด๋น URL๋ก ์ด๋ โ ์นด์นด์ค ๊ฒฐ์ ์ฐฝ ์ด๋ฆผ
- ๊ฒฐ์ ์งํ (์นด์นด์ค ํ๋ฉด)
- ์ฌ์ฉ์๊ฐ ๊ฒฐ์ ์๋จ ์ ํ ๋ฐ ๊ฒฐ์ ์งํ
- ์ฑ๊ณต ์, ์นด์นด์ค๊ฐ
success_url
๋ก pg_token
์ ๋ถ์ฌ ๋ฆฌ๋ค์ด๋ ํธ
- ๊ฒฐ์ ์น์ธ ์์ฒญ (
/api/payments/approve
)
- ํ๋ก ํธ์์
pg_token
์ ๋ฐฑ์๋์ ์ ๋ฌ
- ๋ฐฑ์๋๊ฐ ์นด์นด์คํ์ด API๋ก ์น์ธ ์์ฒญ
- ์ฑ๊ณต ์ DB์ ๊ฒฐ์ ๋ด์ญ ์ ์ฅ + ์ ์ ์ ์๊ฐ ๋ฑ๋ก ์ฒ๋ฆฌ
2. ํ๋ก ํธ์๋ ๊ตฌ์ฑ
โ
๊ฒฐ์ ๋ฒํผ
- ์ปดํฌ๋ํธ:
<KakaoPayButton courseId={1} />
- ์ญํ :
/api/payments/ready
ํธ์ถ
- ์ฑ๊ณต ์
next_redirect_pc_url
๋ก ๋ฆฌ๋ค์ด๋ ํธ
export function KakaoPayButton({ courseId }) {
const requestPayment = async () => {
const res = await axios.post(`/api/payments/ready?courseId=${courseId}`, {}, {
headers: { Authorization: `Bearer ${localStorage.getItem("accessToken")}` },
});
window.location.href = res.data.next_redirect_pc_url;
};
return <button onClick={requestPayment}>๐ณ ์นด์นด์คํ์ด๋ก ๊ฒฐ์ ํ๊ธฐ</button>;
}
โ
๊ฒฐ์ ์น์ธ ํ์ด์ง
- ์ปดํฌ๋ํธ:
<KakaoPayApprovePage />
- ์ญํ :
- URL ์ฟผ๋ฆฌ์์
pg_token
์ถ์ถ
/api/payments/approve
ํธ์ถ
- ์น์ธ ์๋ฃ ์ โ ๋ด ๊ฐ์์ค ์ด๋
export function KakaoPayApprovePage() {
const [searchParams] = useSearchParams();
const pgToken = searchParams.get("pg_token");
useEffect(() => {
if (!pgToken) return;
axios.get(`/api/payments/approve?pg_token=${pgToken}`, {
headers: { Authorization: `Bearer ${localStorage.getItem("accessToken")}` },
})
.then(() => window.location.href = "/my-courses")
.catch(() => alert("๊ฒฐ์ ์น์ธ ์คํจ"));
}, [pgToken]);
return <div>๊ฒฐ์ ์น์ธ ์ค์
๋๋ค...</div>;
}
โ
์ฑ๊ณต ํ์ด์ง (์ ํ)
/payment/success
๋ผ์ฐํธ์์ ์ฒ๋ฆฌ
pg_token
์ถ์ถ ํ /approve
API ํธ์ถ