본문 바로가기

스프링

@RequestBody, @ResponseBody

시작하기에 앞서,

@RequestParam은 요청 파라미터에 있는 값을 수신하여 저장했고,

@ModelAttribute는 폼에 있는 작성된 파라미터 값을 수신하여 저장했다.

그렇다면 실제 HTTP 통신이 이루어질 때, 메세지 바디에 담긴 메세지를 수신하고 송신하려면 어떻게 해야할까?

이를 위해 존재하는 것이 HttpEntity, Request(Response)Entity, @Requestbody, @ResponseBody이다.

근데 이것들은 이전에 배운 @RequestParam, @ModelAttribute와는 다르게 메세지 컨버터(Message Converter)를 사용한다.

메세지 컨버터는 메세지를 자바의 심플 타입 혹은 복합 타입에 매핑될 수 있도록 컨터빙해주는 역할을 한다.

이 과정이 실제로 언제, 어떻게 일어나는지 살펴보고 그 이후에 사용방법을 알아보자.

HTTP 메세지 송수신 원리

HTTP 메세지의 송수신 원리를 이해하기 위해 서버의 시작부터 보내는 것까지 천천히 알아보도록 하자.

(1) 서버 시작시 메세지 컨버터 등록

  • 우리가 서버를 키면 WebMvcConfigurationSupport에서 지원하는 메세지 컨버터들과 우리가 실제로 인터페이스를 확장하여 우리가 추가한 Custom 메세지 컨버터들을 등록해준다.

(2) 사용자의 요청

  • 사용자가 임의의 요청을 진행하게 되고 HTTP 통신을 통해 서버에 전달된다.

(3) 핸들러와 핸들러 어댑터 꺼내기

  • DispatcherServlet에서 DispatcherServlet에서 이에 맞는 핸들러와 핸들러 어댑터를 꺼내온다.

  • (RequestMapping에 대한 자세한 이해가 없다면 RequestMapping에서 확인)


(4) 핸들러 어댑터 handle 메소드 실행

  • 핸들러 어댑터로 handle을 진행하여 찾아진 HandlerMethod로 진행한다.

(5) 핸들러메소드 실행

  • 실제로 핸들러 메소드를 실행한다.
  • 그러기 위해 실행가능한 핸들러메소드에서 invokeAndHandle을 진행해주고 필요한 정보를 invokeForRequest로 받아온다.

(6) Argument Value 추출하기

  • 여기서 실제로 우리가 메소드에서 필요로하는 파라미터를 받아온다.

  • 우리는 실행할 때, 여러 Argument Resolver들을 등록하는데 그 중에서 지원하는지 체크를 한 뒤 지원되는 resolver로 실행한다.

  • 우리는 현재 @RequestBody를 사용하고 있기에 해당 애노테이션을 통해 파라미터를 받을 수 있는 Resolver인 RequestResponseBodyMethodProcessor를 통해 받아온다.

  • 실제로 추후에 설명하겠지만 return 하기 위해 쓸 때는 RequestResponseBodyMethodProcessorhandleReturnValue 메소드를 통해 컨버팅 후 전송한다.

간단히 정리해보면, 우리가 핸들러와 핸들러 어댑터를 찾고 Argument Resolver를 통해 파라미터를 찾는 중 우리가 HttpEntity, RequestEntity, @RequestBody 혹은 HttpEntity, ResponseEntity, @ResponseBody가 존재한다면 RequestResponseBodyMethodProcessor라는 Argument Resolver가 실행되어 메세지 컨버터를 통해 송수신된다는 것이다.

그러면, 메세지 컨버터를 통해 가능한 타입이 많지만 우리가 대표적으로 사용하는 3가지에 대해 알아보면 다음과 같다.

  • 수신과 송신에 있는 타입이 맞을 경우에 해당 컨버터를 선택한다.
  • 선택된 컨버터를 이용해 결과를 반환하지만, 어떤 컨버터도 채택되지 않는다면 오류가 발생한다.

HTTP 메세지 송수신 사용

(1) HttpEntity

(1) String

@Slf4j
@Controller
public class request_mapping {

    @RequestMapping("/request_mapping")
    public HttpEntity<String> visit(HttpEntity<String> person) {

        return new HttpEntity<>(person.getBody());
    }
}

(2) Json

@Slf4j
@Controller
public class request_mapping {

    @RequestMapping("/request_mapping")
    public HttpEntity<String> visit(HttpEntity<Person> person) {

        return new HttpEntity<>(person.getBody().getName() + ", " + person.getBody().getAge());
    }
}

  • HttpEntiy 객체를 선언하여 메세지를 송수신할 수 있다.

(2) RequestEntity

(1) String

@Slf4j
@Controller
@ResponseBody
public class request_mapping {

    @RequestMapping("/request_mapping")
    public ResponseEntity<String> visit(RequestEntity<String> person) {

        return new ResponseEntity<>(person.getBody(), HttpStatus.ACCEPTED);
    }
}

(2) Json

@Slf4j
@Controller
public class request_mapping {

    @RequestMapping("/request_mapping")
    public ResponseEntity<String> visit(RequestEntity<Person> person) {

        return new ResponseEntity<>(person.getBody().getName() + ", " + person.getBody().getAge(), HttpStatus.ACCEPTED);
    }
}

  • RequestEntity 객체를 선언하여 메세지를 수신할 수 있다.
  • ResponseEntity 객체를 선언하여 메세지를 송신할 수 있다.
  • ResponseEntity 객체를 사용할 때 두번째 파라미터 값에 HTTP 상태 코드 값을 기입한다.

(3) Requestbody

(1) String

@Slf4j
@Controller
public class request_mapping {

    @ResponseBody
    @RequestMapping("/request_mapping")
    public String visit(@RequestBody String person) {

        return person;
    }
}

(2) Json

@Slf4j
@Controller
public class request_mapping {

    @ResponseBody
    @RequestMapping("/request_mapping")
    public Person visit(@RequestBody Person person) {

        return person;
    }
}

  • @RequestBody 애노테이션을 통해 문자열은 문자열, 객체는 객체로 매핑하여 메세지를 수신한다.
  • @ResponseBody 애노테이션을 통해 문자열 혹은 객체 그 상태로 메세지를 송신한다.
  • 객체의 경우 메세지 컨버터가 자동으로 Json으로 변경해준다.

'스프링' 카테고리의 다른 글

[Thymeleaf] 연산, 속성값  (0) 2021.09.22
[Thymeleaf] 텍스트, spring EL, 객체, URL 링크, 리터럴  (0) 2021.09.22
@ModelAttribute  (0) 2021.09.20
@RequestParam  (0) 2021.09.20
RequestMapping  (0) 2021.09.20