
기존에는 웹 개발을 PHP의 프레임워크인 Laravel을 사용하여 개발하고 있었습니다. 하지만, '멋쟁이사자처럼 대학 11기' 동아리에 참여하면서 Spring Boot를 처음 접하게 되었는데, '나는 백엔드를 개발하고 API를 만들면, 대체 프론트엔드에서는 이걸 어떻게 활용하고, 같이 작업하는 걸까?' 라는 의문이 생겼습니다. 그래서 찾아본 결과, Spring Boot와 React를 연결할 수 있었고, 이를 이용해서 API를 요청, 반환하여 데이터를 주고 받는 방법을 사용하고 있다는 것에 대해 알게되었습니다.
- Java 11
- macOS Monterey 12.6
- Spring Boot 2.5.6
터미널을 켜고, 'src/main' 폴더 아래에 'frontend' React 프로젝트를 설치해 줍니다.
cd src/main
npx create-react-app frontend

설치가 완료되었다면, 위와 같은 구조로 React 프로젝트 파일이 설치됩니다. 이 과정까지는 대략 2분정도 소요되었습니다.
이제 React 프로젝트의 설정을 마쳤으니 실행해 볼까요? 'src/main/frontend' 폴더에서 리엑트 프로젝트를 실행해 주겠습니다.
cd src/main/frontend
npm start
위 명령어를 실행하면, 리엑트 프로젝트가 실행되는 과정이 보이면서, "http://localhost:3000" 웹 페이지가 자동으로 열립니다.

위 페이지가 보인다면, 성공입니다! 물론, 설치한 리엑트 버전에 따라 초기 페이지는 다를 수 있지만 페이지가 표시된다면, 리엑트 프로젝트가 잘 설치된 것입니다.
그럼 여기서 이상한(?) 점이 보이시나요? React의 웹 페이지 접근 포트는 3000으로 되어 있어요. 하지만, Spring Boot의 접근 포트는 8080입니다. 이와 같이 만약, Spring Boot와 React가 같은 포트로 동작하지 않는다면, CORS 오류가 발생합니다. CORS 오류란, Cross Origin Resource Sharing, 다른 출처 리소스 공유 정책입니다. 간단히 말해서, 같은 도메인 및 서버에서 동작하고 있다면 서로 리소스를 공유하고 있지만, 다른 도메인에서 동작하고 있다면 서로 리소스를 공유할 수 없는 것입니다. 그렇기 때문에 Spring Boot와 React가 같은 포트에서 동작할 수 있도록, Proxy 설정을 해야합니다.
Proxy 설정에 사용되는 방법은 React 공식 문서에 나와 있는 방법입니다. 문서는 https://create-react-app.dev/docs/proxying-api-requests-in-development/ 에서 확인할 수 있습니다.
'src/main/frontend/package.json' 파일에 아래의 코드를 추가해 주세요.
...
"proxy": "http://localhost:8080",
...
Spring Boot의 포트인 8080으로 프록시 설정을 완료했습니다.
프록시 설정을 완료했으니, 테스트도 한 번 해보아야겠죠? 'src/main/java/com.springboot.test/controller/'에 'TestController'을 생성해 주겠습니다. 그 후, "Test" 문자를 반환하는 초간단한 API를 하나 만들어 주겠습니다.
@RestController
public class TestController {
@GetMapping("/api/test")
public String test() {
return "Test";
}
}

Spring Boot 프로젝트를 실행하고, http://localhost:8080/api/test에 접속하면, 위와 같이 정상적으로 작동하는 것을 볼 수 있습니다.
이제 리엑트에서도 이 API 사용이 가능해야 하기 때문에, 'src/main/frontend/src/App.js'에 아래 코드를 추가하여 실행해 보겠습니다.
import logo from './logo.svg';
import './App.css';
import {useEffect, useState} from "react";
function App() {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/api/test');
const result = await response.text();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{data ? (
<p>
{data}
</p>
) : (
<p>Loading data...</p>
)}
</header>
</div>
);
}
export default App;
위 코드를 붙여넣고, 'src/main/frontend'에서 npm start 명령어를 사용하여 React 프로젝트의 서버도 실행시킵니다.
이 때 주의해야 할 점은, Spring Boot의 프로젝트도 동작하는 상태이고, React 프로젝트도 동작하는 상태여야 정상적으로 실행됩니다.

http://localhost:3000 페이지에 접속해 보면, 위와 같이 'Learn React' 아래에 테스트로 만들었던 API의 반환 값인 'Test'를 확인할 수 있고, 이를 통해 Spring Boot와 React 간 Proxy 설정이 완료되었음을 확인할 수 있습니다.
동아리 때문에 React와 Spring Boot를 연결하는 방법에 대해 알아본 것도 맞지만, 개인적으로 토이 프로젝트를 만들 때 Thymeleaf를 사용하고 있었는데, 데이터를 주고 받기 복잡할 뿐더러 개발 시간도 더 많이 걸리는 것 같은 느낌이 들어 React를 사용하여 프론트엔드와 백엔드를 확실하게 구분하는 것이 좋다고 생각하여 꼭 한 번 정리하고 넘어가고 싶었습니다.
React도 한 번 제대로 학습하고, 사용해서 프론트엔드, 백엔드 모든 파트를 대상으로 토이 프로젝트를 만들어보고 싶습니다.