๐Ÿ’ป ์ฝ”๋”ฉ ์ผ๊ธฐ : [React, Spring] 'Axios๋ฅผ ํ™œ์šฉํ•œ React์™€ Spring Boot์˜ ํ†ต์‹ ' ํŽธ

ybkยท2024๋…„ 5์›” 16์ผ

spring

๋ชฉ๋ก ๋ณด๊ธฐ
33/55
post-thumbnail

๐Ÿ””'Axios๋ฅผ ํ™œ์šฉํ•œ React์™€ Spring Boot์˜ ํ†ต์‹ '์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž!


๐Ÿ’Ÿ Axios

HTTP ์š”์ฒญ์„ ๋งŒ๋“ค๊ณ  ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, Axios๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด HTTP GET, POST, PUT, DELETE ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์š”์ฒญ ํ—ค๋”๋‚˜ ์š”์ฒญ ๋ณธ๋ฌธ์„ ์„ค์ •ํ•˜๊ณ  ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. axios ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์š”์ฒญ์„ ์ฃผ๊ณ  ๋ฐ›๊ธฐ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


get ์š”์ฒญ(axios.get("๊ฒฝ๋กœ"))

import React from "react";
import axios from "axios";

function App(props) {
  function handleClick1() {
    axios.get("/path1");
  }

  function handleClick2() {
    const qs = new URLSearchParams();
    qs.append("city", "๋ฏธ๊ตญ");
    qs.append("address", "๋‰ด์š•");
    axios.get("/path2?" + qs.toString());
  }

  function handleClick3() {
    const qs = new URLSearchParams();
    qs.append("name", "kim");
    qs.append("age", 24);
    axios.get(`/path3?${qs.toString()}`);
  }

  return (
    <div>
      <div>
        <button onClick={handleClick1}>/path1 get ์š”์ฒญ</button>
      </div>
      <div>
        <button onClick={handleClick2}>/path2 get ์š”์ฒญ</button>
      </div>
      <div>
        <button onClick={handleClick3}>/path3 get ์š”์ฒญ</button>
      </div>
    </div>
  );
}

export default App;
  • handleClick1() : '/path1'๋กœ GET ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  • handleClick2() : '/path2'๋กœ GET ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. URLSearchParams๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๋ฅผ ๊ฒฝ๋กœ์— ๋ถ™์—ฌ์„œ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. /path2?city=๋ฏธ๊ตญ&address=๋‰ด์š•
  • handleClick3() : '/path3'๋กœ GET ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. URLSearchParams๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๋ฅผ ๊ฒฝ๋กœ์— ๋ถ™์—ฌ์„œ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. /path3?name=kim&age=24


๐Ÿ’Ÿ React์—์„œ GET,POST ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  Spring Boot ์„œ๋ฒ„์—์„œ ์š”์ฒญ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ˆ์ œ

๋จผ์ € React์™€ Spring Boot์™€ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ์„ค์ •์„ ํ•ด์ค๋‹ˆ๋‹ค.

Vite ์„ค์ • ํŒŒ์ผ (vite.config.js)

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:8080",
      },
    },
  },
});
  • api๋กœ ์‹œ์ž‘ํ•˜๋Š” ์š”์ฒญ์„ "http://localhost:8080 (Spring Boot ํฌํŠธ๋ฒˆํ˜ธ)"์œผ๋กœ ๋ณด๋‚ด๋Š” ํ”„๋ก์‹œํ•˜๋„๋ก ์„ค์ •์„ ํ•ฉ๋‹ˆ๋‹ค.
    ํ”„๋ก์‹œ : ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์—์„œ ์ค‘๊ณ„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

React(App.jsx)

import React from "react";
import axios from "axios";

function App(props) {
  function handleClickButton1() {
    //   ajax get ์š”์ฒญ
    axios.get("/api/someurl");
  }

  function handleClickButton2() {
    axios.post("/api/someurl");
  }

  return (
    <div>
      <button onClick={handleClickButton1}>get ์š”์ฒญ</button>
      <button onClick={handleClickButton2}>post ์š”์ฒญ</button>
    </div>
  );
}

export default App;
  • get ์š”์ฒญ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, handleClickButton1 ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ  /api/someurl ๊ฒฝ๋กœ๋กœ get ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  • post ์š”์ฒญ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, handleClickButton2 ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ  /api/someurl ๊ฒฝ๋กœ๋กœ post ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

Spring Boot(Controller40.java)

@Controller
public class Controller40 {

    @GetMapping("/api/someurl")
    public void method1(){
        System.out.println("Controller40.method1");
    }

    @PostMapping("/api/someurl")
    public void method2(){
        System.out.println("Controller40.method2");
    }
}
  • react์—์„œ /api/someurl ๊ฒฝ๋กœ๋กœ get ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด @GetMapping์œผ๋กœ ์ง€์ •๋œ ๋ฉ”์†Œ๋“œ(method1)๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ Controller40.method1์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  • react์—์„œ /api/someurl ๊ฒฝ๋กœ๋กœ post ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด @PostMapping์œผ๋กœ ์ง€์ •๋œ ๋ฉ”์†Œ๋“œ(method2)๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ Controller40.method2๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ’Ÿ URLSearchParams๋ฅผ ํ™œ์šฉํ•œ GET, POST ์š”์ฒญ ์ฒ˜๋ฆฌ ์˜ˆ์ œ**


React(App.jsx)

import React from "react";
import axios from "axios";

function App(props) {

  function handleClickButton5() {
    const params = new URLSearchParams();
    params.append("id", 3);
    params.append("name", "son");
    params.append("email", "son@gmail.com");
    // axios.get("/api/someurl3?"+params);
    axios.get(`/api/someurl3?${params}`);
  }

  function handleClickButton6() {
    const params = new URLSearchParams();
    params.append("foods", "pizza");
    params.append("foods", "coffee");
    params.append("city", "busan");
    axios.post("/api/someurl3", params);
  }

  return (
    <div>
      <button onClick={handleClickButton5}>get ์š”์ฒญ with query string</button>
      <button onClick={handleClickButton6}>post ์š”์ฒญ with data</button>
    </div>
  );
}

export default App;
  • handleClickButton5() : GET ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ์ƒ์„ฑํ•˜์—ฌ axios.get()์„ ํ†ตํ•ด /api/someurl3 ๊ฒฝ๋กœ์— ํ•ด๋‹น ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ํฌํ•จํ•˜์—ฌ GET ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  • handleClickButton6() : axios.post()์„ ํ†ตํ•ด /api/someurl3 ๊ฒฝ๋กœ๋กœ POST ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์š”์ฒญ ๋ณธ๋ฌธ์— ๋ฐ์ดํ„ฐ(foods[], city)๋ฅผ ๋‹ด์•„์„œ ์ถ”๊ฐ€ํ•œ ํ›„์— POST ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

Spring Boot(Controller40.java)

@GetMapping("/api/someurl3")
public void method5(@RequestParam("id") Integer id,
                    @RequestParam("name") String name,
                    @RequestParam("email") String email){
    System.out.println("id = " + id + ", name = " + name + ", email = " + email);
}

@PostMapping("/api/someurl3")
public void method6(String[] foods, String city){
    System.out.println("foods = " + Arrays.toString(foods) + ", city = " + city);
}
  • GET ๋ฐฉ์‹์€ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ URL์— ํฌํ•จ์‹œ์ผœ ์ „๋‹ฌํ•˜๋ฉฐ, POST ๋ฐฉ์‹์€ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ๋ณ„๋„์˜ ๋ชธํ†ต(body)์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  • @RequestParam์˜ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋™์ผํ•˜๋ฉด @RequestParam ์ƒ๋žต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’Ÿ React์™€ Spring Boot ์‹ค์Šต ์˜ˆ์ œ

React์—์„œ Spring Boot ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณผ์ •์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.


React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (App.js)

import React, { useState } from "react";
import axios from "axios";

function App(props) {
  const [customerId, setCustomerId] = useState("");
  const [customerName, setCustomerName] = useState("");

  function handleSearchClick() {
    // ์กฐํšŒ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ /api/customer?id=#๋กœ ์š”์ฒญ
    axios
      .get(`/api/customer?id=${customerId}`)
      .then((response) => response.data)
      .then((data) => setCustomerName(data));
  }

  return (
    <div>
      <div>
        <input type="number" onChange={(e) => setCustomerId(e.target.value)} />
      </div>
      <button onClick={handleSearchClick}>์กฐํšŒ</button>
      <div>์ด๋ฆ„ : {customerName}</div>
    </div>
  );
}

export default App;
  • input ์š”์†Œ์— ID๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์กฐํšŒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ID์˜ ๊ณ ๊ฐ ์ด๋ฆ„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

Controller39.java

@Controller
@RequiredArgsConstructor
public class Controller39 {

    private final Service05 service;

    // /api/customer?id=#
    @GetMapping("/api/customer")
    @ResponseBody
    public String customerName(Integer id) {
        return service.getCustomerName(id);
    }
}
  • /api/customer ๊ฒฝ๋กœ๋กœ GET ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์š”์ฒญ๋œ ๊ณ ๊ฐ ID๋ฅผ ์„œ๋น„์Šค์— ์ „๋‹ฌํ•˜์—ฌ ๊ณ ๊ฐ์˜ ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

Service05.java

@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class Service05 {
    private final Mapper09 mapper;

    public String getCustomerName(Integer id) {
        return mapper.selectNameById(id);
    }
}
  • ๊ณ ๊ฐ ID๋ฅผ ๋ฐ›์•„์„œ mapper๋ฅผ ํ†ตํ•ด ๊ณ ๊ฐ์˜ ์ด๋ฆ„์„ ์กฐํšŒํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Mapper09.java

@Mapper
public interface Mapper09 {

    @Select("""
            SELECT CustomerName
            FROM Customers
            WHERE CustomerId = #{id}
            """)
    String selectNameById(Integer id);
}
  • ๊ณ ๊ฐ ID๋ฅผ ๋ฐ›์•„ DB์—์„œ ๊ณ ๊ฐ์˜ ์ด๋ฆ„์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
profile
๊ฐœ๋ฐœ์ž ์ค€๋น„์ƒ~

0๊ฐœ์˜ ๋Œ“๊ธ€