이번에는 이전부터 계속 언급이 되었던 HTTP 메시지 컨버터에 대해 알아보려고 한다.
스프링 MVC는 메시지 바디에 맞춰서 알맞게 메시지 컨버터를 적용한다.
메시지 컨버터 구조
메시지 컨버터는 인터페이스로 이루어져있다.
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;
}
canRead()
와canWrite()
를 통해서 메시지 컨버터가 해당 클래스, 미디어 타입을 지원하는지 체크할 수 있다.read()
와write()
를 통해서 메시지 컨버터가 메시지를 읽고 쓸 수 있다.
동작
기본적으로 HTTP 메시지 컨버터는 요청과 응답에 둘 다 사용된다.
- HTTP 요청
- 먼저 HTTP 요청이 들어오면 @RequestBody, HttpEntity 를 이용하여 요청 파라미터를 처리한다.
- 메시지 컨버터가 메시지를 읽을 수 있는지를 확인하기 위해
canRead()
를 호출한다.- 클래스 타입을 지원하는지 확인 (byte[], String 혹은 직접만든 객체)
- 미디어 타입(Content-Type)을 지원하는지 확인 (text/plain, application/json, /)
canRead()
조건에 만족되면read()
를 통해 객체를 생성하고 반환하게 된다.
- HTTP 응답
- 컨트롤러를 통해서 @ResponseBody, HttpEntity 파라미터를 통해 넘어온 데이터를 처리한다.
- 메시지 컨버터가 메시지를 쓸 수 있는지를 확인하기 위해서
canWirte()
를 호출한다.- 클래스 타입을 지원하는지 확인 (byte[], String 혹은 직접만든 객체)
- 요청의 미디어 타입(Accept)을 지원하는지 확인 (text/plain, application/json, /)
- @RequestMapping의 produces 속성*
canWrite()
조건에 만족되면write()
를 호출해 응답 메시지 바디에 데이터를 생성한다.
종류
- 스프링 부트는 기본적으로 다음과 같은 메시지 컨버터를 제공한다.
ByteArrayHttpMessageConverter
- 클래스 타입 :
byte[]
/ 미디어 타입 : `/**`
- 클래스 타입 :
StringHttpMessageConverter
- 클래스 타입 :
String
/ 미디어 타입 :*/*
- 클래스 타입 :
MappingJackson2HttpMessageConverter
- 클래스 타입 :
Object
또는HashMap
/ 미디어타입 :application/json
- 클래스 타입 :
- … 등등
각 클래스 타입, 미디어 타입에 알맞는 메시지 컨버터가 선택되어 처리하게 된다.
그렇다면 이러한 메시지 컨버터는 어디서 실행이 되는 걸까?
그 위치는 바로 핸들러 어댑터 쪽에 있다.
애노테이션 기반의 컨트롤러를 매핑해주는 RequestMappingHandlerAdapter는 ArgumentResolver를 통해서 다양한 값을 처리 할 수 있도록 도와준다.
ArgumentResolver
ArgumentResolver는 컨트롤러의 요청 값을 변환하고 처리하는 기능을 담당한다.
어노테이션 기반의 컨트롤러는 매우 다양한 파라미터를 사용할 수 있다.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
정확한 이름은 HandlerMethodArgumentResolver로 인터페이스로 구현되어 있다.
- 처리할 수 있는 값의 종류로는 아래와 같다.
HttpServletRequest
HttpEntity
Model
@RequestBody
@RequestParam
@ModelAttribute
supportsParameter()
를 호출하여 해당 파라미터를 지원하는지 체크하고, resolveArgument()
를 통해서 실제 객체를 생성한다.
이와 같은 맥락으로 응답을 처리하는 ReturnValueHandler가 있다.
ReturnValueHandler
ArgumentResolver와 비슷하지만 ReturnValueHandler는 응답 값을 변환하고 처리하는 기능을 담당한다.
응답 값으로 변환 가능한 값으로는 아래처럼 여러 형식을 지원한다.
ModelandView
@Responsebody
HttpEntity
String
등
컨트롤러에서 view 이름을 반환해도 웹이 동작하는 것이 바로 이 ReturnValueHandler
덕분이다.
위와 같은 ArgumentResolver와 ReturnValueHandler가 메시지 컨버터를 사용해 필요한 객체를 생성하고 값을 반환하거나 응답결과를 만들게 된다.
참고로 위 기능들은 인터페이스이기 때문에 확장도 가능하다.
물론 대부분의 기능을 스프링에서 기본적으로 제공하기 때문에 크게 필요는 없지만 WebMvcConfigurer 를 통해서 확장이 가능하다는 것을 알아두자.
참고 - https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1
'Spring' 카테고리의 다른 글
[Spring] @Transactional 에 대해서 (1) | 2024.04.24 |
---|---|
[Spring] AOP와 Proxy (0) | 2024.04.01 |
[SpringMVC] HTTP 요청, 응답처리 (0) | 2022.05.23 |
[SpringMVC] 매핑 (Mapping) (0) | 2022.05.23 |
[SpringMVC] 로깅 (Logging) (0) | 2022.05.23 |