728x90
HTTP 메시지 컨버터
- 뷰 템플릿으로 HTML을 생성해서 응답하는 것이 아니라, HTTP API처럼 JSON 데이터를 HTTP 메시지 바디에서 직접 읽거나 쓰는 경우 HTTP 메시지 컨버터를 사용하면 편하다.
- HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용된다.
- HTTP 요청 : @ReqeustBody, HttpEntity(RequestEntity)
- HTTP 응답 : @ResponseBody, HttpEntity(ResponseEntity)
💡 @ResponseBody 작동 원리
- @ResponseBody 사용 → HTTP의 바디에 문자 내용을 직접 반환
- viewResolver 대신에 HttpMessageConverter가 동작한다.
- 기본 문자 처리 : StringHttpMessageConverter
- 기본 객체 처리 : MappingJackson2HttpMessageConverter
- byte 처리 등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있다.
응답의 경우 클라이언트의 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해서 HttpMessageConverter가 선택된다.
🔍 HTTP 메시지 컨버터 인터페이스
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() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능을 담당한다.
🔍 스프링 부트 기본 메시지 컨버터 우선 순위
우선순위 | 기본 메시지 컨버터 |
0 | ByteArrayHttpMessageConverter |
1 | StringHttpMessageConverter |
2 | MappingJackson2HttpMessageConverter |
- 스프링 부트는 다양한 메시지 컨버터를 제공하는데 대상 클래스 타입과 미디어 타입 둘을 체그해서 어느 것을 사용할지 결정한다.
- 우선순위로 순서로 타입 체크가 진행된다.
🔍 주요 메시지 컨버터 종류
💡 ByteArrayHttpMessageConveter
- byte[] 데이터를 처리한다.
- 클래스 타입 : byte[]
- 미디어 타입 : */*
- 요청 예) @ReqeustBody byte[] data
- 응답 예) @ResponseBody return byte[]
- 쓰기 미디어 타입 : application/octet-stream
💡 StringHttpMessageConverter
- String 문자로 데이터를 처리한다.
- 클래스 타입 : String
- 미디어 타입 : */*
- 요청 예) @RequestBody String data
- 응답 예) @ResponseBody return "ok"
- 쓰기 미디어 타입 : text/plain
💡 MappingJackson2HttpMessageConverter
- 객체를 데이터로 처리한다.
- 클래스 타입 : 객체 또는 HashMap
- 미디어 타입 : application/json 관련
- 요청 예) @RequestBody HelloData data
- 응답 예) @ResponseBody return helloData
- 쓰기 미디어 타입 : application/json 관련
🔍 HTTP 요청 데이터 읽기
- 컨트롤러에서 @RequestBody, HttpEntity 파라미터 사용하여 HTTP 요청 데이터를 받는다.
- 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 메시지를 호출한다.
- 메시지 컨버터가 메시지를 읽을 수 있는지 없는지 조건 2가지
- 대상 클래스 타입을 지원하는가
- 예) @RequestBody의 대상 클래스 (byte[], String, HelloData)
- HTTP 요청의 Contetn-Type 미디어 타입을 지원하는가
- 예) text/plain, application/json, */*
- 대상 클래스 타입을 지원하는가
- canRead() 메서드의 조건이 모두 만족하면 read() 메서드를 호출해서 객체를 생성하고, 반환한다.
🔍 HTTP 응답 데이터 생성
- 컨트롤러에서 @ResponseBody, HttpEntity로 값이 반환된다.
- 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 메서드를 호출한다.
- 메시지 컨버터가 메시지를 쓸 수 있는지 없는지 조건 2가지
- 대상 클래스 타입을 지원하는가
- 예) return의 대상 클래스 (byte[], String, HelloDate)
- HTTP 요청의 Accept 미디어 타입을 지원하는가
- 예) text/plain, application/json, */*
- 대상 클래스 타입을 지원하는가
- canWrite() 메서드의 조건을 만족하면 write() 메서드를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다.
HTTP 메시지 컨버터 동작 방식
🔍 스프링 MVC에서 HTTP 메시지 컨버터의 위치는 어디에?
- HTTP 메시지 컨버터는 스프링 MVC구조에서 핸들러 어댑터 작동 구조에 포함되어 있다.
- @RequestMapping을 처리하는 핸들러 어댑터인 RequestMappingHandlerAdapter (요청 매핑 핸들러 어뎁터)의 동작 방식에 들어있다.
🔍 Http 메시지 컨버터 동작 방식
- 요청의 경우
- @RequestBody 애노테이션과 HttpEntity<T> 객체를 처리하는 ArgumentResolver가 있다.
- 이러한 ArugmentResolver들이 HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성한다.
- 응답의 경우
- @ResponseBody 애노테이션과 HttpEntity<T> 객체를 처리하는 ReturnValueHandler가 있다.
- ReturnValueHandler가 HTTP 메시지 컨버터를 호출해서 응답 결과를 만든다.
- @RequestBody / @ResponseBody가 있으면 RequestResponseBodyMethodProcessor를 사용한다.
- HttpEntity가 있으면 HttpEntityMethodProcessor를 사용한다.
🔍 요청 매핑 핸들러 어뎁터 구조 (RequestMappingHandlerAdapter)
- 애노테이션 기반의 컨트롤러는 다양한 파라미터를 사용할 수 있다.
- 예) HttpServletRequest / Model / @RequestParam / @ModelAttrbute / @RequestBody / HttpEntity 등등
- 이렇게 다양한 파라미터를 처리할 수 있는 이유는 ArgumentResolver 때문이다.
- 애노테이션 기반 컨트롤러를 처리하는 Request Mapping 핸들러 어댑터(RequestMappingHandlerAdaptor)는 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인데 줄여서 ArgumentResolver라고 부른다.
- ArgumentResolver의 supportsParameter() 메서드를 호출해서 해당 파라미터를 지원하는지 체크한다.
- 지원하면 resolveArgument() 메서드를 호출해서 실제 객체를 생성한다.
- 이렇게 생성된 객체는 컨트롤러 호출시 파라미터로 전달된다.
💡 ReturnValueHandler 동작 방식
- 정확히는 HandlerMethodReturnValueHandler인데 줄여서 ReturnValueHandler라고 부른다.
- ArgumentResovler와 비슷한데, ReturnValueHandler는 응답 값을 변환하고 처리한다.
- 예) ModelAndView / @ResponseBody / HttpEntity / String
✔ 참고사항
- 스프링은 아래의 3가지 인터페이스를 제공한다. 따라서 필요하면 언제든지 기능을 확장할 수 있다.
- HandlerMethodArgumentResolver / HandlerMethodReturnValueHandler / HttpMessageConverter
- 기능 확장시 WebMvcConfigurer를 상속 받아서 스프링 빈으로 등록하면 된다.
- 그러나 기능 확장할 일이 거의 없어 실제 자주 사용하지 않는다.
👀 참고 자료
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1#
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
728x90
'[ Spring ] > SpringMVC 1편' 카테고리의 다른 글
[Spring] MVC 웹 페이지 만들기 (0) | 2022.03.19 |
---|---|
[Spring] HTTP 응답을 보내는 방법 (정적 리소스 / 뷰 템플릿 / HTTP 메시지 ) (0) | 2022.02.26 |
[Spring] HTTP 요청을 받는 방법 (요청 파라미터 / HTTP 요청 메시지) (0) | 2022.02.25 |
[Spring] HTTP request 헤더 조회 (0) | 2022.02.25 |
[Spring] 기본 매핑 / 요청 매핑 (0) | 2022.02.25 |