๐ ์์ฝ
ํ ์ค ๊ฒฐ์ฌ API ๋ฅผ ์ด์ฉํด์ ์ผํ๋ชฐ ๊ฒฐ์ฌ ๋ถ๋ถ ์ํ์ ์งํํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฃผ๋ฌธ๋ฒํธ๋ฅผ ํ ์ค ๊ฒฐ์ฌ API ๋ก ์ ๋ฌํ๊ณ ํ ์ค ๊ฒฐ์ฌ์์ ๊ฒฐ์ฌ ์งํ ํ์ ๊ฐ๋ตํ ๊ฒฐ๊ณผ๋ฅผ ํ๋ฉด์ ์ถ๋ ฅํด ๋ณด๊ฒ์ต๋๋ค.
๊ฒฐ์ฌ ์งํํ์ ๊ฒฐ์ฌ ํ
์ด๋ธ์ ๊ฒฐ์ฌ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค.
๋จ, ์ฃผ๋ฌธ์ ๋ณดํ
์ด๋ธ์ ์ฃผ๋ฌธ์ํ(์ฃผ๋ฌธ์๋ฃ->๊ฒฐ์ฌ์๋ฃ) ๋ณ๊ฒฝ์ด ํ์ํ๋ ๊ฒฐ์ฌ API ํ์ฉ๋ฐฉ๋ฒ์ ์ง์คํ๊ธฐ ์ํด ์๋ตํ๋๋ก ํ๊ฒ ์ต๋๋ค.
ํ๋ก ํธ๋ Vue ๋ฅผ ์ฌ์ฉํ๊ณ , ๋ฒก์๋๋ spring boot ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
DB ๋ ์ค๋ผํด ๋์ปค ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๊ณ ๊ณ์ ์ scott ( ์ํธ : !Ds1234567890 ) ๊ฐ๋ฐ์ ๊ณ์ ์ ์์ฑํ๊ณ ์ฌ์ฉํฉ๋๋ค.
DB ๊ฐ๋ฐ์ ๊ณ์ ๋ฐ ์ค์นํ๋ ๋ฐฉ๋ฒ์ ์๋ตํฉ๋๋ค.
์์ ๊ธฐ์ :
– ํ๋ก ํธ์๋ : Vue
– ๋ฒก์๋ : ์คํ๋ง๋ถํธ & JPA
– DB : Oracle 18xe(Docker)
( Oracle 18xe ๋์ปค ์ด๋ฏธ์ง ์ฃผ์ : https://hub.docker.com/r/kangtaegyung/oraclexe-18c )
๊ฒฐ๊ณผ ํ๋ฉด :
- ๊ฒฐ์ฌ ๋ฒํผ ํ๋ฉด

- ํ ์ค ๊ฒฐ์ฌ ํ๋ฉด #1 : ์ ์ฉ์นด๋ ์ ํ

- ํ ์ค ๊ฒฐ์ฌ ํ๋ฉด #2 : ์ฑ์นด๋ ๊ฒฐ์ฌ

- ํ ์ค ๊ฒฐ์ฌ ํ๋ฉด #3 : ์ฑ์นด๋ ๊ฒฐ์ฌ ์งํ

- ํ ์ค ๊ฒฐ์ฌ ์๋ฃ #4

- ๊ฒฐ์ฌ ์๋ฃ ํ ๊ฒฐ์ฌ ํ ์ด๋ธ์ ์ ์ฅ๋จ

ํ๋ก์ ํธ ํ์๊ธฐ : Vue

ํ๋ก์ ํธ ํ์๊ธฐ : String Boot

๋ฒก์๋ Rest API ์ ๋ณด :
| ๋ฉ์๋ | URL | ์ค๋ช |
|---|---|---|
| POST | /api/shop/simple-approval | ๊ฒฐ์ฌ ์ ์ฅ |
๐ ๊ธฐ์ ๊ตฌํ
์คํ :
- Vue 3.x - toss ๊ฒฐ์ฌ API ( ์ฐธ์กฐ : https://github.com/tosspayments/payment-widget-sample ) - jdk 17 - spring boot 3.x - intellij IDEA & gradle - logging tool : logback
ํ ์ด๋ธ ์ค๊ณ
-- Table , ์ํ์ค ๋ฑ ๊ตฌ์กฐ ์ ์
DROP SEQUENCE SQ_SIMPLE_APPROVAL;
CREATE SEQUENCE SQ_SIMPLE_APPROVAL START WITH 1 INCREMENT BY 1;
DROP TABLE TB_SIMPLE_APPROVAL CASCADE CONSTRAINT;
-- ๊ฒฐ์ฌ ์ ๋ณด ํ
์ด๋ธ
CREATE TABLE TB_SIMPLE_APPROVAL
(
SANO NUMBER NOT NULL PRIMARY KEY, -- ๊ฒฐ์ฌ๋ฒํธ(PK), ์ํ์ค
APPROVAL_DATE VARCHAR2(1000) , -- ๊ฒฐ์ฌ์ผ์ : YYYY-MM-DD HH24:MI:SS
APPROVAL_AMOUNT NUMBER NOT NULL
);
๊ฒฐ์ฌ API ๊ตฌํ์ ์ํ ํ ์ด๋ธ ์ค๊ณ์ ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค๋ผํด(Docker)์ ์ฌ์ฉํ์ฌ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
Spring build.gradle : dependencies ๋ธ๋ญ ๋ด ์ถ๊ฐ
dependencies {
// ์ค๋ผํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ( 19c )
implementation 'com.oracle.database.jdbc:ucp:19.14.0.0'
implementation 'com.oracle.database.security:oraclepki:19.14.0.0'
implementation 'com.oracle.database.security:osdt_cert:19.14.0.0'
implementation 'com.oracle.database.security:osdt_core:19.14.0.0'
// logback , log4jdbc ์ค์
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
... ์๋ต
}
๊ฒฐ์ฌ ์ํฐํฐ
– SimpleApproval.java
package com.example.simpledms.model.entity.shop;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
/**
* @fileName : SimpleApproval
* @author : kangtaegyung
* @since : 11/22/23
* description : ๊ฒฐ์ฌ
*/
@Entity
@Table(name = "TB_SIMPLE_APPROVAL")
@SequenceGenerator(
name = "SQ_SIMPLE_APPROVAL_GENERATOR"
, sequenceName = "SQ_SIMPLE_APPROVAL"
, initialValue = 1
, allocationSize = 1
)
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
public class SimpleApproval {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE
, generator = "SQ_SIMPLE_APPROVAL_GENERATOR"
)
private Integer sano; // ๊ฒฐ์ฌ๋ฒํธ, ๊ธฐ๋ณธํค, ์ํ์ค
private String approvalDate; // ๊ฒฐ์ฌ์ผ
private Integer approvalAmount; // ๊ฒฐ์ฌ๊ธ์ก
}
๊ฒฐ์ฌ ๋ ํฌ์งํ ๋ฆฌ
– SimpleApproval.java
package com.example.simpledms.repository.shop;
import com.example.simpledms.model.entity.shop.SimpleApproval;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* @fileName : SimpleApprovalRepository
* @author : kangtaegyung
* @since : 11/22/23
* description : ์ฃผ๋ฌธ ๋ ํฌ์งํ ๋ฆฌ
*/
@Repository
public interface SimpleApprovalRepository extends JpaRepository<SimpleApproval, Integer> {
}
๊ฒฐ์ฌ ์๋น์ค
– SimpleApprovalService.java
package com.example.simpledms.service.shop;
import com.example.simpledms.model.entity.shop.SimpleApproval;
import com.example.simpledms.repository.shop.SimpleApprovalRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @fileName : SimpleApprovalService
* @author : kangtaegyung
* @since : 11/22/23
* description : ๊ฒฐ์ฌ ์๋น์ค
*/
@Service
@RequiredArgsConstructor
public class SimpleApprovalService {
private final SimpleApprovalRepository simpleApprovalRepository;
public void save(SimpleApproval simpleApproval) {
simpleApprovalRepository.save(simpleApproval);
}
}
๊ฒฐ์ฌ ์ปจํธ๋กค๋ฌ
– SimpleApprovalController.java
package com.example.simpledms.controller.shop;
import com.example.simpledms.model.entity.shop.SimpleApproval;
import com.example.simpledms.service.shop.SimpleApprovalService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* @fileName : SimpleApprovalController
* @author : kangtaegyung
* @since : 11/22/23
* description : ๊ฒฐ์ฌ ์ปจํธ๋กค๋ฌ
*/
@Slf4j
@RestController
@RequestMapping("/api/shop")
@RequiredArgsConstructor
public class SimpleApprovalController {
private final SimpleApprovalService simpleApprovalService;
@PostMapping("/simple-approval")
public ResponseEntity<Object> create(@RequestBody SimpleApproval simpleApproval) {
simpleApprovalService.save(simpleApproval);
return new ResponseEntity<>(HttpStatus.OK);
}
}
๊ณตํต Exception ย ํด๋์ค
– CommonExceptionAdvice.java
- ์ปจํธ๋กค๋ฌ์์ ์ด๋ค ์๋ฌ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ด ํด๋์ค์ internalServerErrorException ํจ์๊ฐ ์คํ๋จ
package com.example.simpledms.exceptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author : kangtaegyung
* @fileName : ExControllerAdvice
* @since : 24. 5. 27.
* description : ๊ณตํต๋ ์์ธ ์ฒ๋ฆฌ ํจ์
* @ResponseStatus(HttpStatus.์ํ์ฝ๋) : ์ํ์ฝ๋๊ฐ ๋ฐ์ํ๋ฉด
* @ExceptionHandler(Exception.class) : Exception ์์ธ ํด๋์ค์ ๋ํด ์ฒ๋ฆฌํ๋ค.
*/
@Slf4j
@RestControllerAdvice
public class CommonExceptionAdvice {
// ์ปจํธ๋กค๋ฌ์์ ์ด๋ค ์๋ฌ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ด ํจ์๊ฐ ์คํ๋จ
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ResponseEntity<?> internalServerErrorException(Exception e) {
log.debug("๋ฒก์๋ ์๋ฌ: " + e.getMessage());
return new ResponseEntity<>("๋ฒก์๋ ์๋ฌ: " + e.getMessage()
, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Vue ํ์ด์ง
– Vue ํจํค์ง ์ถ๊ฐ :
npm i @tosspayments/payment-widget-sdk npm i axios
1) ๊ณตํต js
– utils/axiosDefaultConfig.js : axios ๊ธฐ๋ณธ ์ค์ ํ์ผ
import axios from "axios";
// axios ๊ธฐ๋ณธ ์ค์
export default axios.create({
baseURL: "http://localhost:8000/api",
headers: {
"Content-Type": "application/json"
}
});
– services/shop/SimpleApprovalService.js
import axiosDefault from "@/utils/axiosDefaultConfig";
class SimpleApprovalService {
create(data) {
return axiosDefault.post("/shop/simple-approval", data);
}
}
export default new SimpleApprovalService();
– router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: "/",
name: "home",
component: () => import("../views/HomeView.vue"),
},
// ๊ฒฐ์ฌ ๋ฒํผ ๋ฉ๋ด
{
path: "/simple-order",
name: "simple-order",
component: () => import("@/views/shop/simple-product/SimpleOrderList.vue"),
},
// ํ ์ค ๊ฒฐ์ฌ
{
path: '/toss-check/:sono',
component: () => import('@/views/shop/toss/CheckoutView.vue')
},
{
path: '/success',
component: () => import('@/views/shop/toss/SuccessView.vue')
},
{
path: '/fail',
component: () => import('@/views/shop/toss/FailView.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
ํ ์ค ๊ฒฐ์ฌ API ํจ์ : ํ ์ค ๊ฒฐ์ ์ฌ์ดํธ์์ ์ ๊ณต
– utils/confirmPayment.js
export async function confirmPayment(requestData) {
// TODO: ๊ฐ๋ฐ์์ผํฐ์ ๋ก๊ทธ์ธํด์ ๋ด ๊ฒฐ์ ์์ ฏ ์ฐ๋ ํค > ์ํฌ๋ฆฟ ํค๋ฅผ ์
๋ ฅํ์ธ์. ์ํฌ๋ฆฟ ํค๋ ์ธ๋ถ์ ๊ณต๊ฐ๋๋ฉด ์๋ผ์.
// @docs https://docs.tosspayments.com/reference/using-api/api-keys
const secretKey = "test_gsk_docs_OaPz8L5KdmQXkzRz3y47BMw6";
// ํ ์คํ์ด๋จผ์ธ API๋ ์ํฌ๋ฆฟ ํค๋ฅผ ์ฌ์ฉ์ ID๋ก ์ฌ์ฉํ๊ณ , ๋น๋ฐ๋ฒํธ๋ ์ฌ์ฉํ์ง ์์ต๋๋ค.
// ๋น๋ฐ๋ฒํธ๊ฐ ์๋ค๋ ๊ฒ์ ์๋ฆฌ๊ธฐ ์ํด ์ํฌ๋ฆฟ ํค ๋ค์ ์ฝ๋ก ์ ์ถ๊ฐํฉ๋๋ค.
// @docs https://docs.tosspayments.com/reference/using-api/authorization#%EC%9D%B8%EC%A6%9D
const encryptedSecretKey = btoa(secretKey+":")
// ------ ๊ฒฐ์ ์น์ธ API ํธ์ถ ------
// @docs https://docs.tosspayments.com/guides/payment-widget/integration#3-๊ฒฐ์ -์น์ธํ๊ธฐ
const response = await fetch("https://api.tosspayments.com/v1/payments/confirm", {
method: "POST",
headers: {
"Authorization": `Basic ${encryptedSecretKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(requestData),
});
const json = await response.json();
return { response, json };
}
Vue ํ์ด์ง
๊ฒฐ์ฌ ๋ฒํผ ๊ฒฐ๊ณผ ํ๋ฉด :

– views/shop/SimpleOrderList.vue
<template>
<div>
<!-- ๊ฒฐ์ฌ ๋ฒํผ -->
<div class="row d-flex justify-content-end">
<button type="button" @click="goApproval" class="btn btn-warning w-25">
Go Approval
</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// ์ฃผ๋ฌธ๋ฒํธ ์ํ(6์๋ฆฌ์ด์ : ํ ์ค ๊ฒฐ์ฌ API ํ์์๋ฆฌ์) : ์ฃผ๋ฌธ๋ฒํธ๋ ๊ณ ์ ํ ๊ฐ์ผ๋ก ํ
์คํธ ํ ๊ฒ
sono: 222235
}
},
methods: {
// ํ ์ค ๊ฒฐ์ฌํ์ด์ง๋ก ์ด๋
goApproval() {
this.$router.push("/toss-check/" + this.sono);
},
},
};
</script>
<style></style>
- ์ฃผ๋ฌธ๋ฒํธ : ๊ณ ์ ํ ๊ฐ์ผ๋ก ํ ์คํธํด์ผ ์ ์ ์คํ๋จ
- ๊ฒฐ์ฌ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ํ ์ค API ๊ฒฐ์ฌ ํ์ด์ง๋ก ์ด๋๋จ,
- ์ด๋ ์ ์ฃผ๋ฌธ๋ฒํธ๊ฐ ์น๋ธ๋ผ์ฐ์ ์ฃผ์์ฐฝ์ผ๋ก ์ ๋ฌ๋จ : /toss-check/์ฃผ๋ฌธ๋ฒํธ
ํ ์ค ๊ฒฐ์ฌ ํ๋ฉด #1 :

– views/toss/CheckoutView.vue : ํ ์ค API ์ฌ์ดํธ์์ ์ ๊ณต
<template>
<div class="wrapper">
<div class="box_section">
<!-- ๊ฒฐ์ UI -->
<div id="payment-method"></div>
<!-- ์ด์ฉ์ฝ๊ด UI -->
<div id="agreement"></div>
<!-- ๊ฒฐ์ ํ๊ธฐ ๋ฒํผ -->
<button
:disabled="!inputEnabled"
@click="requestPayment"
class="button"
id="payment-button"
style="margin-top: 30px"
>
๊ฒฐ์ ํ๊ธฐ
</button>
</div>
</div>
</template>
<script>
import { loadPaymentWidget, ANONYMOUS } from "@tosspayments/payment-widget-sdk";
export default {
data() {
return {
paymentWidget: null,
paymentMethodWidget: null,
// TODO: clientKey๋ ๊ฐ๋ฐ์์ผํฐ์ ๊ฒฐ์ ์์ ฏ ์ฐ๋ ํค > ํด๋ผ์ด์ธํธ ํค๋ก ๋ฐ๊พธ์ธ์.
// TODO: customerKey๋ ๊ตฌ๋งค์์ 1:1 ๊ด๊ณ๋ก ๋ฌด์์ํ ๊ณ ์ ๊ฐ์ ์์ฑํ์ธ์.
clientKey: "test_gck_docs_Ovk5rk1EwkEbP0W43n07xlzm",
customerKey: this.$route.params.sono, // ์ฃผ๋ฌธ๋ฒํธ(๊ณ ์ ๊ฐ, ๊ฐ๋ฐ์์ฝ๋ฉ)
amount: 0,
inputEnabled: false,
};
},
methods: {
// TODO: ํ ์ค API ๊ฒฐ์ฌ
async requestPayment() {
try {
if (this.paymentWidget) {
// TODO: ๊ฒฐ์ฌ ์์ฒญ ์์ ์ ๋ณด
let data = {
orderId: this.$route.params.sono, // ์ฃผ๋ฌธ๋ฒํธ(๊ฐ๋ฐ์์ฝ๋ฉ), ํ์
orderName: "ํ
์คํธ ์ด๋ฆ", // ์ฃผ๋ฌธ๋ช
(๊ฐ๋ฐ์์ฝ๋ฉ) ํ์
successUrl: `${window.location.origin}/success`, // ์ฑ๊ณต url, ํ์
failUrl: `${window.location.origin}/fail`, // ์คํจ url, ํ์
};
console.log(data);
// ------ '๊ฒฐ์ ํ๊ธฐ' ๋ฒํผ ๋๋ฅด๋ฉด ๊ฒฐ์ ์ฐฝ ๋์ฐ๊ธฐ ------
// ๊ฒฐ์ ๋ฅผ ์์ฒญํ๊ธฐ ์ ์ orderId, amount๋ฅผ ์๋ฒ์ ์ ์ฅํ์ธ์.
// ๊ฒฐ์ ๊ณผ์ ์์ ์
์์ ์ผ๋ก ๊ฒฐ์ ๊ธ์ก์ด ๋ฐ๋๋ ๊ฒ์ ํ์ธํ๋ ์ฉ๋์
๋๋ค.
// @docs https://docs.tosspayments.com/reference/widget-sdk#requestpayment๊ฒฐ์ -์ ๋ณด
await this.paymentWidget.requestPayment(data);
}
} catch (error) {
// ์๋ฌ ์ฒ๋ฆฌํ๊ธฐ
console.error(error);
}
},
},
async mounted() {
// TODO: ํ ์ค API ------ ๊ฒฐ์ ์์ ฏ ์ด๊ธฐํ ------
// @docs https://docs.tosspayments.com/reference/widget-sdk#sdk-์ค์น-๋ฐ-์ด๊ธฐํ
this.paymentWidget = await loadPaymentWidget(this.clientKey, ANONYMOUS);
// TODO: ํ ์ค API ------ ๊ฒฐ์ UI ๋ ๋๋ง ------
// @docs https://docs.tosspayments.com/reference/widget-sdk#renderpaymentmethods์ ํ์-๊ฒฐ์ -๊ธ์ก-์ต์
this.paymentMethodWidget = this.paymentWidget.renderPaymentMethods(
"#payment-method",
{ value: 13000 }, // ๊ฒฐ์ฌ๊ธ์ก(๊ฐ๋ฐ์์ฝ๋ฉ)
{ variantKey: "DEFAULT" }
);
// TODO: ํ ์ค API ------ ์ด์ฉ์ฝ๊ด UI ๋ ๋๋ง ------
// @docs https://docs.tosspayments.com/reference/widget-sdk#renderagreement์ ํ์-์ต์
this.paymentWidget.renderAgreement("#agreement", {
variantKey: "AGREEMENT",
});
// TODO: ํ ์ค API
this.paymentMethodWidget.on("ready", () => {
this.inputEnabled = true;
});
},
};
</script>
<style>
@import "@/assets/css/style.css";
</style>
- ํ ์ค API ์ฌ์ดํธ์์ ์ ๊ณตํ๋ ์์ค
- ๊ฐ๋ฐ์์ฝ๋ฉ : ์ด ๋ถ๋ถ์ด ์ง์ ๊ฐ๋ฐ์๊ฐ ์์ฑํด์ ์์ฉํ๋ ๋ถ๋ถ์
- ์์์๋ ์ฃผ๋ฌธ๋ฒํธ, ์ฃผ๋ฌธ๋ช ์ ์ง์ ๊ฐ๋ฐ์๊ฐ ์ฝ๋ฉํ์
ํ ์ค ๊ฒฐ์ฌ ํ๋ฉด #4

– views/toss/SuccessView.vue : ํ ์ค API ์ฌ์ดํธ์์ ์ ๊ณต
<template>
<section v-if="confirmed">
<div class="box_section" style="width: 600px">
<img
style="width: 100px"
src="https://static.toss.im/illusts/check-blue-spot-ending-frame.png"
/>
<h2>๊ฒฐ์ ๋ฅผ ์๋ฃํ์ด์</h2>
<div class="p-grid typography--p" style="margin-top: 50px">
<div class="p-grid-col text--left"><b>๊ฒฐ์ ๊ธ์ก</b></div>
<div class="p-grid-col text--right" id="amount">
{{ jsonData.totalAmount }}์
</div>
</div>
<div class="p-grid typography--p" style="margin-top: 10px">
<div class="p-grid-col text--left"><b>์ฃผ๋ฌธ๋ฒํธ</b></div>
<div class="p-grid-col text--right" id="orderId">
{{ jsonData.orderId }}
</div>
</div>
</div>
</section>
</template>
<script>
import { confirmPayment } from "@/utils/confirmPayment";
import SimpleApprovalService from '@/services/shop/SimpleApprovalService';
export default {
data() {
return {
requestData: {
orderId: this.$route.query.orderId,
amount: this.$route.query.amount,
paymentKey: this.$route.query.paymentKey,
},
confirmed: false,
jsonData: null,
};
},
methods: {
// TODO: ํ ์ค ๊ฒฐ์ฌ ํจ์
async confirm() {
try {
const { response, json } = await confirmPayment(this.requestData);
console.log(json);
if (!response.ok) {
this.$router.push(`/fail?message=${json.message}&code=${json.code}`);
} else {
this.confirmed = true;
this.jsonData = json;
// ๊ฒฐ์ฌ ์ ์ฅ ํจ์ ์คํ(๊ฐ๋ฐ์์ฝ๋ฉ)
this.confirmApproval()
}
} catch (e) {
console.log(e);
}
},
// ๊ฒฐ์ฌ ์ ์ฅ ํจ์ ์ ์(๊ฐ๋ฐ์์ฝ๋ฉ)
async confirmApproval() {
let now = new Date();
let yearMonthDay = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()}`;
let hourMinuteSecond = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
let dateFormat = `${yearMonthDay} ${hourMinuteSecond}`;
try {
let approval = {
sono: this.$route.query.orderId, // ์ฃผ๋ฌธ๋ฒํธ
approvalDate: dateFormat, // ๊ฒฐ์ฌ์ผ
approvalAmount: this.$route.query.amount, // ์ฃผ๋ฌธ๊ธ์ก
};
let response = await SimpleApprovalService.create(approval);
this.simpleApproval = response.data;
console.log(response.data);
} catch (e) {
console.log(e);
}
},
},
mounted() {
this.confirm();
},
};
</script>
<style>
@import "@/assets/css/style.css";
</style>
- ๊ฐ๋ฐ์ ์ฝ๋ฉ : ์ด ๋ถ๋ถ์ด ์ง์ ๊ฐ๋ฐ์๊ฐ ์์ฑํด์ ์์ฉํ๋ ๋ถ๋ถ์
- ์์์๋ ๊ฒฐ์ฌ ์ ์ฅ ํจ์ ์ ์ํ๊ณ (confirmApproval()), ๊ฒฐ์ฌ ์ ์ฅ ํจ์๋ฅผ ์คํํ์
๐ ๊ฒฐ๋ก
ํ ์ค ๊ฒฐ์ฌ API ๋ฅผ ์ด์ฉํด์ Vue & Spring boot ๋ก ์ฐ๋ํ๋ ์์ ๋ฅผ ์ดํด๋ณด์์ต๋๋ค.
ํ ์ค ๊ฒฐ์ฌ ํ์ด์ง๊ฐ ๋ก๋ฉ๋ ๋ ์ฃผ๋ฌธ๋ฒํธ๋ฅผ ์น๋ธ๋ผ์ฐ์ ์ฃผ์์ฐฝ์ผ๋ก ์ ๋ฌํ์ผ๋ฉฐ,
ํ ์ค ๊ฒฐ์ฌ๊ฐ ์๋ฃ๋๋ฉด ๊ฒฐ์ฌ ํ
์ด๋ธ์ Create ํ๋ ๊ธฐ๋ฅ๋ ๊ตฌํํ์ต๋๋ค..
Spring Boot ๋ @RestController ์ด๋
ธํ
์ด์
์ ์ด์ฉํด ๊ตฌํํ์ผ๋ฉฐ, ๊ฒฐ๊ณผ๋ JSON ๋ฐ์ดํฐ๋ก ๋ฆฌํด๋ฉ๋๋ค.
Vue ๋ axios ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ๋ฒก์๋์ ํต์ ํฉ๋๋ค.
DB ํ๋ ์์ํฌ๋ JPA ๋ฅผ ์ด์ฉํด์ sql ๋ฌธ์ ์ง์ ์ ์ํ์ง ์๊ณ ์๋ํ๊ธฐ๋ฅ์ ์ด์ฉํด ๊ตฌํํ์ต๋๋ค.
Mybatis ์ ์ง์ sql ๋ฌธ ์ ์ ๊ธฐ๋ฅ์ ๋์ํด ์์ฃผ ๋ฐ๋ณต๋๊ณ ์ฌ์ด ๊ธฐ๋ฅ์ JPA ์ sql ์๋์์ฑ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ณ ,
๋ณต์กํ sql ๋ฌธ์ @Query ๋ฅผ ์ด์ฉํด ์ง์ ์์ฑํ ์ ์์ด ์์ฆ ์๋น์ค ์
์ฒด ๊ธฐ์ค์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
๊ฒฐ์ฌ API ์ ๊ด์ฌ ์์ผ์๋ค๋ฉด Source ๋ ์๋์์ ์ฐพ์ ์ ์์ต๋๋ค.
- Github ์ฃผ์ : https://github.com/KangTaeGyung/simple-toss-api
๊ฐ์ฌํฉ๋๋ค.



