๐ ์์ฝ
ํ ์ค ๊ฒฐ์ฌ 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
๊ฐ์ฌํฉ๋๋ค.