Web/Spring

[Inflearn] 스프링 MVC (7) HttpMessageConverter

UL :) 2022. 2. 4. 00:46

김영한 강사님의 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 강의 정리

2022.02.06~02.07 진행

강의를 듣고 개인적으로 정리한 글입니다. 코드와 그림 출처는 김영한 강사님께 있습니다. 문제 있을 시 알려주세요.

 

언제 HttpMessageConverter 가 적용되는가

스프링 MVC는 다음의 경우에 viewResolver 대신 HttpMessageConverter를 적용한다.

  • HTTP 요청 : @RequestBody, HttpEntity(RequestEntity)
  • HTTP 응답 : @ResponseBody, HttpEntity(ResponseEntity)

 

HttpMessageConverter 동작과정

HTTPMessageConverter 인터페이스를 간략히 알아보자면, 다음과 같다.

package org.springframework.http.converter;

public interface HttpMessageConverter<T> {

    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

    List<MediaType> getSupportedMediaTypes();

    T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}

HTTP 요청/응답이 오고, 컨트롤러에서 HttpMessageConverter가 적용되면

  • canRead()canWrite()을 호출해 대상 클래스 타입미디어 타입을 체크한다.
    • HTTP 요청: @RequestBody의 대상 클래스(파라미터) 체크, 요청의 Content-type을 지원하는가 체크
    • HTTP 응답: return 의 대상 클래스 체크, 응답의 Accept를 지원하는가 체크
  • 조건을 만족하면
    • HTTP 요청: read()를 호출해서 객체를 생성 및 반환
    • HTTP 응답: write()를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성
  • 만족하지 않으면 다음 메시지 컨버터로 우선순위가 넘어간다.

 

스프링 부트가 제공하는 메시지 컨버터

스프링 부트는 다음과 같이 다양한 메시지 컨버터를 제공한다. 숫자가 작은 순으로 우선순위가 높다.

0 = ByteArrayHttpMessageConverter
1 = StringHttpMessageConverter
2 = MappingJackson2HttpMessageConverter
  • ByteArrayHttpMessageConverter
    • 클래스 타입: byte[]
    • 미디어 타입: */*
    • 응답시 미디어 타입: application/octet-stream
  • StringHttpMessageConverter
    • 클래스 타입: String
    • 미디어 타입: */*
    • 응답시 미디어 타입: text/plain
  • MappingJackson2HttpMessageConverter
    • 클래스 타입: 객체 또는 HashMap
    • 미디어 타입: application/json 관련
    • 응답시 미디어 타입: application/json 관련

 

ArgumentResolver와 ReturnValueHandler

애노테이션 기반 컨트롤러가 매우 다양한 파라미터를 사용할 수 있는 이유ArgumentResolver 이다.

  • 애노테이션 기반 컨트롤러를 처리하는 RequestMappingHandlerAdaptorHandlerMethodArgumentResolver를 호출해서 컨트롤러(핸들러)가 필요로하는 다양한 파라미터의 값(객체)을 생성한다. 파라미터의 값이 모두 준비되면 컨트롤러를 호출하면서 값을 넘겨준다.
  • 스프링은 30개가 넘는 ArgumentResolver를 기본으로 제공한다. [https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-annarguments]
public interface HandlerMethodArgumentResolver {

    boolean supportsParameter(MethodParameter parameter);

    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}
  • 동작방식 : ArgumentResolver의 suppoertsParameter()를 호출해서 해당 파라미터를 지원하는지 체크한다. 지원하면 resolveArgument()를 호출해서 실제 객체를 생성하고, 이 객체는 컨트롤러 호출시 넘어간다.
    • 이 인터페이스를 확장해서 원하는 ArgumentResolver를 만들 수도 있다.

기능확장은 생략 (WebMvcConfigurer 상속)

반대로 응답 값을 변환하고 처리하는 것은 ReturnValueHandler 이다. ModelView로 반환하든 String으로 반환하든 동작하는 이유가 이것 덕분이다.

 

HttpMessageConverter가 사용되는 위치

HttpMessageConverter를 사용하는 @RequestBody@ResponseBody는 각각 컨트롤러가 필요로 하는 파라미터 값, 반환 값에 사용된다. 따라서

  • 요청의 경우 @RequestBodyHttpEntity를 처리하는 ArgumentResolver가 HttpMessageConverter를 사용해서 필요한 객체를 생성한다.
  • 응답의 경우 @ResponseBodyHttpEntity를 처리하는 ArgumentResolver가 HttpMessageConverter를 사용해서 응답결과를 생성한다.