@Controller와 @RestController의 차이

김재민·2022년 4월 26일
0

개요

김영한님의 '실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화'을 들으면서 개발하다보니 API의 클래스내에 @RestController 어노테이션을 사용하여 컨트롤러를 명시해주는 것을 보게 되었다.

일반적으로 MVC구조에서 Controller에게 @Controller를 썻었는데 왜 @RestController를 쓸지 생각을 해보게 되었고 조사해보았다.

주요한 차이

HTTP Response Body가 생성되는 방식에서의 차이가 있다.

@Controller의 동작 방식

Controller로 View 반환하기

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

참고

DispatcherServlet은 모든 요청을 받고 세부 경로는 각 Controller에게 뿌려주는 프론트 컨트롤러의 역할

ViewResolver는 사용자가 요청한 것에 대한 응답 view를 렌더링하는 역할

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

Controller가 반환한 뷰의 이름으로부터 View를 렌더링하기 위해 ViewResolver가 사용됨.
ViewResolver의 설정에 맞게 View를 찾아 렌더링함


Controller로 Data 반환하기

Data를 반환해야되는 경우
컨트롤러에서는 데이터를 반환하기 위해 @ResponseBody 어노테이션을 활용해주어야 함
이를 통해 Controller도 Json형태로 데이터를 반환

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

컨트롤러를 통해 객체를 반환할 때에는 일반적으로 ResponseEntity로 감싸서 반환을 함.

또한, 객체를 반환하기 위해서는 viewResolver 대신에 HttpMessageConverter가 동작.

HttpMessageConverter에는 여러 Converter가 등록되어 있고,

반환해야 하는 데이터에 따라 사용되는 Converter가 달라짐

단순 문자열인 경우에는 StringHttpMessageConverter가 사용되고, 객체인 경우에는 
MappingJackson2HttpMessageConverter가 사용되고

데이터의 종류에 따라 서로 다른 MessageConverter가 작동하게 됨

Spring은 Client의 HTTP Accept헤더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해 적합한
HttpMessageConverter를 선택하여 이를 처리

예제코드

@Controller
@RequiredArgsConstructor
public class UserController {

	private final UserService userService;
	
    @GetMapping(value = "/users")
    public @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";
	}
  }  
  1. findUser메소드에서 User객체를 ResponseEntity< User >의 형태로 반환하고 있고, json으로 반환하기 위해 @ResponseBody어노테이션을 사용

  2. detailView메소드에서는 View로 전달해주고 있기 때문에 String으로 반환

@RestController 동작 방식

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

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

예제코드

@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));
	}
  }  
  1. findUser메소드는 User객체를 그대로 반환하고 있음
    이때 문제는 클라이언트가 예상하는 HttpStatus를 설정해줄 수 없음
    예를 들어 어떤 객체의 생성 요청이라면 201 CREATED를 기대할 것이지만 객체를 그대로 반환하면 HttpStatus를 설정해 줄 수 없음
    -> 그렇기 때문에 상황에 맞는 ResponseEntity로 감싸서 반환해주어야 함





출처 : https://mangkyu.tistory.com/49 [MangKyu's Diary]

profile
어제의 나보다 나은 오늘의 내가 되자!🧗‍♂️

0개의 댓글