현재는 먼저 화면을 잡고 백엔드를 잡고 싶어서, next로 구조를 잡다보니, route.ts로 api호출의 역할을 대신하고 있다.
앞선 글에서도 큰 흐름은 그렇게 정리하다보니 정작 중요한 얘기를 못했다.
Q. Next.js에 Spring을 붙이면 데이터 흐름은 어떻게 바뀔까
앞선 흐름에서는 Next.js 프로젝트 안에서 화면을 만들고, 필요한 데이터도 Next 내부의 API Route에서 mock 데이터로 응답하는 구조를 살펴봤다.
이번에는 여기에 Spring 백엔드를 붙이면 어떤 부분이 바뀌는지 정리해보려 한다.
결론부터 말하면, Spring을 붙인다고 해서 React 컴포넌트의 흐름이 전부 바뀌는 것은 아니다. 핵심적으로 바뀌는 부분은 route.ts가 하던 서버 역할을 Spring 서버가 가져간다는 점이다.
1. 현재 구조는 Next 내부 API를 사용한다
현재 프로젝트의 데이터 흐름은 다음과 같다.
MainPageClient
-> useCareerList
-> fetchCareerList
-> fetch("/api/careers/list")
-> Next route.ts
-> createCareerListMock()
-> JSON 응답
여기서 MainPageClient는 화면을 구성하는 클라이언트 컴포넌트다.
useCareerList는 데이터 상태를 관리하는 hook이다.
fetchCareerList는 실제 API 요청을 보내는 함수다.
route.ts는 Next.js 내부에서 API 요청을 받아 응답을 만들어주는 파일이다.
현재는 Spring 서버가 없기 때문에 route.ts가 임시 백엔드 역할을 한다.
즉, 실제 DB에서 데이터를 가져오는 것이 아니라 createCareerListMock() 같은 mock 데이터를 만들어 JSON으로 응답한다.
현재 구조를 더 단순하게 보면 다음과 같다.
브라우저
-> Next 프론트엔드
-> Next route.ts mock API
즉, 프론트엔드와 임시 API 서버가 모두 Next.js 프로젝트 안에 있는 상태다.
2. Spring을 붙이면 route.ts 역할이 Spring으로 이동한다
Spring을 붙이면 가장 크게 바뀌는 부분은 API 요청의 도착지다.
현재는 클라이언트에서 다음과 같이 요청을 보낸다.
const res = await fetch("/api/careers/list", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
})
이 요청은 Next.js 내부의 다음 파일로 연결된다.
app/api/careers/list/route.ts
하지만 Spring 서버를 붙이면 이 요청은 Next의 route.ts로 가지 않고 Spring 서버의 Controller로 가게 된다.
예를 들어 Spring 서버가 localhost:8080에서 실행 중이라면 요청 코드는 다음과 같이 바뀔 수 있다.
const res = await fetch("http://localhost:8080/api/careers/list", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
})
바뀐 것은 전체 구조가 아니라 API 요청 주소다.
fetch("/api/careers/list")
이 요청이 Next 내부 API를 바라보느냐,
fetch("http://localhost:8080/api/careers/list")
Spring 서버 API를 바라보느냐의 차이다.
3. Spring을 붙인 뒤의 전체 흐름
Spring을 붙이면 흐름은 다음과 같이 바뀐다.
MainPageClient
-> useCareerList
-> fetchCareerList
-> fetch("http://localhost:8080/api/careers/list")
-> Spring Controller
-> Service
-> Repository
-> DB
-> JSON 응답
이전에는 fetchCareerList가 Next 내부의 route.ts를 호출했다.
이제는 Spring의 Controller를 호출한다.
즉, 프론트엔드 쪽 흐름은 거의 그대로 유지된다.
MainPageClient
useCareerList
fetchCareerList
CareerSide
이 부분은 그대로 남는다.
대신 다음 부분이 바뀐다.
Next route.ts
createCareerListMock()
이 역할이 Spring 서버로 이동한다.
4. Spring 서버에서는 어떤 일이 일어날까
Spring 쪽에서는 보통 Controller, Service, Repository 구조로 요청을 처리한다.
예를 들어 Next에서 /api/careers/list로 요청을 보냈다면, Spring에서는 다음과 같은 Controller가 요청을 받을 수 있다.
@RestController
@RequestMapping("/api/careers")
public class CareerController {
@PostMapping("/list")
public CareerListResponse getCareerList(@RequestBody CareerListRequest request) {
return careerService.getCareerList(request);
}
}
이 코드에서 Controller는 HTTP 요청을 받는 역할을 한다.
그 다음 실제 비즈니스 로직은 Service가 처리한다.
Controller
-> HTTP 요청을 받는다.
Service
-> 필요한 비즈니스 로직을 처리한다.
Repository
-> DB에 접근해 데이터를 조회하거나 저장한다.
DB
-> 실제 데이터가 저장되는 공간이다.
즉, Spring을 붙이면 mock 데이터를 직접 만드는 방식에서 벗어나 실제 DB 기반의 데이터를 응답할 수 있게 된다.
5. 프론트엔드 입장에서 바뀌는 것과 바뀌지 않는 것
Spring을 붙인다고 해서 프론트엔드 컴포넌트가 전부 바뀌는 것은 아니다.
MainPageClient는 여전히 useCareerList를 사용한다.
const careerList = useCareerList(...)
useCareerList는 여전히 데이터를 불러오고, items, loading, error 상태를 관리한다.
items
loading
error
CareerSide는 여전히 전달받은 데이터를 화면에 렌더링한다.
<CareerSide
error={careerList.error}
items={careerList.items}
loading={careerList.loading}
/>
즉, 화면을 구성하는 방식은 크게 바뀌지 않는다.
바뀌는 것은 fetchCareerList가 요청을 보내는 대상이다.
기존
fetchCareerList -> Next route.ts
변경 후
fetchCareerList -> Spring Controller
그래서 Spring을 붙일 때 가장 먼저 확인해야 하는 부분은 API 호출 함수다.
6. 기존 구조와 Spring 적용 후 구조 비교
기존 구조는 다음과 같다.
브라우저
-> Next 프론트엔드
-> Next route.ts
-> mock 데이터 생성
-> JSON 응답
Spring을 붙인 뒤의 구조는 다음과 같다.
브라우저
-> Next 프론트엔드
-> Spring 백엔드 API
-> Service
-> Repository
-> DB
-> JSON 응답
두 구조의 차이는 명확하다.
기존에는 Next 안에서 임시로 데이터를 만들었다.
Spring을 붙이면 백엔드 서버가 따로 생기고, 실제 DB와 연결된 데이터를 내려준다.
7. route.ts는 더 이상 필요 없을까
Spring을 붙이면 보통 route.ts는 필요 없어질 수 있다.
기존의 route.ts가 단순히 mock 데이터를 반환하는 역할이었다면, Spring Controller가 그 역할을 대체하기 때문이다.
다만 항상 route.ts를 제거해야 하는 것은 아니다.
프로젝트 구조에 따라 Next의 API Route를 중간 서버처럼 사용할 수도 있다.
예를 들어 다음과 같은 구조도 가능하다.
브라우저
-> Next route.ts
-> Spring API
-> DB
이 경우 route.ts는 브라우저와 Spring 서버 사이에서 중간 계층 역할을 한다.
하지만 일반적인 프론트엔드와 백엔드 분리 구조에서는 다음 흐름을 더 많이 사용한다.
브라우저
-> Next 프론트엔드
-> Spring 백엔드 API
-> DB
이번 코드에서는 route.ts가 mock API 역할을 하고 있었기 때문에, Spring을 붙인다면 이 부분이 Spring Controller로 대체된다고 보는 것이 가장 이해하기 쉽다.
8. 정리
Spring을 붙이면 Next.js의 화면 구조가 완전히 바뀌는 것이 아니다.
MainPageClient, useCareerList, fetchCareerList, CareerSide 같은 프론트엔드 흐름은 그대로 유지된다.
다만 fetchCareerList가 요청을 보내는 목적지가 바뀐다.
기존에는 Next 내부의 route.ts가 요청을 받았다.
fetchCareerList
-> Next route.ts
Spring을 붙이면 Spring Controller가 요청을 받는다.
fetchCareerList
-> Spring Controller
그리고 Spring 내부에서는 Controller, Service, Repository, DB 순서로 요청을 처리한다.
이번 내용을 통해 Next.js와 Spring의 역할을 다음처럼 구분할 수 있었다.
Next.js
-> 화면을 만들고 사용자와 상호작용한다.
React hook
-> 데이터의 상태를 관리한다.
API 함수
-> 서버에 요청을 보낸다.
Spring
-> 요청을 받아 비즈니스 로직을 처리하고 DB 데이터를 응답한다.
DB
-> 실제 데이터를 저장한다.
'프로그래밍 > next.js' 카테고리의 다른 글
| [커리큘럼 페이지 프로젝트] Mock API를 걷어내고 Spring을 붙이며 (0) | 2026.06.10 |
|---|---|
| [커리큘럼 페이지 프로젝트] Next.js App Router에서 화면과 데이터 호출 흐름 이해하기 (0) | 2026.06.07 |