반응형
Axios를 이용한 Spring Boot와 React 연동 가이드
1. Axios란?
Axios는 브라우저와 Node.js 환경 모두에서 사용할 수 있는 Promise 기반의 HTTP 클라이언트 라이브러리입니다. 비동기적으로 HTTP 통신을 쉽게 할 수 있도록 도와주며, 대표적인 경쟁 기술로는 JavaScript에 내장된 fetch() API와 jQuery의 ajax()가 있습니다.
Axios의 주요 특징
- 자동 JSON 데이터 변환: 요청 시 JavaScript 객체를 자동으로 JSON으로 변환하고, 응답 시 JSON 데이터를 자동으로 JavaScript 객체로 변환해 줍니다.
fetch()는 이 과정을 수동(JSON.stringify(),res.json())으로 처리해야 합니다. - Promise 기반:
async/await문법과 함께 사용하여 코드를 더 간결하고 가독성 있게 작성할 수 있습니다. - 브라우저 호환성: 구형 브라우저를 포함한 대부분의 브라우저를 지원합니다.
- 에러 처리:
catch를 통해 네트워크 오류나 잘못된 응답(4xx, 5xx)을 쉽게 처리할 수 있습니다. - 요청/응답 인터셉터: 요청을 보내기 전이나 응답을 받기 후에 공통 로직(예: 토큰 추가, 에러 로깅)을 삽입할 수 있습니다.
2. 설치 방법
React (npm/yarn)
React 프로젝트에서는 npm 또는 yarn을 통해 간단하게 설치할 수 있습니다.
# npm 사용 시
npm install axios
# yarn 사용 시
yarn add axios
JavaScript (CDN)
HTML 파일에서 직접 사용하려면 <script> 태그를 통해 CDN을 추가합니다.
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
3. 기본 문법
Axios는 HTTP 요청 메서드에 해당하는 다양한 함수를 제공합니다.
axios.METHOD(url, [data], [config])
METHOD:get,post,put,delete등 HTTP 메서드.url: 요청을 보낼 서버의 주소 (API Endpoint).data(선택 사항): 요청 본문(body)에 담아 보낼 데이터. 주로post,put요청에서 사용됩니다.config(선택 사항): 요청 헤더(headers) 등 추가적인 설정을 위한 객체.headers:{ 'Content-Type': 'application/json' }(기본값) 또는{ 'Content-Type': 'multipart/form-data' }(파일 업로드 시).
메서드별 사용 예시
// GET: 데이터 조회
axios.get('/api/data');
// POST: 데이터 생성 (body에 데이터 포함)
axios.post('/api/data', { name: '새 항목', value: 10 });
// PUT: 데이터 수정
axios.put('/api/data/1', { name: '수정된 항목', value: 20 });
// DELETE: 데이터 삭제
axios.delete('/api/data/1');
4. 비동기 처리 방식
1. .then() / .catch() (Promise 체이닝)
요청 성공 시 .then() 블록이, 실패 시 .catch() 블록이 실행됩니다.
const fetchData = () => {
axios.get('https://api.example.com/data')
.then(response => {
// 성공 시 response.data에 서버 응답이 담겨 있음
console.log('데이터:', response.data);
})
.catch(error => {
// 실패 시
console.error('에러 발생:', error);
});
};
2. async / await (동기적 스타일)
async 함수 내에서 await 키워드를 사용하면, 비동기 코드를 동기 코드처럼 작성할 수 있어 가독성이 향상됩니다. 에러 처리는 try...catch 문을 사용합니다.
const fetchData = async () => {
try {
const response = await axios.get('https://api.example.com/data');
// 성공 시
console.log('데이터:', response.data);
} catch (error) {
// 실패 시
console.error('에러 발생:', error);
}
};
5. Spring Boot와 React 연동 예제 (Spring → React)
시나리오
- Backend (Spring Boot): 간단한 게시물 목록을 제공하고, 새 게시물을 등록하는 API를 만듭니다.
- Frontend (React): Spring Boot API를 호출하여 게시물 목록을 화면에 표시하고, 폼을 통해 새 게시물을 등록합니다.
Backend: Spring Boot 설정 (localhost:8080)
1. DTO (Data Transfer Object) 생성
PostDto.java: 클라이언트와 주고받을 데이터 구조를 정의합니다.
// PostDto.java
package com.example.demo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class PostDto {
private long id;
private String title;
private String content;
}
2. Controller 생성 (@RestController)
PostApiController.java: API 엔드포인트를 정의합니다.
@CrossOrigin("http://localhost:3000"): React 개발 서버(localhost:3000)로부터의 요청을 허용하기 위한 CORS 설정입니다. (React 기본 포트는 3000, Vite는 5173일 수 있습니다.)@GetMapping: 게시물 목록을 조회하는 API.@PostMapping: 새 게시물을 등록하는 API.@RequestBody는 React가 보낸 JSON 데이터를PostDto객체로 변환해 줍니다.
// PostApiController.java
package com.example.demo;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@RestController
@RequestMapping("/api/posts")
@CrossOrigin("http://localhost:3000") // React 앱의 주소를 허용
public class PostApiController {
private final List<PostDto> posts = new ArrayList<>();
private final AtomicLong counter = new AtomicLong();
// 초기 데이터
public PostApiController() {
posts.add(new PostDto(counter.incrementAndGet(), "첫 번째 게시물", "안녕하세요!"));
posts.add(new PostDto(counter.incrementAndGet(), "두 번째 게시물", "Axios 연동 예제입니다."));
}
// GET: 모든 게시물 조회
@GetMapping
public List<PostDto> getAllPosts() {
System.out.println("GET /api/posts 요청 받음");
return posts;
}
// POST: 새 게시물 등록
@PostMapping
public PostDto createPost(@RequestBody PostDto newPost) {
System.out.println("POST /api/posts 요청 받음: " + newPost.getTitle());
PostDto post = new PostDto(
counter.incrementAndGet(),
newPost.getTitle(),
newPost.getContent()
);
posts.add(post);
return post; // 생성된 게시물 정보 반환
}
}
Frontend: React 설정 (localhost:3000)
1. Axios 설치 (이미 완료했다고 가정)
2. React 컴포넌트 작성 (PostComponent.js)
useEffect를 사용하여 컴포넌트가 처음 렌더링될 때 Spring 서버로부터 게시물 목록을 가져옵니다 (axios.get).useState를 사용하여 게시물 목록(posts), 새 게시물 제목(newTitle), 내용(newContent)을 상태로 관리합니다.handleSubmit함수에서axios.post를 호출하여 사용자가 입력한 데이터를 Spring 서버로 전송합니다.
// PostComponent.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function PostComponent() {
const [posts, setPosts] = useState([]);
const [newTitle, setNewTitle] = useState('');
const [newContent, setNewContent] = useState('');
// 1. 컴포넌트 마운트 시 데이터 가져오기 (GET 요청)
useEffect(() => {
const fetchPosts = async () => {
try {
// Spring Boot API에 GET 요청 (전체 주소 사용)
const response = await axios.get('http://localhost:8080/api/posts');
setPosts(response.data); // 응답 데이터를 상태에 저장
} catch (error) {
console.error('게시물 데이터를 가져오는 데 실패했습니다.', error);
}
};
fetchPosts();
}, []); // 빈 배열을 전달하여 한 번만 실행되도록 설정
// 2. 폼 제출 시 데이터 보내기 (POST 요청)
const handleSubmit = async (e) => {
e.preventDefault(); // 폼 기본 동작(새로고침) 방지
const newPost = { title: newTitle, content: newContent };
try {
// Spring Boot API에 POST 요청
const response = await axios.post('http://localhost:8080/api/posts', newPost);
// 응답으로 받은 새 게시물을 기존 목록에 추가
setPosts([...posts, response.data]);
// 입력 필드 초기화
setNewTitle('');
setNewContent('');
} catch (error) {
console.error('게시물을 등록하는 데 실패했습니다.', error);
}
};
return (
<div>
<h1>게시물 목록</h1>
<ul>
{posts.map(post => (
<li key={post.id}>
<strong>{post.title}</strong>: {post.content}
</li>
))}
</ul>
<hr />
<h2>새 게시물 작성</h2>
<form onSubmit={handleSubmit}>
<div>
<label>제목: </label>
<input
type="text"
value={newTitle}
onChange={(e) => setNewTitle(e.target.value)}
/>
</div>
<div>
<label>내용: </label>
<input
type="text"
value={newContent}
onChange={(e) => setNewContent(e.target.value)}
/>
</div>
<button type="submit">등록</button>
</form>
</div>
);
}
export default PostComponent;
6. CORS (Cross-Origin Resource Sharing) 문제 해결
문제점
보안상의 이유로 브라우저는 다른 출처(Origin)의 리소스를 요청하는 것을 기본적으로 차단합니다. 여기서 출처는 프로토콜, 호스트(도메인), 포트 번호를 모두 포함합니다.
- React 앱:
http://localhost:3000 - Spring Boot 앱:
http://localhost:8080
위 두 주소는 포트 번호가 다르므로 다른 출처로 간주되어 CORS 정책 위반 오류가 발생합니다.
해결 방안 (Spring Boot)
Spring Boot에서 특정 출처의 요청을 허용하도록 설정하면 간단히 해결할 수 있습니다.
- Controller 레벨 설정: 특정 컨트롤러의 모든 메서드에 CORS를 적용합니다.
@CrossOrigin("http://localhost:3000") @RestController public class MyController { ... } - 메서드 레벨 설정: 특정 메서드에만 적용합니다.
@CrossOrigin("http://localhost:3000") @GetMapping("/api/data") public String getData() { ... } - 전역 설정: 애플리케이션 전체에 동일한 CORS 정책을 적용합니다.
// WebConfig.java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 모든 경로에 대해 .allowedOrigins("http://localhost:3000") // 허용할 출처 .allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드 .allowCredentials(true); // 쿠키 등 자격 증명 허용 } }
7. 요약: Spring → React 데이터 흐름
- [React] 사용자가 페이지에 접속하면
PostComponent가 렌더링됩니다. - [React]
useEffect훅이 실행되어axios.get('http://localhost:8080/api/posts')요청을 보냅니다. - [Spring]
PostApiController의@GetMapping메서드가 요청을 수신합니다. - [Spring] 컨트롤러는 서비스나 리포지토리를 통해 데이터를 조회한 후
List<PostDto>객체를 반환합니다. - [Spring] Spring의
Jackson라이브러리가List<PostDto>자바 객체를 JSON 문자열로 직렬화(Serialize)합니다. - [Spring] 직렬화된 JSON 데이터를 HTTP 응답 본문에 담아 React로 보냅니다.
- [React] Axios가 응답을 받으면, JSON 문자열을 자동으로 JavaScript 객체로 파싱(Parse)하여
response.data에 담아줍니다. - [React]
setPosts(response.data)가 호출되어 컴포넌트의posts상태가 업데이트됩니다. - [React] 상태가 변경되었으므로 컴포넌트가 리렌더링되어 화면에 게시물 목록이 표시됩니다.
반응형
'프론트엔드 > 리액트' 카테고리의 다른 글
| [React] 키오스크 미니 프로젝트 피드백 (0) | 2025.09.24 |
|---|---|
| [React] 12장: 최종 프로젝트 - 미니 블로그 만들기 (0) | 2025.09.16 |
| [React] 11장: 전역 상태 관리 (Zustand) - 컴포넌트의 벽 허물기 (0) | 2025.09.16 |
| [React] 10장: React Router - 페이지 이동과 목차 만들기 (0) | 2025.09.16 |
| [React] 9장: 스타일링 - 컴포넌트에 옷 입히기 (0) | 2025.09.16 |
| [React] 8장: Hooks 심화 - React 능력 끌어올리기 (0) | 2025.09.16 |
| [React] 7장: 폼 다루기 - 사용자의 입력 받기 (0) | 2025.09.16 |
| [React] 6장: 리스트와 Key - 동적인 목록 만들기 (0) | 2025.09.16 |