Spring/series

[spring 4편] spring http message convert 설명 (RequestBody, ResponseBody)

무대포 개발자 2021. 6. 12. 17:36
728x90
반응형

목차는 spring series 목차 에 있습니다.

spring http message convert 설명

  • spring 에서 client 와 server 간 데이터를 주고 받을 때, 데이터를 어떻게 주고 받는지에 대해서 공부했습니다.
  • 아래 예시는 spring mvc + json 기준입니다.

client 에서 server 로 request 를 보낼 때 메시지 변환 과정

  • client 에서 json 데이터를 네트워크를 통해 보낼 때, server 의 spring 엔진 에서는 데이터 header 부분의 'Content-type' 을 살펴봅니다.
  • spring 은 'Content-type' 을 보고, HttpMessageConverter 구현체를 찾기 시작합니다.
  • HttpMessageConverter 구현체는 client 에서 보낸 body (데이터) 를 자바로 변환해줍니다.
  • 변환 과정을 순서대로 나열한 예시는 다음과 같습니다.
    • client 에서 /test GET Method 를 호출했습니다. (conetent-type = 'application/json')
    • spring 엔진에서는 json 에 맞는 MessageConverter 를 찾아 자바로 컨버팅 해줍니다. 이것을 Unmarshal 이라고 합니다.
    • Unmarshal 은 직렬화된 (byte) 것을 오브젝트로 (자바 객체) 변환하는 것을 의미합니다.

변환 소스

  • 아래 소스를 보면 messageConverters 를 for 문으로 돌리면서 canRead 메소드를 수행하여 적절한 MessageConverter 를 찾습니다.
  • canRead 메소드 또한 제공하고 있는 mediaTypes 조회해서 적절한 mediaType 을 찾습니다.

@Override
@SuppressWarnings({"unchecked", "rawtypes", "resource"})
public T extractData(ClientHttpResponse response) throws IOException {
    MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
    if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
        return null;
    }
    MediaType contentType = getContentType(responseWrapper);

    try {
        for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
            if (messageConverter instanceof GenericHttpMessageConverter) {
                GenericHttpMessageConverter<?> genericMessageConverter =
                        (GenericHttpMessageConverter<?>) messageConverter;
                if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
                    if (logger.isDebugEnabled()) {
                        ResolvableType resolvableType = ResolvableType.forType(this.responseType);
                        logger.debug("Reading to [" + resolvableType + "]");
                    }
                    return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
                }
            }
            if (this.responseClass != null) {
                if (messageConverter.canRead(this.responseClass, contentType)) {
                    if (logger.isDebugEnabled()) {
                        String className = this.responseClass.getName();
                        logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");
                    }
                    return (T) messageConverter.read((Class) this.responseClass, responseWrapper);
                }
            }
        }
    }


    protected boolean canRead(@Nullable MediaType mediaType) {
        if (mediaType == null) {
            return true;
        }
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.includes(mediaType)) {
                return true;
            }
        }
        return false;
    }

server 에서 client 로 response 보낼 때 메시지 변환 과정

  • server 에서 client 로 json 데이터를 보낼려 할 때, server 의 spring 엔진에서는 request 에 담겨진 header 의 'Accept' 를 살펴봅니다.
  • spring 엔진에서는 이 정보를 통해 response 를 어떤 MessageConvert 를 이용해서 데이터를 보낼지 결정합니다.
  • 이를 marshal 이라고 하며, 오브젝트를 (자바 객체) 직렬화하는 (byte) 것입니다.

spring @RequestBody, @ResponseBody

@RequestBody

  • 해당 annotation 은 Http Request body 를 특정 자바 객체로 비직렬화 (unmarshal) 하겠다는 의미입니다.
  • 적절한 message converter 를 찾기 위해 header 의 'Content-type' 을 참조합니다.

@ResponseBody

  • 해당 annotation 은 반환할 값을 Http Response 의 body 로 serialzed 하겠다는 의미입니다.
  • 적절한 message converter 를 찾기 위해 header 의 'Accept' 를 참조합니다.

RestController

  • 위 설명과 별개로 Controller 와 ResponseBody 를 합친게 RestController 입니다.
  • RestController 를 선언하면 별도 ResponseBody 는 필요없습니다.

Reference