https://docs.tosspayments.com/guides/payment-widget/integration
ํ ์คํ์ด๋จผ์ธ ์์ ์ ๊ณตํ๋ ๊ฒฐ์ flow๋ ์์ ๊ฐ๋ค.
์ฃผ์ ์ ๋ณด ๋ช๊ฐ์ง๋ง ์บก์ณํด์ ๋ฃ์์ง๋ง ์๋ ์ด๋ฏธ์ง์์๋ ๋ณผ ์ ์๋ฏ
ํ ์คํ์ด๋จผ์ธ ์์๋ ๊ฐ๋ฐํ๊ธฐ ํธ๋ฆฌํ๊ฒ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ค.
๊ฐํธ๊ฒฐ์ ๋ฅผ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด ์ฐ์ ๋ณธ์ธ์ด ์ํ๋ ํ๋ซํผ์์ ์ ๊ณตํ๋ ๊ฒฐ์ ํ๋ฆ์ด๋ ์ ์ฉ ๋ฐฉ์์ ๋ํด ๋จผ์ ์์ธํ๊ฒ ๊ณต๋ถํ๊ธฐ๋ฅผ ์ถ์ฒํ๋ค.
๋๋ ์ฌ์ ์ ๋ง์ ์ ๋ณด๋ฅผ ์ฐพ์๋ณด๊ณ ํ ์คํ์ด๋จผ์ธ flow๋ฅผ ์ดํดํ๋ค! ๋ผ๊ณ ์๊ฐํ์์๋ ๋ถ๊ตฌํ๊ณ ๋ง์ ๊ฐ๋ฐํ ๋ ๋ง์ ์ ๋ฅผ ๋จน์๋ค..
์์ฃผ! ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํด๋ณด๋ฉด
๊ฒฐ์ ์์ ฏ์ ํ๋ฉด์ ๋์ฐ๊ณ ๊ฒฐ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํ ํ ์์ฒญ์ ํ๋ค.
ํ ์คํ์ด๋จผ์ธ ์์ ํด๋น ์ ๋ณด๋ฅผ ๊ฒ์ฆํ๊ณ ์น์ธํ ํ์ ๊ฒฐ์ ์ ์ฑ๊ณตํ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ์ฟผ๋ฆฌ๋ก ๋ฆฌ๋ค์ด๋ ํธ ํด์ค๋ค.
์ฟผ๋ฆฌ์ ๋ด๊ธด ๊ฒฐ์ ๋ฅผ ๊ตฌ๋ถํ payment key, orderId, ๊ธ์ก๊ณผ ๊ฐ์ ๊ฒ์ ๋ฝ์์ ๋ฐฑ์๋๋ก ๋๊ธด๋ค.
๋ฐฑ์๋๋ ํด๋น ์ ๋ณด๋ฅผ DB์ ์ ์ฅํ๋ค.
https://github.com/tosspayments/payment-widget-sample
-> ์ ๋งํฌ์ ์ ์ํ๋ฉด ํ ์คํ์ด๋จผ์ธ ์์ ์ ๊ณตํ๋ ๋ค์ํ ์ธ์ด๋ก ๊ฐ๋ฐ๋ ๊ฒฐ์ ์์ ฏ์ ํ์ธํ ์ ์๋ค.
<template>
<div class="wrapper">
<div class="box_section">
<!-- ๊ฒฐ์ UI -->
<div id="payment-method"></div>
<!-- ์ด์ฉ์ฝ๊ด UI -->
<div id="agreement"></div>
<!-- ๊ฒฐ์ ํ๊ธฐ ๋ฒํผ -->
<div class="result-wrapper">
<button @click="requestPayment" class="button" id="payment-button" style="margin-top: 30px">
๊ฒฐ์ ํ๊ธฐ
</button>
</div>
</div>
</div>
</template>
<script>
import {loadPaymentWidget, ANONYMOUS} from "@tosspayments/payment-widget-sdk";
import {nanoid} from "nanoid";
export default {
data() {
return {
data: null,
paymentWidget: null,
paymentMethodWidget: null,
clientKey: "test_ck_Ba5PzR0ArnWdaxZloyQ18vmYnNeD",
customerKey: nanoid(),
amount: null,
};
},
methods: {
async requestPayment() {
try {
if (this.paymentWidget) {
var regex = /[^0-9]/g;
var result = this.data.userContact.replace(regex, "");
await this.paymentWidget.requestPayment({
orderId: nanoid(),
orderName: this.data.reservationName,
customerName: this.data.userName,
customerEmail: this.data.userEmail,
reservationId: this.data.id,
customerMobilePhone: result,
successUrl: `${window.location.origin}/success?orderName=${encodeURIComponent(
this.data.reservationName)}&reservationId=${this.data.id}`,
failUrl: `${window.location.origin}/fail`,
});
}
} catch (error) {
console.error(error);
}
},
},
async mounted() {
this.paymentWidget = await loadPaymentWidget(this.clientKey, ANONYMOUS);
this.paymentMethodWidget = this.paymentWidget.renderPaymentMethods("#payment-method",
{value: this.amount}, {variantKey: "DEFAULT"});
this.paymentWidget.renderAgreement("#agreement", {variantKey: "AGREEMENT"});
},
created() {
const {data} = history.state;
this.data = data;
this.amount = this.data.price
}
};
</script>
<style>
.box_section {
width: 650px;
background-color: white;
border-radius: 10px;
box-shadow: 0 10px 20px rgb(0 0 0 / 1%), 0 6px 6px rgb(0 0 0 / 6%);
padding: 40px 30px 50px 30px;
margin: auto;
margin-top: 100px;
color: #333D4B;
}
.button{
color: #f9fafb;
background-color: #3182f6;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 18px;
white-space: nowrap;
text-align: center;
cursor: pointer;
border: 0 solid transparent;
user-select: none;
transition: background 0.2s ease, color 0.1s ease;
text-decoration: none;
border-radius: 7px;
padding: 10px 13px;
}
.result-wrapper{
display: flex;
flex-direction: column;
align-items: center;
}
</style>
์ฐ๋ฆฌ๋ ๊ฒฐ์ ํ๋ฉด์ Vue๋ก ๋์ ๋ค.
ํด๋น ์ฝ๋๋ก ๊ฒฐ์ ์์ ฏ์ ๋ถ๋ฌ์ค๊ณ ์ ๋ ฅํ ๊ฒฐ์ ์ ๋ณด๋ฅผ ๋ฐฑ์๋๋ก ๋๊ธฐ๋ฉด
์๋ฒ์์ ํ ์คํ์ด๋จผ์ธ ์ธก์ ๊ฒฐ์ ์น์ธ์ ์์ฒญํ๋ค.
์ ์ฝ๋ ์์ฑํ๊ธฐ๊น์ง๋ ์ฐธ ๋ง์ ๊ณผ์ ์ด ์์๋ค.
Vue์ ๊ฐ์ฅ ์ต๊ทผ ๋ฒ์ ์ด Vue3 ๋ผ๊ณ ์๊ณ ๊ทธ๊ฑธ ๊ธฐ์ค์ผ๋ก webpack์ผ๋ก ์ค์น๊น์ง ์๋ฃํ๋๋ฐ
ํ ์ค์์ ์ ๊ณตํ๋ ๊ฒ vite ๋ฒ์ ์ด๋ผ ํ๋ก์ ํธ ์ค์ ์ ์์ ๋ฐ๊ฟ์ผํ๋ ์ถ์ด์ ๋ฐ๊พธ๋ ค๊ณ ์ฝ์งํ๋ค๊ฐ
์ญ์ ์ฌ์ค์น ์ญ์ ์ฌ์ค์น ๋ฐ๋ณตํ๋ค ๋ค์ webpack์ผ๋ก ๋๊ณ ์ฝ๋๋ฅผ ๋ฏ์ด๋ณด๋ ์ค์ ๋ฌธ์ ๊ฐ ์๋๋ผ
์ฝ๋ ๋ฌธ์ ๋ผ๋ ๊ฒ์ ๋ฐ๊ฒฌํ๊ณ ์์ ํด์ ๊ฒฐ๊ตญ ํด๊ฒฐํ ๊ฒฝํ..
์๋ฌด๋๋ ํด๋น ์ธ์ด, ํ์ผ๊ตฌ์กฐ๊ฐ ์ต์ํ์ง ์์์ ์ฌ์ํ ๋ฌธ์ ๊ฐ ๊ณ์ ๋ฐ์ํ๋ค..
public class PaymentController {
private final PaymentServiceImplV1 paymentService;
@PostMapping("reservation/{reservationId}/payment")
@Operation(summary = "๊ฒฐ์ ์์ฒญ", description = "์์ฝ ๊ฑด์ ๋ํด ๊ฒฐ์ ์์ฒญ์ ํ๋ค.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "๊ฒฐ์ ์ฑ๊ณต"),
@ApiResponse(responseCode = "400", description = "์กด์ฌํ์ง ์๋ ์์ฝ์
๋๋ค."),
})
public ResponseEntity<CommonResponse<PaymentResponseDto.CreatePaymentResponseDto>> createPayment(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@PathVariable Long reservationId,
@RequestBody PaymentRequestDto.CreatePaymentRequestDto requestDto) {
PaymentResponseDto.CreatePaymentResponseDto paymentResponseDto = paymentService.createPayment(
userDetails.getUser().getId(),
reservationId,
requestDto);
return ResponseEntity.status(HttpStatus.CREATED).body(
new CommonResponse<>(
HttpStatus.CREATED,
"๊ฒฐ์ ์ฑ๊ณต",
paymentResponseDto
)
);
}
์ฐ๋ฆฌ๋ ์์ฝ ์ ๋ณด๋ฅผ ํฌํจํด์ ๋๊ธฐ๊ณ ์์ฝ์ ๋ณด๊ฐ ์ผ์นํ ๊ฒฝ์ฐ์๋ง ๊ฒฐ์ ์์ฒญ์ ํ๋๋ก ๊ตฌํํ๋ค.
์ด๋ ๊ฒ ๊ฒฐ์ ์น์ธ์ด ๋จ์ด์ง๋ฉด ํ ์คํ์ด๋จผ์ธ ์ธก์์ ํด๋ผ์ด์ธํธ์ ์ฑ๊ณต URL์ ๋๊ฒจ์ฃผ๊ณ ํด๋ผ์ด์ธํธ๋ ๋ฐ์์จ ์ ๋ณด๋ฅผ ๋ค์ ์๋ฒ์ ๋๊ฒจ
DB์ ์ ์ฅ๋๋ค.
private PaymentResponseDto.CreatePaymentResponseDto handleSuccessfulResponse(
PaymentRequestDto.CreatePaymentRequestDto requestDto
, Reservation reservation) {
Payment payment = Payment.builder()
.orderId(requestDto.getOrderId())
.orderName(requestDto.getOrderName())
.amount(requestDto.getAmount())
.paymentKey(requestDto.getPaymentKey())
.paymentType(requestDto.getPaymentType())
.reservation(reservation)
.build();
paymentRepository.save(payment);
return PaymentResponseDto.CreatePaymentResponseDto.from(payment);
}
์๋ฒ์์ ํ ์คํ์ด๋จผ์ธ ์ธก์ผ๋ก ๊ฒฐ์ ์์ฒญ์ ํ๋ ์ฝ๋๋ ์๋จ์ Github ๋งํฌ์์ ์ฐธ๊ณ ํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข๋ค.
๋๋ ์ ๊ณต๋ ์ฝ๋๋ฅผ ํ๋ก์ ํธ์ ๋ง๊ฒ ์ปค์คํ ํด์ ๊ตฌํํ๋ค.
์ฐ์ฌ๊ณก์ ๋์ ๊ฒฐ๊ตญ ์์ฑํ๊ธด ํ๋ค.
๋ค๋ง, ์๊ฐ ๊ด๊ณ์ ๊ตฌํํ์ง ๋ชปํ ๋ถ๋ถ๋ค์ด ๊ฝค๋ ์์ด ์๋นํ ์์ฝ๋ค.
Vue.js๋ฅผ ์ฒ์ ๋ค๋ค๋ณด๋ ๊ฑฐ๋ผ ์ด ๋ถ๋ถ์์ ์์์น ๋ชปํ๊ฒ ๋ง์ ์๊ฐ์ด ์์๋๋ค.
ํ๋ก ํธ๋ ๋ฐฑ์ ์ฐ๊ฒฐํ๋ ๊ฒฝํ ์์ฒด๊ฐ ์ฒ์์ด๋ผ ์ ๋ง ์ ๋ฅผ ๋จน์๋ค..
๊ฒฐ์ ์ ๋ณด๊ฐ DB์ ์ ์์ด๋๊ฒ ๊ฐ์ฅ ํฐ ๋๊ด์ด์๋๋ฐ ์ด์ฒ๊ตฌ๋ ์์ด ์ฝ๋ ํ ์ค๋ง ์์ ํ๋ฉด ๋๋ ๋ฌธ์ ์๋ค.. (์ฝ๋๋ฅผ ๊ผผ๊ผผํ๊ฒ ์ดํ์๋ค ..)
๊ทธ๋ฆฌ๊ณ DB ์ฐ๊ฒฐ๋ ๊ฒ ํ์ธํ๋๋ฐ ๋ฐฐํฌํ๊ณ ๋์ ๊ฐ์๊ธฐ ๋ ์ ๋๋ ๊ฒฝ์ฐ.. (์ด๊ฒ ๋ํ ์ฃผ์ ์คํ ๋ฌธ์ .. ๊ผผ๊ผผํ๊ฒ ํ์ธํฉ์๋ค..)
๋ฐฐํฌํ๊ณ ๋์๋ ๋ก์ปฌ, ๋ฐฐํฌ ์ฃผ์ ์๋ค ๊ฐ๋ค ํ๋ฉด์ ๊ฐ๋ฐ์ ์งํํ๋๋ฐ ์ฌ๊ธฐ์ ๊ผผ๊ผผํ๊ฒ ํ์ธํ์ง ์์ผ๋ฉด ๋ฐ์ด๋๋ค๋๊ฑธ ๊ฒฝํ์ ํตํด ์๊ฒ๋์๋ค..
์ฐ๋ฆฌ๊ฐ ์๊ฐ์ ์ซ๊ฒจ ํ๋ก ํธ ๋ถ๋ถ์ ์ฝ๋์ปจ๋ฒค์ ์ ์ ๋๋ก ์งํค์ง ๋ชปํ๋๋ฐ ์ด๋ฒ ํ๋ก์ ํธ ๊ฒฝํ์ ํตํด
ํ์ ์์ ์ฝ๋์ปจ๋ฒค์ , github์ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ง๋ ํ์์ ์ด๊ณ ์ค์ํ ๊ฒ์ธ์ง ๊นจ๋ฌ์๋ค.
'PROJECT' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
AirDnS ํ๊ณ #1 (0) | 2024.04.11 |
---|---|
Spring PROJECT (5) | 2023.12.26 |