- Spring MVC 마스터하기 42022년 04월 24일
- starryeye
- 작성자
- 2022.04.24.:57
HTTP 메시지 컨버터에 대하여 알아보자
컨트롤러가 응답을 하는데는 3가지 종류가 있다.
ㄱ. 정적 리소스 응답
ㄴ. 뷰 템플릿을 사용한 응답
ㄷ. HTTP Message Body에 직접 데이터를 넣어 응답
이 중에서 뷰 템플릿을 사용한 응답은..
그림과 같이 viewResolver가 문자열(hello-template)로 반환된 논리적 뷰 이름으로 뷰를 찾아준다.
(Thymeleaf의 경우 viewResolver는 ThymeleafViewResolver 이다.)
뷰가 동적으로 렌더링 되어 HTML로 생성되고 웹브라우저에게 응답으로 내려준다.
하지만, HTTP Message Body에 직접 데이터를 넣어 응답 해주는 경우에는..
위와 같이 @ResponseBody가 사용되며, viewResolver가 사용되지 않는다.
viewResolver 대신에 HttpMessageConverter가 사용된다.
-> 기본 문자 처리의 경우, StringHttpMessageConverter
-> 기본 객체 처리의 경우, MappingJackson2HttpMessageConverter (json)
HttpMessageConverter
뷰 템플릿으로 HTML을 생성해서 응답하는 것이 아니라, Json 데이터를 HTTP 메시지 바디에서 직접 읽거나 쓰는 경우, HTTP 메시지 컨버터를 사용하면 편리하다. (들어올때도 나갈때도 적용)
ex)
Json으로 요청 데이터가 들어옴 -> HttpMessageConverter -> 객체로 만들어줌
컨트롤러에서 객체 return -> HttpMessageConverter -> Json으로 응답 데이터 나감
HttpMessageConverter를 안 쓰는 경우, Stream을 읽어서 직접 변환 해줘야 한다.. 잠깐 보자
위 예제는
요청데이터 바디에 Json 데이터가 존재하는 경우이다.
HttpServletRequest의 getInputStream 메서드를 사용하여 Steam으로 받는다.
받은 Stream을 UTF-8로 인코딩 해주고, String 타입으로 다시 받는다.
String 타입의 요청 바디를 ObjectMapper를 통하여 객체(HelloData.class)로 변환 한다.
응답으로는 HttpServletResponse의 getWriter 메서드를 사용하여 String(ok) 을 반환한다.
HttpMessageConverter를 사용하지 않은 경우는 위와 같이 굉장히 불편하다.
스프링 MVC가 HTTP 메시지 컨버터를 적용하는 경우
HTTP 요청 : @RequestBody, HttpEntity(RequestEntity)
HTTP 응답 : @ResponseBody, HttpEntity(ResponseEntity)
HTTP 메세지 컨버터 인터페이스
public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); List<MediaType> getSupportedMediaTypes(); default List<MediaType> getSupportedMediaTypes(Class<?> clazz) { return (canRead(clazz, null) || canWrite(clazz, null) ? getSupportedMediaTypes() : Collections.emptyList()); } T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
HTTP 메시지 컨버터는 요청과 응답 모두에 사용된다.
canRead(), canWrite() : 메시지 컨버터가 대상이 되는 메시지의 클래스, 미디어 타입을 지원하는지 체크
read(), write() : 메시지 컨버터를 통하여 메시지를 읽고 쓰는 기능
이 인터페이스를 구현한 구현 객체가 바로,
StringHttpMessageConverter, MappingJackson2HttpMessageConverter 등 이다.
스프링 부트의 주요한 메시지 컨버터 순위
1순위 : ByteArrayHttpMessageConverter
-> 클래스 타입 : Byte[]
-> 미디어 타입 : */*
2순위 : StringHttpMessageConverter
-> 클래스 타입 : String
-> 미디어 타입 : */*
3순위 : MappingJackson2HttpMessageConverter
-> 클래스 타입 : 객체 또는 HashMap
-> 미디어 타입 : application/json
(모두 해당 안되면 에러)
<클래스 타입>
요청의 경우, Controller의 @RequestBody의 대상 클래스 타입
응답의 경우, Controller의 return 타입
<미디어 타입>
요청의 경우, HTTP 요청의 Content-Type
응답의 경우, HTTP 요청의 Accept (@RequestMapping의 produces 요소)
메시지 컨버터 동작 순서 예시 (요청)
매핑된 Controller에 @RequestBody가 적용되어있다.
-> 메시지 컨버터 동작
-> 매핑된 Controller의 파라미터가 (@RequestBody String data) 로 되어있다.
-> Byte 메시지 컨버터의 canRead() 호출
-> 탈락
-> String 메시지 컨버터의 canRead() 호출
-> 파라미터 타입이 String이라 성공
-> 요청 데이터의 미디어 타입이 application/json 이다.
-> */* 에 포함 되므로 성공
-> StringHttpMessageConverter가 동작한다.
-> read()를 호출하여 메시지 바디를 String 타입으로 변환하여 Controller 파라미터에 넣어준다.
RequestMappingHandlerAdapter
에노테이션 기반의 컨트롤러를 사용하면, 핸들러 어댑터는 RequestMappingHandlerAdapter가 사용된다.
(핸들러 매핑은 RequestMappingHandlerMapping)
RequestMappingHandlerAdapter는 매우 다양한 파라미터 타입과, return 타입을 처리 할 수 있다.
HandlerMethodArgumentResolver (인터페이스)
HandlerMethodArgumentResolver는 매핑된 컨트롤러가 필요로 하는 다양한 파라미터를 생성해준다.
(HttpServletRequest, Model, @RequestParam, @ModelAttribute, @RequestBody, HttpEntity 등)
ex. HttpServletRequest를 생성해주는 HandlerMethodArgumentResolver가 있다
public interface HandlerMethodArgumentResolver { boolean supportsParameter(MethodParameter parameter); @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception; }
RequestMappingHandlerAdapter가 HandlerMethodArgumentResolver의 supportsParameter 메서드를 호출하여 해당 파라미터를 지원하는지 체크한다.
(등록된 모든 HandlerMethodArgumentResolver의 supportsParameter 메서드가 호출 된다, 루프)
지원하면 RequestMappingHandlerAdapter가 HandlerMethodArgumentResolver의 resolveArgument 메서드를 호출하여해당 파라미터의 타입 객체를 생성하며 반환한다.
HandlerMethodReturnValueHandler (인터페이스)
HandlerMethodReturnValueHandler는 매핑된 컨트롤러의 return 값을 처리해준다.
( ModelAndView, @ResponseBody, HttpEntity, String 등)
public interface HandlerMethodReturnValueHandler { boolean supportsReturnType(MethodParameter returnType); void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
supportsReturnType : 매핑된 핸들러가 해당 리턴 타입을 지원하는가 체크
(등록된 모든 HandlerMethodReturnValueHandler의 supportsReturnType 메서드가 호출 된다, 루프)
handleReturnValue : return 값을 model에 넣어주며, 뷰를 셋팅 해준다.
HTTP Message Conveter
HandlerMethodArgumentResolver 와 HandlerMethodReturnValueHandler 가 사용한다.
요청에서는 실제 필요한 객체를 생성해준다.
RequestMappingHandlerAdapter는 여러개의 HandlerMethodArgumentResolver 를 가진다.
HandlerMethodArgumentResolver는 여러개의 HttpMessageConverter를 가진다.
응답에서는 응답 결과를 만들어준다.
RequestMappingHandlerAdapter는 여러개의 HandlerMethodReturnValueHandler 를 가진다.
HandlerMethodReturnValueHandler는 여러개의 HttpMessageConverter를 가진다.
<요청 예시>
1. RequestMappingHandlerAdapter는 등록된 HandlerMethodArgumentResolver 들을 돌려서 매핑된 Controller가 필요한 파라미터를 지원하는 HandlerMethodArgumentResolver 를 찾는다. (supportsParameter)
2. 매핑된 HandlerMethodArgumentResolver는 등록된 HttpMessageConverter들을 돌려서 클래스타입, 미디어 타입을 보고 HttpMessageConverter를 찾는다. (canRead)
3. 필요한 타입을 생성 후 반환 (Read)
'Spring > MVC' 카테고리의 다른 글
Spring MVC 마스터하기 Validation 1 (0) 2022.05.08 Spring MVC Redirect, PRG (0) 2022.05.06 Spring MVC 마스터하기 3 (응답 부분) (0) 2022.04.22 Spring MVC 마스터하기 2 (요청 부분) (0) 2022.04.19 Spring MVC 마스터하기 1 (0) 2022.04.17 다음글이전글이전 글이 없습니다.댓글