Spring에서 컨트롤러를 지정해주기 위한 어노테이션은 @Controller와 @RestController가 있음
차이점
@Controller의 역할은 Model 객체를 만들어 데이터를 담고 View를 찾는 것이지만, @RestController는 단순히 객체만을 반환하고 객체 데이터는 JSON 또는 XML 형식으로 HTTP 응답에 담아서 전송함
- @Controller와 @ResponseBody를 사용하여 만들 수 있지만 이러한 방식은 RESTful 웹서비스의 기본 동작이기 때문에 Spring은 @Controller와 @ResponseBody의 동작을 조합한 @RestController을 도입
Spring의 Controller 동작방식
1. @Controller 이해하기
Controller로 view 반환하기
전통적인 Spring MVC의 컨트롤러인 @Controller는 주로 View를 반환하기 위해 사용, 아래와 같은 과정을 통해 Spring MVC Container는 Client의 요청으로부터 View를 반환
- Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
- DispatcherServlet이 요청을 처리할 대상을 찾는다.
- HandlerAdapter을 통해 요청을 Controller로 위임한다.
- Controller는 요청을 처리한 후에 ViewName을 반환한다.
- DispatcherServlet은 ViewResolver를 통해 ViewName에 해당하는 View를 찾아 사용자에게 반환한다.
Controller가 반환한 View의 이름으로부터 View를 렌더링하기 위해서는 ViewResolver가 사용되며, ViewResolver 설정에 맞게 View를 찾아 렌더링함.
Controller로 Data 반환하기
하지만 Spring MVC의 컨트롤러를 사용하면서 Data를 반환해야 하는 경우도 있음. 컨트롤러에서는 데이터를 반환하기 위해 @ResponseBody 어노테이션을 활용해줘야 함. 이를 통해 Controller도 Json 형태로 데이터를 반환할 수 있음.
- Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
- DispatcherServlet이 요청을 처리할 대상을 찾는다.
- HandlerAdapter을 통해 요청을 Controller로 위임한다.
- Controller는 요청을 처리한 후에 객체를 반환한다.
- 반환되는 객체는 Json으로 Serialize되어 사용자에게 반환된다.
컨트롤러를 통해 객체를 반환할 때에는 일반적으로 ResponseEntity로 감싸서 반환함.
객체를 반환하기 위해서는 viewResolver 대신에 HttpMessageConverter가 동작함.
HttpMessageConverter에는 여러 Converter가 등록되어 있고, 반환해야 하는 데이터에 따라 사용되는 Converter의 종류가 달라짐
- 단순 문자열 : StringHttpMessageConverter
- 객체 : MappingJackson2HttpMessageConverter
Spring은 클라이언트의 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보를 조합해 적합한 HttpMessageConverter를 선택하여 이를 처리함.
MessageConverter가 동작하는 시점은 HandlerAdapter와 Controller가 요청을 주고 받는 시점(4, 6번에서 컨버터가 사용 됨).
@Controller 예제
@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";
}
}
- findUser는 User 객체를 ResponseEntity로 감싸서 반환
- User를 json으로 반환하기 위해 @ResponseBody라는 어노테이션을 붙여줌
- detailView 함수에서는 View를 전달해주고 있기 때문에 String을 반환값으로 설정
2. @RestController 이해하기
RestController
@RestController는 @Controller에 @ResponseBody가 추가된 것, RestController의 주 용도는 Json 형태로 객체 데이터를 반환하는 것.
데이터를 응답으로 제공하는 REST API를 개발할 때 주로 사용하며 객체를 ResponseEntity로 감싸서 반환(동작 과정은 @Controller에 @ResponseBody를 붙인 것과 완벽히 동일
- Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
- DispatcherServlet이 요청을 처리할 대상을 찾는다.
- HandlerAdapter을 통해 요청을 Controller로 위임한다.
- Controller는 요청을 처리한 후에 객체를 반환한다.
- 반환되는 객체는 Json으로 Serialize되어 사용자에게 반환된다.
@RestController
@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로 감싸서 반환해야 함
'항해 99 > Spring' 카테고리의 다른 글
Entity와 DTO의 분리 (0) | 2024.03.08 |
---|---|
lombok 주의 사항 (0) | 2024.03.06 |
메서드 명 find와 get의 차이 (0) | 2024.03.04 |
TDD(Test-Driven Development), JUnit (0) | 2024.03.03 |
Swagger 사용하기 (0) | 2024.03.01 |