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

전통적인 Spring MVC의 컨트롤러인 @Controller와 Restuful 웹서비스의 컨트롤러인 @RestController의 주요한 차이점은 HTTP Response Body가 생성되는 방식이다.

 

@Controller


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

 

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

한편으로는 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가 사용

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을 반환값으로 설정

 


 

@RestController


예전에 프로그래밍을 할 때에는 jsp나 html과 같은 뷰를 전달해 주었기 때문에 @Controller를 사용해왔었지만,

최근에는 프론트엔드와 백엔드를 따로 두고, 백엔드에서는 REST API를 통해 json으로 데이터만 전달하기 때문에 편리성을 위해 @RestController를 사용하고 있다.

 

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

 

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

 


 

@RequestBody, @ResponseBody 어노테이션


보통 웹에서 화면 전환이 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다.

비동기 통신을 하기 위해선 클라이언트가 서버로 요청 메시지의 본문(Body)에 데이터를 담아서 보내야 하고, 서버도 클라이언트에 응답하기 위해 응답 메시지의 본문(Body)에 데이터를 담아서 보내야 한다.

이 때의 본문(body)를 각각 Request Body와 Response Body로 부르는데, 이러한 Body에 담기는 데이터 형식은 JSON(JavaScript Object Notation)이다.

@RequestBody 어노테이션은 이러한 비동기 통신에서 쓰이는 Body 안의 데이터(JSON객체)를 자바 객체(VO)로 변환해주는 어노테이션이다. 마찬가지로 @ResponseBody 어노테이션은 보내려는 자바 객체(VO)를 데이터(JSON객체)로 바꿔 Body 안에 넣어주는 어노테이션이라고 보면 무방하다.

 

 

출처 :
https://mangkyu.tistory.com/49?category=761302
https://velog.io/@dyunge_100/Spring-Controller%EC%99%80-RestController%EC%9D%98-%EC%B0%A8%EC%9D%B4

+ Recent posts