프로그래밍/Java

[Spring, Spring Boot] @Controller와 @RestController

차나니 2024. 3. 31. 23:52

@Controller와 @RestController란?

Spring과 Spring Boot에서 컨트롤러를 지정해주기 위한 어노테이션은 @Controller와 @RestController가 있습니다.

Spring MVC의 컨트롤러인 @Controller와 Restful 웹서비스의 컨트롤러인 @RestController의 차이점은 HTTP Response Body가 생성되는 방식입니다. 

 

@Controller란?

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

 

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

[@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을 반환값으로 설정해주었습니다. (물론 이렇게 데이터를 반환하는 RestController와 View를 반환하는 Controller를 분리하여 작성하는 것이 좋습니다.)

 

 

@RestController란?

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

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

 

[@ResContoroller 예제 코드]

@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로 감싸서 반환해주어야 합니다.