✅ HttpMessageConverter 1장
♐ HttpMessageConverter란?
- View를 응답하는 것이 아닌, Rest API(HTTP API)로 JSON, TEXT, XML 등의 데이터를 응답 Message Body에 직접 입력하는 경우 HttpMessageConverter를 사용
♐ 동작 원리
♐ 적용 케이스
- 1. HTTP 요청 : `@RequestBody`, `HttpEntity<>`, `RequestEntity<>`
- 2. HTTP 응답 : `@ResponseBody`, `HttpEntity<>`, `ResponseEntity<>`
즉, HttpMessageConverter`는 요청과 응답 모두 사용된다
♐ 우선 순위
- Spring은 다양한 HttpMessageConverter를 제공하고 있고 우선순위가 있다. 대상 Class와 MediaType을 체크해서 어떤 Converter를 사용할지 결정한다.
1️⃣ ByteArrayHttpMessageConverter
- byte[] Data 를 처리한다.
- 대상 : byte[]
- MediaType : */*
@Slf4j
@RestController // @Controller + @ResponseBody
public class MessageConverterController {
// 요청 헤더 -> content-type: */*
@PostMapping("/byte-array")
// byte[] -> produces = "application/octext-stream"
public byte[] byteArray(@RequestBody byte[] data) {
log.info("byte-array logic");
return data; // response
}
}
2️⃣ StringHttpMessageConverter
- String Data를 처리한다.
- 대상: String
- MediaType : */*
// 요청 헤더 -> content-type: text/plain
@PostMapping("/string")
// String -> produces = "text/plain"
public String string(@RequestBody String data) {
log.info("string logic");
return data;
}
3️⃣ MappingJackson2HttpMessageConverter
- `JSON` Data를 처리한다.
- 대상 : `Object`, `HashMap`
- MediaType : `application/json`
// 요청 헤더 content-type: application/json
@PostMapping("/json")
// Data -> produces = "application/json"
public Data json(@RequestBody Data data) {
log.info("json logic");
return data;
}
♐ 동작 순서
1️⃣ 요청 데이터 읽기
- 요청
- Controller에서 @RequestBody 혹은 HttpEntity<>로 파라미터 바인딩한다.
- `MessageConverter`는 `canRead()` 메서드로 읽기가능 여부를 조회한다.
- 대상 클래스가`byte[], String, Object` 인지 여부 확인
- 요청 헤더의 `Content-Type` Media Type 지원여부 확인(`consumes`) - read() 메서드를 호출하여 Object를 생성한다.
2️⃣ 응답 데이터 읽기
- Controller에서 @ResponseBody 혹은 HttpEntity<>로 응답이 반환된다.
- MessageConverter는 canWrite() 메서드로 사용가능 여부를 조회한다.
- write() 메서드를 호출하여 HTTP Response Message Body에 데이터를 입력한다.
✅ 실습해보기
♐ 첫번째 실습(성공)
- content-type : `applicatin/json`
- @RequestBody : `String`
@PostMapping("/json-to-text")
// String -> produces = "text/plain"
public String jsonToText(@RequestBody String data) {
// logic
return data;
}
1. ByteArrayHttpMessageConverter 의 canRead() 메서드 호출 : false
2. StringHttpMessageConverter 의 canRead() 메서드 호출 : true
3. 우선순위에 밀려서 MappingJackson2HttpMessageConverter 는 동작하지 않는다.
♐ 두번째 실습(성공)
- content-type : `applicatin/json`
- @RequestBody : `Object`
@Data
public class DataDto {
private final String key;
}
@PostMapping("/json-to-json")
// Object -> produces = "application/json"
public DataDto jsonToJson(@RequestBody DataDto dto) {
// logic
return dto;
}
1. ByteArrayHttpMessageConverter 의 canRead() 메서드 호출 : false
2. StringHttpMessageConverter 의 canRead() 메서드 호출 : false
3. MappingJackson2HttpMessageConverter 의 canRead() 메서드를 호출 : true
♐ 세번째 실습(실패)
- content-type : `text/plain`
- @RequestBody : `Object`
// "{\"key\": \"value\"}"
@PostMapping("/text-to-json")
// Object -> produces = "application/json"
public DataDto textToJson(@RequestBody DataDto dto) {
// logic
return dto;
}
1.ByteArrayHttpMessageConverter 의 canRead() 메서드 호출 : false
2.StringHttpMessageConverter 의 canRead() 메서드 호출 : false
3.MappingJackson2HttpMessageConverter 의 canRead() 메서드 호출 : false
✅ HttpMessageConverter 2장
♐ HttpMessageConverter 의 사용 구조
- 요청시에는 Argument Resolver가 사용하는것이다.
- 응답시에는 ReturnValueHandler가 사용한다.
♐ 대표적인 Argument Resolver , ReturnValueHandler
1️⃣ RequestResponseBodyMethodProcessor
- @RequestBody, @ResponseBody 를 모두 처리 가능
- HandlerMethodArgumentResolver 상속
- HandlerMethodReturnValueHandler 상속
- 즉,@RequestBody`, `@ResponseBody` 두가지 모두 처리하기위해 둘다 상속
2️⃣ HttpEntityMethodProcessor
- HttpEntity<> 를 사용하기 위해 사용
- `HandlerMethodArgumentResolver` 상속
- `HandlerMethodReturnValueHandler` 상속
- 즉,`HttpEntity<>` 를 상속받은 `RequestEntity<>` , `ResponseEntity<>` 모두 처리
3️⃣HttpEntityMethodProcessor.supportParameter()
- HttpEntity<> 혹은 HttpEntity를 상속받은 객체 여부 확인
4️⃣HttpEntityMethodProcessor.resolveArgument()
- 실제 Object로 만들어주는 메서드
- readWithMessageConverters(webRequest, parameter, paramType);
- 위 코드를 실행하여 코드 내부에서 `MessageConverter` 호출하여 값을 처리한다.
💡ArgumentResolver 와 HttpMessageConverter 는 다르다.
♐ HttpMessageConverter 의 확장
- WebMvcConfigurer를 상속받고 Spring Bean으로 등록
- @Configuration를 이용하여 Spring Bean으로 등록
예시코드
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
default void addInterceptors(InterceptorRegistry registry) {
}
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
default void addCorsMappings(CorsRegistry registry) {
}
default void addViewControllers(ViewControllerRegistry registry) {
}
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
'Spring' 카테고리의 다른 글
[Spring/JPQL] JPQL이 무엇인지 알고 사용하자 (1) | 2025.04.18 |
---|---|
[Spring]Converter 보다 세부적으로 타입변경하는 법 (0) | 2025.04.16 |
[SPRING/JPA]양방향 관계시 사용하는 CASCADE에 대해 알아보자 (1) | 2025.04.11 |
[Spring/JPA] 영속성 컨텍스트 (0) | 2025.04.11 |
[Spring] Annotation (2) | 2025.04.10 |