728x90
📌 Intro
Spring에서는 웹 요청을 처리하기 위해 @Controller, @RestController와 같은 어노테이션을 사용한다.
이번 글에서는 이 두 어노테이션의 차이를 이해하기 위해 Spring MVC의 핵심 구조를 먼저 살펴보고, 그 위에서 각 어노테이션의 처리 흐름과 용도를 비교해보자.
1. Spring MVC 구조의 핵심: DispatcherServlet
Spring MVC는 다음과 같은 프론트 컨트롤러 패턴(Front Controller Pattern)을 따른다.
더보기
여기서 프론트 컨트롤러 패턴은 사용자의 모든 요청을 한 곳(중앙 컨트롤러)에서 먼저 받아서, 이후 어떤 로직(컨트롤러, 서비스 등)으로 넘길지를 결정하는 방식을 의미한다.
이 패턴에서 모든 요청은 중앙 진입점인 `DispatcherServlet`으로 들어오며, 이후의 흐름을 모두 이 객체가 조율한다.
1.1. 처리 흐름
- 클라이언트가 HTTP 요청 전송
- `DispatcherServlet`이 요청 수신
- `HandlerMapping`을 통해 어떤 `Controller`가 처리할지 결정
- 해당 `Controller`를 실행할 수 있는 `HandlerAdapter` 확보
- `Controller` 메서드 실행 → 결과 반환
- `View` 처리 단계
- 템플릿(View 이름 반환 시): `ViewResolver`가 실제 뷰 렌더링
- 데이터 응답(JSON 등): `HttpMessageConverter`가 객체 → JSON 변환
- 최종 응답 반환
1.2. 핵심 컴포넌트 정리
컴포넌트 | 주요 역할 | 실무에서 체크할 사항 |
DispatcherServlet | 요청 흐름의 중심 / 예외 처리 | 예외 핸들링 주의 |
HandlerMapping | URI → Controller 매핑 | 중복 매핑 여부 |
HandlerAdapter | 핸들러 실행 추상화 | 커스텀 핸들러 가능 여부 |
ViewResolver | View 이름 → 실제 뷰 경로 결정 | prefix/suffix 설정 |
HttpMessageConverter | 객체 ↔ HTTP 메시지 변환 (JSON, XML) | Content-Type 정확히 설정 |
2. @Controller – 전통적인 서버 사이드 렌더링 방식
`@Controller`는 View 렌더링을 위한 컨트롤러로, 템플릿 기반 응답에 적합하다.
하지만 필요 시 `@ResponseBody`를 통해 데이터도 반환할 수 있다.
2.1. View 반환 흐름 예시
@Controller
public class HomeController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("msg", "Hello!");
return "home"; // → /templates/home.html 렌더링
}
}
처리 흐름 요약
- 클라이언트가 `/home` 요청
- `DispatcherServlet`이 요청 수신
- `HandlerMapping` → `HomeController` 선택
- 메서드 실행 후 "home" 반환 (반환값 "home"은 View 이름)
- `ViewResolver`가 "home" → `home.html` 파일을 찾아 렌더링
- HTML 응답 전송
2.2. Data 반환 예시 (with @ResponseBody)
컨트롤러에서는 데이터를 반환하려면 `@ResponseBody` 어노테이션을 활용해주어야 한다.
이를 통해 Controller도 Json 형태로 데이터를 반환할 수 있다.
@Controller
public class DataController {
@GetMapping("/data")
@ResponseBody
public Map<String, String> data() {
return Map.of("msg", "Hello!");
}
}
`@ResponseBody`를 붙이면 View 렌더링을 생략하고 HttpMessageConverter를 통해 JSON 응답이 된다.
3. @RestController – RESTful API 전용 컨트롤러
`@RestController`는 내부적으로 `@Controller` + `@ResponseBody`가 결합된 어노테이션이다.
즉, 반환하는 객체가 항상 JSON으로 직렬화되어 클라이언트에 전송된다.
→ REST API 개발 시 필수 사용
별도의 `@ResponseBody` 없이도 JSON으로 자동 변환된다. 내부적으로는 `HttpMessageConverter`가 동작한다.
@RestController
public class ApiController {
@GetMapping("/api/hello")
public Map<String, String> hello() {
return Map.of("message", "Hello, REST!");
}
}
처리 흐름
- 클라이언트가 `/api/hello` 요청
- `DispatcherServlet`이 요청 수신
- `HandlerMapping` → `ApiController` 선택
- `hello()` 호출 후 `Map` 객체 반환
- `HttpMessageConverte`r가 JSON 변환 (`{"message": "Hello, REST!"}`)
- JSON 응답이 클라이언트에 전송됨
4. @Controller vs @RestController 비교
항목 | `@Controller ` | `@RestController` |
주 용도 | View 반환 (템플릿 렌더링) | JSON 등 데이터 반환 (REST API) |
View 처리 방식 | ViewResolver | 사용하지 않음 |
JSON 응답 시 | `@ResponseBody` 필요 | 자동 처리됨 |
추천 사용처 | 웹 페이지, 서버 렌더링 기반 서비스 | RESTful API, 모바일 백엔드 |
✏️ 마무리
- Spring MVC는 `DispatcherServlet`을 중심으로 다양한 컴포넌트들이 요청을 처리하는 구조를 갖고 있다.
- `@Controller`는 View와 데이터를 모두 반환할 수 있지만, RESTful API에 적합한 방식은 `@RestController`이다.
- 내부적으로는 `HttpMessageConverter`, `ViewResolver` 등이 적절히 개입하여 응답 포맷을 결정한다.
📎 참고자료
728x90