Spring에서 컨트롤러를 구현할 때 `@Controller`와 `@RestController` 두 가지 어노테이션을 사용할 수 있다.
이 두 가지 방식의 차이점과 사용법에 대해 자세히 알아보자!
📌 @Controller
`@Controller`는 전통적인 Spring MVC 컨트롤러로, 주로 View를 반환하기 위해 사용된다.
1. View 반환하기
@Controller
public class ViewController {
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "안녕하세요");
return "hello"; // hello.jsp나 hello.html 같은 뷰 파일을 찾는다.
}
}
- 클라이언트가 `/hello` URL로 요청을 보낸다.
- DispatcherServlet이 Handler Mapping을 통해 요청 URL에 맞는 컨트롤러와 메서드를 찾는다.
- Handler Adapter를 통해 컨트롤러를 실행한다.
- 컨트롤러가 model에 데이터를 담고 view 이름을 반환한다.
- ViewResolver가 view이름("hello")을 실제 물리적 view 파일 경로(/templates/hello.html)로 변환한다.
- view가 model 데이터를 사용해 화면을 생성해 클라이언트에게 제공한다.
2. Data 반환하기
웹 애플리케이션이 발전하면서 view 대신 data를 직접 반환해야 하는 경우가 많아졌는데,
`@Controller`에서 데이터를 반환하려면 `@ResponseBody` 어노테이션을 활용해야 한다.
@Controller
public class DataController {
// 데이터 반환 - ResponseEntity 사용
@GetMapping("/message")
@ResponseBody
public ResponseEntity<Message> getMessage() {
Message message = new Message("안녕하세요");
return ResponseEntity.ok(message);
}
// HTTP 상태 코드를 포함한 응답
@PostMapping("/messages")
@ResponseBody
public ResponseEntity<Message> createMessage(@RequestBody MessageRequest request) {
Message savedMessage = messageService.save(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(savedMessage);
}
}
`@ResponseBody`를 사용하면 ViewResolver 대신 HttpMessageConverter가 동작해 객체를 JSON 형식으로 변환한다.
`ResponseEntity`를 사용하면 HTTP 상태 코드, 헤더, 본문을 모두 제어할 수 있어 더 세밀한 응답 제어가 가능하다.
📌 @RestController의 등장
컨트롤러에 @ResponseBody를 모든 메서드에 적용해야 하는 번거로움을 해결하기 위해 @RestController가 등장하게 되었다.
`@RestController`는 `@Controller`와 `@ResponseBody`가 결합된 어노테이션으로
REST API 개발에 주로 사용된다.
아래 소스코드를 살펴보면, @Controller는 @Component 주석이 있고
@RestController는 @Controller와 @ResponseBody가 포함되어 있는 것을 확인할 수 있다.
`@RestController`를 사용하면 클래스 내의 모든 메서드에 자동으로 @ResponseBody가 적용되는 것이다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController
- 클라이언트의 HTTP 요청이 Dispatcher Servlet으로 전달된다.
- Dispatcher Servlet은 Handler Mapping을 통해 요청을 처리할 적절한 Controller를 찾는다.
- Dispatcher Servlet은 Handler Adapter를 통해 해당 Controller를 호출할 준비를 한다.
- Handler Adapter는 실제 RestController를 호출하여 비즈니스 로직을 처리한다.
- RestController는 비즈니스 로직 처리를 위해 Service 계층을 호출하고, 필요한 경우 Repository를 통해 Database에 접근한다.
- Service 계층에서 처리된 결과는 ResponseEntity 객체로 변환된다.
- ResponseEntity는 Handler Adapter를 통해 Dispatcher Servlet으로 전달된다.
- 최종적으로 Dispatcher Servlet은 응답을 클라이언트에게 반환한다.
`@RestController`를 사용하면 모든 메서드에 `@ResponseBody`가 적용되어 데이터를 반환할 때마다 어노테이션을 추가하지 않아도 된다. 주로 REST API를 개발할 때 사용되며, 다음 예시를 통해 ResponseEntity의 필요성을 살펴보도록 하자.
@RestController // @Controller + @ResponseBody
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// 단순 객체 반환
@GetMapping(value = "/users")
public User findUser(@RequestParam String userName){
return userService.findUser(userName);
}
// ResponseEntity 사용
@GetMapping(value = "/users")
public ResponseEntity<User> findUserWithResponseEntity(@RequestParam String userName){
return ResponseEntity.ok(userService.findUser(userName));
}
}
첫 번째 메서드처럼 객체를 직접 반환하면 HTTP 상태 코드를 세밀하게 제어할 수 없다.
예를 들어 사용자를 찾지 못했을 때 404 Not Found를 반환하거나, 서버 오류 시 500 Internal Server
Error를 반환하는 등의 처리가 불가능하다.
반면 ResponseEntity를 사용하면 다양한 상황에 맞는 적절한 HTTP 상태 코드를 반환할 수 있다
- 리소스를 찾을 수 없을 때: 404 Not Found
- 잘못된 요청일 때: 400 Bad Request
- 서버 오류 발생 시: 500 Internal Server Error
- 정상 처리 시: 200 OK
따라서 REST API를 구현할 때는 ResponseEntity를 사용하여 더 명확한 응답을 제공하는 것이 좋다.
📌 @Controller와 @RestController 비교
특성 | @Controller | @RestController |
View 반환 여부 | O | X |
JSON 데이터 반환 | @ResponseBody 필요 | 기본 동작 |
주요 사용 사례 | 템플릿 렌더링 | REST API 개발 |
정리해보면
`@Controller`는 View 템플릿을 사용하는 전통적인 웹 애플리케이션에 유용하다.
`@RestController`는 RESTful API 개발을 위한 간결하고 효율적인 방법을 제공한다.
REST API 구현 시 `ResponseEntity`를 사용하면 HTTP 상태 코드와 응답 구조를 세밀하게 제어할 수 있다.
사용하려는 애플리케이션의 요구 사항에 따라 적절한 어노테이션을 선택해서 개발하면 된다!!!!
🗂️ References
[Spring] @Controller와 @RestController 차이
[Spring] @Controller와 @RestController의 차이점 알아보기
'Study > Spring' 카테고리의 다른 글
[Spring] Bean Validation 활용한 효율적인 검증 구현하기 (0) | 2025.01.14 |
---|---|
[Spring] BindingResult 활용한 Validation 검증 동작 방식 (0) | 2025.01.07 |