[Spring] @Controller 와 @RestController 차이

nooyji·2022년 7월 13일
0

Spring 에서 컨트롤러를 지정해주기 위한 어노테이션은 @Controller 와 @RestController 가 있습니다. 전통적인 Spring MVC 의 컨트롤러인 @Controller 와 Restful 웹서비스의 컨트롤러인 @RestController 의 주요한 차이점은 HTTP Response Body 가 생성되는 방식입니다. 이번에는 2가지 어노테이션의 차이와 사용법에 대해 알아보도록 하겠습니다.

  1. @Controller 이해하기

Controller 로 View 반환하기

전통적인 Spring MVC 의 컨트롤러인 @Controller 는 주로 View 를 반환하기 위해 사용합니다. 아래와 같은 과정을 통해 Spring MVC Container 는 Client 의 요청으로부터 View 를 반환합니다.

  1. Client 는 URI (Uniform Resource Identifier) 형식으로 웹 서비스에 요청을 보낸다.
  2. DispatcherServlet 이 요청을 위임할 HandlerMapping 을 찾는다.
  3. HandlerMapping 을 통해 요청을 Controller 로 위임한다.
  4. Controller 는 요청을 처리한 후에 ViewName 을 반환한다.
  5. DispatcherServlet 은 ViewResolver 를 통해 ViewName 에 해당하는 View 를 찾아 사용자에게 반환한다.

Controller 가 반환한 뷰의 이름으로부터 View 를 렌더링하기 위해서는 ViewResolver 가 사용되며, ViewResolver 설정에 맞게 View 를 찾아 렌더링합니다.

Controller 로 Data 반환하기

하지만 Spring MVC 의 컨트롤러를 사용하면서 Data 를 반환해야 하는 경우도 있습니다. 컨트롤러에서는 데이터를 반환하기 위해 @ResponseBody 어노테이션을 활용해주어야 합니다. 이를 통해 Controller 도 Json 형태로 데이터를 반환할 수 있습니다.

  1. Client 는 URI 형식으로 웹 서비스에 요청을 보낸다.
  2. DispatcherServlet 이 요청을 위임할 HandlerMapping 을 찾는다.
  3. HandlerMapping 을 통해 요청을 Controller 로 위임한다.
  4. Controller 는 요청을 처리한 후에 객체를 반환한다.
  5. 반환되는 객체는 Json 으로 Serialize 되어 사용자에게 반환된다.

컨트롤러를 통해 객체를 반환할 때에는 일반적으로 ResponseEntity 로 감싸서 반환을 합니다. 그리고 객체를 반환하기 위해서는 viewResolver 대신에 HttpMessageConverter 가 동작합니다. HttpMessageConverter 에는 여러 Converter 가 등록되어 있고, 반환해야 하는 데이터에 따라 사용되는 Converter 가 달라집니다. 단순 문자열인 경우에는 StringHttpMessageConverter 가 사용되고, 객체인 경우에는 MappingJackson2HttpMessageConverter 가 사용되며, 데이터 종류에 따라 서로 다른 MessageConverter 가 작동하게 됩니다. Spring 은 클라이언트의 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해 적합한 HttpMessageConverter 를 선택하여 이를 처리합니다.

@Controller 예제 코드

@Controller
@RequiredArgsConstructor
pulic class UserController {
	private final UserService userService;
    
    @getMapping(value = "/users")
    pulic @ResponseBody ResponseEntity<User> findUser(@RequestParam("userName") String userName) {
    return ResponseEntity.ok(userService.findUser(user));
    }

	@GetMapping(value = "/users/detailView")
	public String detailView(Model model, @RequestParam("userName") String userName) {
		User user = userService.findUser(userName);
    	model.addAttribute("user", user);
    	return "/users/detailView";
    }
}

위 예제의 findUser 는 User 객체를 ResponseEntity 로 감싸서 반환하고 있고, User 를 json 으로 반환하기 위해 @Response Body 라는 어노테이션을 붙여주고 있습니다. detailView 함수에서는 View 를 전달해주고 있기 때문에 String 을 반환값으로 설정해주었습니다. (물론 이렇게 데이터를 반환하는 RestController 와 View 를 반환하는 Controller 를 분리하여 작성하는 것이 좋습니다.)

  1. @RestController 이해하기

RestController

@RestController 는 @Controller 에 @ResponseBody 가 추가된 것입니다. 당연하게도 RestController 의 주용도는 Json 형태로 객체 데이터를 반환하는 것입니다. 최근에 데이터를 응답으로 제공하는 REST API 를 개발할 때 주로 사용하며 객체를 ResponseEntity 로 감싸서 반환합니다. 이러한 이유로 동작 과정 역시 @Controller 에 @ResponseBody 를 붙인 것과 완벽히 동일합니다.

  1. Client 는 URI 형식으로 웹 서비스에 요청을 보낸다.
  2. DispatcherServlet 이 요청을 위임할 HandlerMapping 을 찾는다.
  3. HandlerMapping 을 통해 요청을 Controller 로 위임한다.
  4. Controller 는 요청을 처리한 후에 객체를 반환한다.
  5. 반환되는 객체는 Json 으로 Serialize 되어 사용자에게 반환된다.

@RestController 예제 코드

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {

	private final UserService userService;
    
    @GetMapping(value = "/users")
    public User findUser(@RequestParam("userName") String userName){
    	return userService.findUser(user);
    }
    
    @GetMapping(value = "/users")
    public ResponseEntity<User> findUserWithResponseEntity(@RequestParam("userName") String userName){
    	return ResponseEntity.ok(userService.findUser(user));
    }
}

findUser 는 User 객체를 그대로 반환하고 있습니다. 이러한 경우의 문제는 클라이언트가 예상하는 HttpStatus 를 설정해줄 수 없다는 것입니다. 예를 들어 어떤 객체의 생성 요청이라면 201 CREATED 를 기대할 것이지만 객체를 그대로 반환하면 HttpStatus 를 설정해줄 수 없습니다. 그래서 객체를 상황에 맞는 ResponseEntity 로 감싸서 반환해주어야 합니다.

원문 : https://mangkyu.tistory.com/49

0개의 댓글