티스토리 뷰

Spring

[Spring] @Controller와 @RestController 차이

망나니개발자 2019. 9. 9. 21:48
반응형

Spring에서 컨트롤러를 지정해주기 위한 어노테이션은 @Controller와 @RestController가 있습니다. 전통적인 Spring MVC의 컨트롤러인 @Controller와 Restuful 웹서비스의 컨트롤러인 @RestController의 주요한 차이점은 HTTP Response Body가 생성되는 방식입니다. 이번에는 2가지 어노테이션의 차이와 사용법에 대해 알아보도록 하겠습니다. 

 

1. @Controller(Spring MVC Controller)


[ Controller - View ]

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

 

  1. Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
  2. Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.
  3. Controller가 요청을 처리한 후에 응답을 DispatcherServlet으로 반환하고, DispatcherServlet은 View를 사용자에게 반환한다.

@Controller가 View를 반환하기 위해서는 ViewResolver가 사용되며, ViewResolver 설정에 맞게 View를 찾아 렌더링합니다.

 

 

[ Controller - Data ]

하지만 Spring MVC의 컨트롤러에서도 Data를 반환해야 하는 경우도 있습니다. Spring MVC의 컨트롤러에서는 데이터를 반환하기 위해 @ResponseBody 어노테이션을 활용해주어야 합니다. 이를 통해 Controller도 Json 형태로 데이터를 반환할 수 있습니다.

 

  1. Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
  2. Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.
  3. @ResponseBody를 사용하여 Client에게 Json 형태로 데이터를 반환한다.

@RestController가 Data를 반환하기 위해서는 viewResolver 대신에 HttpMessageConverter가 동작합니다. HttpMessageConverter에는 여러 Converter가 등록되어 있고, 반환해야 하는 데이터에 따라 사용되는 Converter가 달라집니다. 단순 문자열인 경우에는 StringHttpMessageConverter가 사용되고, 객체인 경우에는 MappingJackson2HttpMessageConverter가 사용되며, 데이터 종류에 따라 서로 다른 MessageConverter가 작동하게 됩니다. Spring은 클라이언트의 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해 적합한 HttpMessageConverter를 선택하여 이를 처리합니다.

 

 

[ @Controller 예제 코드 ]

@Controller
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @PostMapping(value = "/info")
    public @ResponseBody User info(@RequestBody User user){
        return userService.retrieveUserInfo(user);
    }
    
    @GetMapping(value = "/infoView")
    public String infoView(Model model, @RequestParam(value = "userName", required = true) String userName){
        User user = userService.retrieveUserInfo(userName);
        model.addAttribute("user", user);
        return "/user/userInfoView";
    }

}

위 예제의 info는 User라는 데이터를 반환하고자 하고 있고, User를 json으로 반환하기 위해 @ResponseBody라는 어노테이션을 붙여주고 있습니다. infoView 함수에서는 View를 전달해주고 있기 때문에 String을 반환값으로 설정해주었습니다. (물론 이렇게 데이터를 반환하는 RestController와 View를 반환하는 Controller를 분리하여 작성하는 것이 좋습니다.)

 

 

 

2. @RestController(Spring Restful Controller)


[ RestController ]

@RestController는 Spring MVC Controlle에 @ResponseBody가 추가된 것입니다. 당연하게도 RestController의 주용도는 Json 형태로 객체 데이터를 반환하는 것입니다. 개인적으로는 VueJS + Spring boot 프로젝트를 진행하며 Spring boot를 API 서버로 활용할 때 또는 Android 앱 개발을 하면서 데이터를 반환할 때 사용하였습니다.

 

  1. Client는 URI 형식으로 웹 서비스에 요청을 보낸다.
  2. Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.
  3. RestController는 해당 요청을 처리하고 데이터를 반환한다.

 

 

[ @RestController 예제 코드 ]

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @PostMapping(value = "/info1")
    public ResponseEntity<User> info1(@RequestBody User user){
        return ResponseEntity.ok(userService.retrieveUserInfo(user));
    }

    @PostMapping(value = "/info2")
    public ResponseEntity<User> info2(@RequestParam(value = "userName", required = true) String userName){
        User user = userService.retrieveUserInfo(userName);

        if(user == null){
            return ResponseEntity.noContent().build()
        }

        return ResponseEntity.ok(user)
    }

    @PostMapping(value = "/info3")
    public ResponseEntity<User> info3(@RequestParam(value = "userName", required = true) String userName){
        return Optional.ofNullable(userService.retrieveUserInfo(userName))
                .map(user -> ResponseEntity.ok(user))
                .orElse(ResponseEntity.noContent().build());
    }
}

 

info1의 메소드는 User 데이터를 그대로 반환하고 있습니다. 하지만 이렇게 처리하는 것 보다 info2처럼 결과 데이터와 상태코드를 함께 제어하여 반환하는 것이 좋습니다. 또한 만약 userService에서 반환하는 형태가 Optional이라면 info3 처럼 깔끔하게 처리를 해줄 수 있습니다.

(Optional에 대해서 잘 모른다면 여기를 참고해주세요!)

반응형
댓글
댓글쓰기 폼
  • 이이잉기모링 RestController는 Controller의 ResposneBody 기반으로 응답을 한다고 하셧는데
    Controller에 ResponseBody로 응답하는거랑 차이가 있나요?
    2020.05.10 18:24
  • 망나니개발자 @Controller와 @RestController는 용도의 차이라고 이해하시면 될 것 같습니다! 예전에 프로그래밍을 할 때에는 jsp나 html과 같은 뷰를 전달해 주었기 때문에 @Controller를 사용해왔었지만, 최근에는 프론트엔드와 백엔드를 따로 두고, 백엔드에서는 REST API를 통해 json으로 데이터만 전달하기 때문에 편리성을 위해 @RestController를 사용하게 되었습니다ㅎㅎ 2020.05.11 11:06 신고
  • 코동이 글 감사합니다. ㅎㅎ 질문하나만 해도 될까요? json통신은 어떤 방식으로 하시나요? jquery로 ajax이용하시나요? 2020.06.08 18:18 신고
  • 망나니개발자 Template Engine을 사용하는 경우에는 jquery로 ajax를 이용하고 있고, Vue 같은 프레임워크를 쓸때는 json library를 쓰고 있고, 안드로이드의 경우에는 Retrofit2 라이브러리를 사용하고 있습니다:) 더 궁금한거 있으시면 편하게 물어봐주세요ㅎㅎ 2020.06.08 18:49 신고
  • 코동이 아 답변 감사합니다! 또 궁금한게 있습니다...

    class UserController에서 retrieveUserInfo2 메서드의 return new ResponseEntity<>(userVO, HttpStatus.OK); 이것은 JSON으로 상태를 반환하다고 알고 있는데요. 혹시 이 결과값을 Template Engine에서 나타내고 싶다면, RestController를 Controller로 바꿔서 model 객체에 담아서 return하는게 맞나요, 아니면 단순하게 jquery ajax부분에서 success 할 때 해당 페이지로 return시켜주는게 맞나요?
    2020.06.11 14:24 신고
  • 망나니개발자 Template 엔진을 사용하는 경우에도 Form 기반으로 전체 페이지를 불러오는지, Ajax의 비동기처리로 일부 데이터만 불러오는지에 따라 다르게 처리를 해주어야 합니다!
    만약 전체 페이지를 불러오는 경우라면 Form 기반으로 Request 를 보내고, Model에 add를 하여서 return을 해주시는게 맞습니다. 하지만 Ajax로 비동기로 처리를 한다면 json의 형태로 데이터만 반환받아서 이미 로드된 화면에 데이터만 업데이트 해주면 됩니다!
    개발하시는 부분이 전체 페이지를 로드해야 하는지 아니면 ajax의 비동기 처리로 데이터만 불러와서 화면의 일부만 갱신하면 되는지 상황에 맞게 선택하셔서 사용하면 될 것 같습니다!
    2020.06.11 18:34 신고
  • 두더지 Spring Jsp에서 연습할 때 기존에서는 @controller에서 뷰 데이터 다 처리했는데
    rest api에서는@controller @restcontroller 선언한 두 개의 클레스 만들고
    @controller 클레스는 view만 처리하고
    @restcontroller 클레스는 데이터 처리에 사용하면 되나요?

    2020.12.13 03:32
  • 망나니개발자 넵 말씀해주신대로 컨트롤러를 2개로 분리하면 됩니다. 물론 최근에는 React나 Vue 등을 사용하여 Front단을 분리하고 있지만요! 2020.12.13 13:52 신고
  • 두더지 감사합니다. 2020.12.13 16:56
  • cws Optional에 여기가 링크가 안 열립니다 ㅜ.ㅜ 2020.12.14 18:03
  • 망나니개발자 헉 링크가 깨졌었군요! 수정하였습니다 감사합니다!! 2020.12.14 20:05 신고
  • seogenius @RestController나 @ResponseBody로 리턴하면 디스패처 서블릿 거치지 않고 바로 컨버터에 의해 변환되어 http body에 실려 바로 클라이언트한테 반환되는 것인가요? 2021.03.29 13:38 신고
  • 망나니개발자 디스패처 서블릿은 프론트 컨트롤러로써 요청을 처리할 적합한 핸들러를 찾아 역할을 위임시킵니다. View를 반환하는 경우에는 ViewResolver를 위해 디스패처 서블릿을 거쳐야하지만, 데이터를 반환하는 경우에는 그럴 필요가 없는 것으로 알고 있습니다. 2021.03.29 20:33 신고
  • seogenius 알맞은 메시지 컨버터에 의해 응답형태로 변환돼서 HTTP Body에 실릴 때 디스패처 서블릿이 처리해주지 않나요? 헷깔리네요..ㅠ 2021.04.02 00:35 신고
  • 망나니개발자 저도 공부한지 오래되어서 확실하진 않지만, Dispatcher Servlet에서 ViewResolver는 관리하지만, MessageConverter는 관리하지 않는 것으로 알고 있습니다. 조만간 확인 후에 잘못된 내용이면 답글 달아드리도록 하겠습니다:) 2021.04.02 11:22 신고
  • seogenius 네 감사합니다^^ 2021.04.02 11:24 신고
  • 뽀리 이해하기 쉽게 정리해주셔서 잘 배우고 갑니다! 감사합니당! 2021.05.12 14:07
  • 망나니개발자 많은 도움이 되셨다니 뿌듯하네요! 감사합니다:) 2021.05.12 15:18 신고
  • 망규느님 안뇽하세요...@restcontroller 가 json 데이터 반환값을 만들어주는 방법이 궁금하여 찾다가 보게되었습니다!! 정리왕이십니다... 감사합니다 >_< 2021.06.08 00:18
  • 망나니개발자 앗 도움이 많이 되셨나욤!?!? 앞으로도 좋은 글들 많이 포스팅할테니 자주 들려주세요:) 2021.06.24 15:51 신고
  • mrunzap@gmail.com 제가 제대로 이해했는 지 모르겠습니다만,
    결론적으로 @controller에서 @ResponseBody를 사용해서 Json Data를 처리하다가, (Controller는 데이터와 뷰 처리를 하고)
    역할을 분리하여 @RestController에서는 json 데이터만 관리하고, controller에서는 view만 관리하게 된건가요?
    2021.07.07 07:06
  • 망나니개발자 넵 정확하게 이해하셨습니다:)
    과거에는 Spring에서 html이나 jsp 등과 같은 화면 렌더링까지 담당했었습니다. 하지만 이제는 백엔드와 프론트엔드를 완전히 분리하고, 백엔드에서는 API를 통해 json 포맷의 데이터 만을 반환하기 때문에 이를 보다 간편하게 개발하고자 @RestController가 등장하게 되었습니다!
    2021.07.07 11:07 신고
  • SSUK-GOD 궁금증 바로 해결하고 갑니다!! 혹시 출처를 남기고 저 나름대로 내용을 바꿔서 포스팅해도 될까요? 2021.07.13 20:36 신고
  • 망나니개발자 넵 괜찮습니다ㅎㅎ 출처만 남겨주세용:)
    감사합니다!!
    2021.07.13 21:11 신고
반응형
공지사항
Total
1,299,838
Today
240
Yesterday
3,635
TAG
more
«   2021/07   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함