아래 두 코드는 어떤 차이점이 있을까요? 코드만 보자만 어노테이션 차이밖에 없습니다. (@Controller, @RestController)
@Controller
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("/customers")
public String list(Model model) {
model.addAttribute("customers", customerService.getAllCustomers());
return "views/customers";
}
}
@RestController
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("/customers")
public String list(Model model) {
model.addAttribute("customers", customerService.getAllCustomers());
return "views/customers";
}
}
위 두 코드는 결과가 같을까요? 다를까요? 결과는 바로! 아래와 같습니다.
같은 코드에서 어노테이션만 바꿨을 뿐인데 왜 이런 차이가 생겼을까요 ?
먼저, 간단하게 MVC가 무엇인지 짚고 넘어가보겠습니다.
MVC (Model View Controller)
Model : View 에 출력할 데이터를 담아두는 역할로 화면을 렌더링하기 위해 필요한 데이터를 모두 담아서 뷰에 전달한다.
View : 모델에 담겨있는 데이터를 사용해서 화면을 렌더링하는 역할로, 주로 Html을 생성하는 부분을 말한다.
Controller : http 요청을 받아서 파라미터 검증과 비즈니스 로직을 실행하는 역할로, 뷰에 필요한 데이터를 조회해서 모델에 저장한다.
@controller 는 주로 view를 반환하기 위해 사용합니다. 아래와 같은 흐름으로 Client의 요청에 맞는 View를 반환합니다.
1. 클라이언트가 요청을 보내면 dispatche Servlet으로 요청을 받는다.
2. dispatcher servlet은 요청에 해당하는 Controller로 위임 처리를 하도록 Handler Mapping 에게 위임을 처리한다.
3. view Resolver는 Controller 가 반환한 논리 뷰 이름을 실제 물리뷰 경로로 변경하고 View 객체를 반환환한다.
그렇다면 View가 아닌 Data를 반환해야하면 어떻게 해야할까요? 그럴때 @RestController를 이용하면 됩니다. @RestController는 데이터 반환을 할 수 있습니다. 아래와 같은 흐름으로 Client의 요청에 맞는 Data를 반환합니다.
1. 클라이언트가 요청을 보내면 dispatche Servlet으로 요청을 받는다.
2. dispatcher servlet은 요청에 해당하는 Controller로 위임 처리를 하도록 Handler Mapping 에게 위임을 처리한다.
3. HttpMessageConverter가 동작하여 요청에 맞는 데이터를 반환합니다.
@Controller는 view Resolver가 동작하여 view를 반환합니다. 첫번째 코드블럭에서는 @Controller를 사용하여 view를 반환했기때문에, 정상적으로 view가 보여졌습니다.
@RestController HttpMessageConverter가 동작하여 데이터를 반환합니다. 하여 "views/customers"에 해당되는 view 경로로 반환이 되지않고 "views/customers" 로 반환이 되어 렌더링 결과에 차이가 생기게 된것입니다.
만약 @Controller를 사용하여 Data를 반환하고 싶으면, @ResponseBody 어노테이션을 같이 사용하면 됩니다.
실제로 어노테이션 코드를 확인해보면 아래와 같이 @RestController = @Controller + @ResponseBody 로 구성된것을 확인할 수 있습니다.