@RequestBody를 컨트롤러 메서드단에 적용하면 HTTP 메세지 바디에 그대로 String 문자열이나,
ResponseEntity의 인자로 객체를 반환하면 JSON으로 문자열을 반환하면 OK와 같은 문자열을 그대로 입력할 수 있다.
응답으로 객체/문자열을 처리하는 방법은 이전 시간에 논의한 내용을 참고하자
https://progyun.tistory.com/209
[스프링 웹 MVC 1편] 25. HTTP 응답 - HTTP API, 메세지 바디에 직접 입력
package hello.springmvc.basic.response; import hello.springmvc.basic.HelloData; import java.io.IOException; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframew
progyun.tistory.com
이때 viewResolver 대신 HttpMessageConverter가 동작하게 되는데 이 인터페이스의 구체 클래스로
1) 기본 문자처리를 위한 StringHttpMessageConverter
2) 기본 객체처리를 위한 MappingJackson2HttpMessageConverter
3) 이외에도 바이트 코드 등 기타 HttpMessageConverter가 등록되어 있다.
응답의 경우 클라이언트의 HTTP Accept Header와 서버 컨트롤러의 반환 타입 정보 둘을 조합해서 HttpMessageConverter가 선택됨.
스프링 MVC는 다음 경우에 HTTP 메세지 컨버터를 적용함
-> HTTP 요청 : @RequestBody, HttpEntity(RequestEntity)
-> HTTP 응답 : @ResponseBody, HttpEntity(ResponseEntity)
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.converter;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
/**
* Strategy interface for converting from and to HTTP requests and responses.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 3.0
* @param <T> the converted object type
*/
public interface HttpMessageConverter<T> {
/**
* Indicates whether the given class can be read by this converter.
* @param clazz the class to test for readability
* @param mediaType the media type to read (can be {@code null} if not specified);
* typically the value of a {@code Content-Type} header.
* @return {@code true} if readable; {@code false} otherwise
*/
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
/**
* Indicates whether the given class can be written by this converter.
* @param clazz the class to test for writability
* @param mediaType the media type to write (can be {@code null} if not specified);
* typically the value of an {@code Accept} header.
* @return {@code true} if writable; {@code false} otherwise
*/
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
/**
* Return the list of media types supported by this converter. The list may
* not apply to every possible target element type and calls to this method
* should typically be guarded via {@link #canWrite(Class, MediaType)
* canWrite(clazz, null}. The list may also exclude MIME types supported
* only for a specific class. Alternatively, use
* {@link #getSupportedMediaTypes(Class)} for a more precise list.
* @return the list of supported media types
*/
List<MediaType> getSupportedMediaTypes();
/**
* Return the list of media types supported by this converter for the given
* class. The list may differ from {@link #getSupportedMediaTypes()} if the
* converter does not support the given Class or if it supports it only for
* a subset of media types.
* @param clazz the type of class to check
* @return the list of media types supported for the given class
* @since 5.3.4
*/
default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
return (canRead(clazz, null) || canWrite(clazz, null) ?
getSupportedMediaTypes() : Collections.emptyList());
}
/**
* Read an object of the given type from the given input message, and returns it.
* @param clazz the type of object to return. This type must have previously been passed to the
* {@link #canRead canRead} method of this interface, which must have returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
*/
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/**
* Write a given object to the given output message.
* @param t the object to write to the output message. The type of this object must have previously been
* passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param contentType the content type to use when writing. May be {@code null} to indicate that the
* default content type of the converter must be used. If not {@code null}, this media type must have
* previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
* returned {@code true}.
* @param outputMessage the message to write to
* @throws IOException in case of I/O errors
* @throws HttpMessageNotWritableException in case of conversion errors
*/
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
HTTP 메세지 컨버터는 HTTP 요청, HTTP 응답 모두에 의해 사용됨
-> canRead(), canWrite()를 통해 메세지 컨버터가 해당 클래스나 미디어타입(consumes, produces)를 지원하는지 체크
-> read(), write() 메세지 컨버터를 통해서 메세지를 읽고 쓰는 기능
스프링 부트 기본 메세지 컨버터
0 - ByteArrayHttpMessageConverter
1 - StringHttpMessageConverter
2 = MappingJackson2HttpMessageConverter : application/json
- 스프링 부트의 다양한 메세지 컨버터 중 일부를 서술한 것이다
대상 클래스 타입과 미디어타입(content-type) 둘을 체크해서 사용 여부를 결정하게 된다.
만족하지 않는 경우 다음 메세지 컨버터로 우선순위가 넘어간다.
1) ByteArrayMessageConverter : byte[] 데이터를 처리한다.
- 클래스 타입 String, 미디어 타입 : */*
요청 예시) @RequestBody byte[] java
응답 예시) @ResponseBody return byte[] / 미디어 타입 : application/octet-stream
2) StringHttpMessageConverter : String 문자로 데이터를 처리한다
- 클래스 타입 : String, 미디어타입 : */*
요청 예시) @RequestBody String data
응답 예시) @ResponseBody return "ok" / 미디어 타입 text-plain
3) MappingJackson2HttpMessageConverter: application/json
- 클래스 타입: 객체 또는 HashMap, 미디어 타입: application/json 관련
요청 예시 : @RequestBody HelloData data
응답 예시 : @ResponseBody return helloData / 미디어 타입 application/json 관련
헷갈렸던 내용이 요청 응답 어떻게 구분할 것인가였는데
이제 보니 요청 데이터 관련의 경우 메서드의 파라미터 단으로 HttpEntity나 @RequestBody가 들어가고
응답 데이터 관련한 경우는 HttpEntity나 @ResponseBody로 값이 반환된다.
HTTP 요청 데이터 읽기
- HTTP 요청이 오고, 컨트롤러에서 @RequestBody HttpEntity 파라미터를 사용한다.
- 메세지 컨버터가 메세지를 읽을 수 있는지 확인하기 위해 canRead()를 호출한다.
-> 대상 클래스 타입을 지원하는가? (예) @RequestBody의 대상 클래스가 byte[]인지 String인지 HelloData인지
-> HTTP 요청의 Content-Type 미디어 타입을 지원하는가 (예) text/plain, application/json, */*
- canRead() 조건을 만족하는 read()를 호출하고 객체 생성하고, 반환한다.
HTTP 응답 데이터 생성
- 컨트롤러에서 @ResponseBody, HttpEntity로 값이 반환된다
- 메세지 컨버터가 메세지를 쓸 수 있는지 확인하기 위해, canWrite()를 호출한다.
-> 대상 클래스 타입을 지원하는가? (예) return의 대상 클래스가 byte[]인지 String인지 HelloData인지
-> HTTP 요청의 Accept 미디어 타입을 지원하는가 / 더 자세히는 @RequestMapping의 produces
= 클라이언트가 읽을 수 있는 자료의 출력이 필요하기 때문이다
(예) text/plain, application/json, */*
- canWrite() 조건을 만족하는 write()를 호출해서 HTTP 응답 메세지 바디에 데이터를 생성한다.
==> 만약 세가지가 다 탈락하게 되면 에러가 발생한다.
'스프링 공부 (인프런 김영한 선생님) > 스프링 MVC 1편' 카테고리의 다른 글
[스프링 웹 MVC 1편] 27. 요청 매핑 핸들러 어댑터 구조 (0) | 2023.06.05 |
---|---|
[스프링 웹 MVC 1편] 25. HTTP 응답 - HTTP API, 메세지 바디에 직접 입력 (0) | 2023.06.04 |
[스프링 웹 MVC 1편] 24. HTTP 응답 - 정적 리소스, 뷰 템플릿 (0) | 2023.06.04 |
[스프링 웹 MVC 1편] 23. HTTP 요청 파라미터 (JSON) (0) | 2023.06.03 |
[스프링 웹 MVC 1편] 22. HTTP 요청 파라미터 (@ModelAttribute, 단순 텍스트) (0) | 2023.06.03 |