Programming-[Backend]/Spring

[스프링 웹MVC] 13. 스프링 MVC - HTTP 메시지 컨버터, 요청 매핑 핸들러 어댑터 구조

컴퓨터 탐험가 찰리 2021. 8. 14. 10:37
728x90
반응형

 

 

1. 메시지 컨버터

 

 

메시지 컨버터는 HTTP 요청 body를 원하는 타입으로 변환하거나, HTTP 응답으로 뷰 템플릿을 전송하는 것이 아니라 JSON 객체 등으로 HTTP body에 직접 메시지를 쓰는 경우에 사용한다. 구체적으로, ViewResolver 대신 HttpMessageConverter가 적용된다. 스프링부트에서는 앞서 살펴보았던 @RequestBody, @ResponseBody, HttpEntity 등이 적용되어 body가 송수신되는 경우에 메시지 컨버터가 적용된다.

 

HttpMessageConverter를 상속하여 여러가지 타입의 데이터 메시지를 처리하는 다양한 컨터버 클래스들이 존재한다. 대표적인 컨버터들은 다음과 같다. 위쪽 컨버터부터 순서대로 작동한다.

 


ByteArrayHttpMessageConverter

Http의 byte[] 메시지를 처리한다. 클래스 타입은 byte[], 미디어타입은 */*(전체) 이다.

 

StringHttpMessageConverter

String 문자로 데이터를 처리한다. 클래스 타입은 String, 미디어타입은 */* 이다.

 

MappingJackson2HttpMessageConverter

application/json 데이터를 처리한다. 클래스 타입은 지정한 객체 또는 HashMap, 미디어 타입은 application/json 관련 이다.

 


메시지 컨버터는 요청과 응답에 각각 canRead(), canWrite() 메서드를 적용하여 변환 가능 여부를 판단하고 객체를 생성하여 반환한다. ByteArrayHttpMessageConverter에서 canRead 메서드를 적용했는데 Http 요청 클래스가 byte가 아니면 다음 StringHttpMessageConverter로 넘어가서 처리되는 방식으로 실행된다. 예를 들어 요청의 경우 컨트롤러에서 @RequestBody, HttpEntity 등의 객체가 있는지 확인하고 byte[], String, 지정한 타입의 객체 타입인지 순서대로 확인 후 위에서 살펴본 미디어 타입들을 지원하는지 확인하여 객체 생성을 진행하고 반환하게 되는 것이다. 응답도 컨트롤러에서 @ResponseBody, HttpEntity로 반환된 값을 바탕으로 요청과 같은 단계를 거쳐 응답 메시지 바디를 생성하게 된다.

 

 

 


 

 

2. RequestMappingHandlerAdapter 구조

 

 

메시지 컨버터가 HTTP 요청의 클래스와 타입을 조회하고 핸들러에서 처리할 수 있도록 변환해주고, HTTP 응답에도 사용할 수 있도록 값을 변환해준다는 것을 배웠다. 이 메시지 컨버터는 아래 스프링 MVC 도식에서 표현된 핸들러어댑터인 RequestMappingHandlerAdapter에서 사용된다. 

스프링MVC의 구조

 

RequestMappingHandlerAdapter의 작동 방식

 

- ArgumentResolver, ReturnValueHandler의 HTTP 메시지 처리

 

RequestMappingHandlerAdapter에서는 HTTP 요청값을 읽어들여서 핸들러의 파라미터로 전달해주는 역할을 하는 ArgumentResolver가 동작한다. 예를 들어, 다음 컨트롤러 2개만 보더라도 HttpServletRequest, InputStream 타입을 파라미터로 요구하는데, 바이트로된 HTTP 요청 메시지에서 이런 타입들로 변환하여 컨트롤러에게 인자(Argument)로 전달해주어야 한다. HttpServletRequest, Model, @RequestParam, @ModelAttribute, @RequestBody, HttpEntity 등 모든 파라미터를 변환하여 인자로 전달해주는 역할을 하는 것이다.

 

응답데이터는 ReturnValueHandler가 생성한다. 이때도 마찬가지로 메시지 컨버터를 이용하여 HTTP 요청의 Header부분의 Accept 정보를 기반으로, 클라이언트가 받을 수 있는 데이터 타입이 무엇인지 확인하고 그에 맞는 HTTP 메시지를 전달하게 된다.

 

1
2
3
4
5
6
7
8
9
10
@PostMapping("/request-body-string-v1")
    public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ......
    }
 
    @PostMapping("/request-body-string-v2")
    public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
        ......
    }
 
cs

 

 

여러 타입의 요청과 응답에 대해 많은 타입의 ArugmentResolver, ReturnValueHandler가 존재한다. IDE에서 각 인터페이스와 구현체를 따라가보면 복잡한 코드가 작성되어 있지만, 핵심은 위에 설명한 원리와 메서드들을 사용한다는 것이기 때문에 향후 문제가 발생하면 배운 내용을 바탕으로 원인을 유추해나가면 될 것 같다. 필요하다면(그럴 일이 거의 없겠지만), WebMvcConfigurer를 상속받아서 아래와 같이 확장할 수도 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean
public WebMvcConfigurer wevMvcConfigurer() {
  return new WebMvcConfigurer() {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
      ...
    }
 
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
      ...
    }
  };
}
cs

 

 

 

 


 

참조

 

 

1. 인프런_스프링 MVC 1편 - 백엔드 웹개발 핵심 기술_김영한 님 강의

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

728x90
반응형