HTTP 메세지 컨버터

OneTwoThree·2023년 10월 7일
0

스프링mvc1

목록 보기
5/5

출처 : 김영한 님 강의


스프링 MVC는 다음 경우에 HTTP 메세지 컨버터를 적용한다
HTTP 요청 : @RequestBody,HttpEntity(RequestEntity)
HTTP 응답 : @ResponseBody, HttpEntity(ResponseEntity)
즉 HTTP 바디에서 직접 메세지를 읽거나 쓸 때 사용한다.

HTTP 메세지 컨버터 인터페이스가 있다.
HTTP 요청, 응답에 둘다 사용된다.

canRead와 canWrite는 메세지 컨버터가 해당 미디어타입을 지원하는지 체크한다.
read, write를 통해 메세지를 읽고 쓸 수 있다.

스프링부트 기본 메세지 컨버터들과 우선순위는 위와 같다.
대상 클래스 타입, 미디어 타입을 체크해서 사용여부를 결정한다.
만족하지 않으면 다음 메세지 컨버터로 우선순위가 넘어간다.

ByteArrayHttpMessageConverter는
클래스타입 : byte[], 미디어타입 : */*
StringHttpMessageConverter는
클래스타입 : String , 미디어타입 : */*
MappingJackson2HttpMessageConverter는
클래스타입 : 객체, HashMap, 미디어타입 : application/json
일 때 동작한다.

HTTP 요청 데이터를 읽을 때는 컨트롤러에서 @RequestBody HttpEntity 파라미터를 사용할 때 동작한다.

메세지 컨버터가 메세지를 읽을 수 있는지 확인하기 위해 canRead()를 호출한다.(클래스타입과 HTTP요청의 미디어 타입을 지원하는지)
canRead()를 만족하면 read()를 호출해서 객체를 생성하고 반환한다.

HTTP 응답 데이터를 생성할 때는 컨트롤러에서 @ResponseBody, HttpEntity로 값을 반환한다.
마찬가지로 클래스 타입과 HTTP 요청의 Accept 미디어 타입을 지원하는지 확인하기 위해 canWrite()를 호출한다.
조건을 만족하면 write()를 호출해서 HTTP 응답 메세지 바디에 데이터를 생성한다.


✅ ArgumentResolver

@RequestMapping을 처리하는 핸들러 어댑터인 (애노테이션 기반의 컨트롤러를 처리하는) RequestMappingHandlerAdapter는 위와 같이 동작한다.

애노테이션 기반의 컨트롤러는 매우 다양한 파라미터를 사용할 수 있는데, ArgumentResolver 덕분이다.
RequestMappingHanlderAdapter는 ArgumentResolver를 통해서 컨트롤러가 필요로 하는 다양한 파라미터의 값을 생성한다.

스프링에는 다양한 종류의 ArgumentResolver가 있다.

ArgumentResolver 인터페이스는 위와 같다.
supportsParameter로 파라미터를 지원하는지 확인한다.
지원하면 resolveArgument를 호출해서 실제 객체를 생성한다.
이렇게 생성된 객체가 컨트롤러 호출 시 넘어간다.

인터페이스를 확장해서 원하는 ArgumentResolver를 만들 수 있다.

@Component
@RequiredArgsConstructor
public class LoggedInArgumentResolver implements HandlerMethodArgumentResolver {

    private final JwtTokenProvider jwtTokenProvider;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(LoggedInMember.class)
                && Long.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String headerAuthorization = webRequest.getHeader(HttpHeaders.AUTHORIZATION);
        LoggedInMember loggedInMember = parameter.getParameterAnnotation(LoggedInMember.class);
        if (!loggedInMember.required() && headerAuthorization == null) {
            return null;
        }
        validExistAccessTokenInHeader(headerAuthorization);
        String accessToken = headerAuthorization.split(" ")[1];
        return jwtTokenProvider.getMemberId(accessToken);
    }

    private void validExistAccessTokenInHeader(String headerAuthorization) {
        if(headerAuthorization == null) throw new NotExistAccessTokenException();
    }

}

프로젝트에서 로그인을 맡은 팀원이 작성한 ArgumentResolver이다.
supportsParameter에서 파라미터에 로그인 한 멤버를 나타내는 애노테이션인 @LoggedInMember가 있는지 확인한다.
조건을 만족하면 resolveArgument로 넘어간다. ResolveArgument에서는 원하는 값을 반환해준다. 위 예시의 경우 애노테이션의 required 속성값이 false고 헤더에 토큰이 없으면 null을 반환한다.
아닐 경우 헤더에서 값을 가져와서 memberId를 반환한다.

✅ ReturnValueHandler

HandlerMethodArgumentResolver를 줄여서 ReturnValueHandler라 부른다.
ArgumentResolver와 비슷한데 응답 값을 변환하고 처리한다.

✅ Http 메세지 컨버터

HTTP 메세지 컨버터는 ArgumentResolver와 ReturnValueHandler에서 쓰인다.
요청할 때 ArgumentResolver의 경우는 각각 @RequestBodyHttpEntity를 처리하는 ArgumentResolver가 있는데 이 ArgumentResolver들에서 각각 HTTP 메세지 컨버터를 사용해서 필요한 객체를 생성한다.

응답할 때는 @ResponseEntityHttpEntity를 ReturnValueHandler에서 처리하는데 여기에서 HTTP 메세지 컨버터를 사용해서 응답 값을 만든다.


스프링은 HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler, HttpMessageConverter 인터페이스를 모두 제공하기 때문에 확장해서 WebMvcConfigurer를 상속받은 설정 클래스에 빈으로 등록해주면 된다.

0개의 댓글