์ปจํธ๋กค๋ฌ๊ฐ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ์ด์
์ ๋
ธํ
์ด์
๊ธฐ๋ฐ์ ์ปจํธ๋กค๋ฌ๋ ๋งค์ฐ ๋ค์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. HttpServletRequest
, Model
์ ๋ฌผ๋ก ์ด๊ณ , @RequestParam
, @ModelAttribute
๊ฐ์ ์ ๋
ธํ
์ด์
๊ทธ๋ฆฌ๊ณ @RequestBody
, HttpEntity
๊ฐ์ HTTP ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ ๋ถ๋ถ๊น์ง ๋งค์ฐ ํฐ ์ ์ฐํจ์ ๋ณด์ฌ์ฃผ์๋ค. ์ด๋ ๊ฒ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ์ด์ ๋ ๋ฐ๋ก ArgumentResolver ๋๋ถ์ด๋ค.
์ ๋
ธํ
์ด์
๊ธฐ๋ฐ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฒ๋ฆฌํ๋ RequestMappingHandlerAdaptor
๋ ArgumentResolver
๋ฅผ ํธ์ถํด์ ์ปจํธ๋กค๋ฌ(ํธ๋ค๋ฌ)๊ฐ ํ์๋ก ํ๋ ๋ค์ํ ํ๋ผ๋ฏธํฐ์ ๊ฐ(๊ฐ์ฒด)์ ์์ฑํ๋ค. ๊ทธ๋ฆฌ๊ณ ํ๋ฆฌ๋ฏธํฐ์ ๊ฐ์ด ๋ชจ๋ ์ค๋น๋๋ฉด ์ปจํธ๋กค๋ฌ๋ฅผ ํธ์ถํ๋ฉด์ ๊ฐ์ ๋๊ฒจ์ค๋ค.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter); // ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ํ๋์ง ์ฒดํฌ
// ์ค์ ๊ฐ์ฒด ์์ฑ(์ดํ ์ปจํธ๋กค๋ฌ ํธ์ถ ์ ์ ๋ฌ๋จ)
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
HTTP ์์ฒญ์ ๊ฒฝ์ฐ @RequestBody ๋ฅผ ์ฒ๋ฆฌํ๋ ArgumentResolver ๊ฐ ์๊ณ , HttpEntity ๋ฅผ ์ฒ๋ฆฌํ๋ ArgumentResolver ๊ฐ ์๋ค. ์ด ArgumentResolver ๋ค์ด HTTP ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ์ฌ์ฉํด์ ํ์ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
HTTP ์๋ต์ ๊ฒฝ์ฐ @ResponseBody ์ HttpEntity ๋ฅผ ์ฒ๋ฆฌํ๋ ReturnValueHandler ๊ฐ ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ๊ธฐ์์ HTTP ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ํธ์ถํด์ ์๋ต ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ ๋ค
HttpMessageConverter
์คํ๋ง MVC๋ ๋ค์์ ๊ฒฝ์ฐ์ HTTP ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ์ ์ฉํ๋ค.
HTTP ์์ฒญ: @RequestBody
, HttpEntity(RequestEntity)
HTTP ์๋ต: @ResponseBody
, HttpEntity(ResponseEntity)
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}
์คํ๋ง ๋ถํธ ๊ธฐ๋ณธ ๋ฉ์์ง ์ปจ๋ฒํฐ
0 = ByteArrayHttpMessageConverter
: byte[] ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ค.
- ๋์ ํด๋์ค ํ์
:
byte[]
- ์ฝ๊ธฐ ๋ฏธ๋์ดํ์
:
*/*
- ์์ฒญ ์)
@RequestBody byte[] data
- ์์ฒญ ์)
- ์ฐ๊ธฐ ๋ฏธ๋์ดํ์
application/octet-stream
- ์๋ต ์)
@ResponseBody return byte[]
- ์๋ต ์)
- ๋์ ํด๋์ค ํ์
:
1 = StringHttpMessageConverter
: String ๋ฌธ์๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ค.- ๋์ ํด๋์ค ํ์
:
String
- ์ฝ๊ธฐ ๋ฏธ๋์ดํ์
:
*/*
- ์์ฒญ ์)
@RequestBody String data
- ์์ฒญ ์)
- ์ฐ๊ธฐ ๋ฏธ๋์ดํ์
text/plain
- ์๋ต ์)
@ResponseBody return "ok"
- ์๋ต ์)
- ๋์ ํด๋์ค ํ์
:
2 = MappingJackson2HttpMessageConverter
: application/json
- ๋์ ํด๋์ค ํ์
:
๊ฐ์ฒด
๋๋HashMap
- ์ฝ๊ธฐ ๋ฏธ๋์ดํ์
application/json
๊ด๋ จ- ์์ฒญ ์)
@RequestBody HelloData data
- ์์ฒญ ์)
- ์ฐ๊ธฐ ๋ฏธ๋์ดํ์
application/json
๊ด๋ จ- ์๋ต ์)
@ResponseBody return helloData
- ์๋ต ์)
- ๋์ ํด๋์ค ํ์
:
HTTP ์์ฒญ ๋ฐ์ดํฐ ์ฝ๊ธฐ
@RequestBody
,HttpEntity(RequestEntity)
๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ- ๋ฉ์ธ์ง ์ปจ๋ฒํฐ๊ฐ ๋ฉ์ธ์ง๋ฅผ ์ฝ์ ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด
canRead()
๋ฅผ ํธ์ถํ๋ค- ๋์ ํด๋์ค ํ์
์ ์ง์ํ๋๊ฐ.
- ์) @RequestBody ์ ๋์ ํด๋์ค ( byte[] , String , HelloData )
- HTTP ์์ฒญ์ Content-Type ๋ฏธ๋์ด ํ์
์ ์ง์ํ๋๊ฐ.
- ์) text/plain , application/json
- ๋์ ํด๋์ค ํ์
์ ์ง์ํ๋๊ฐ.
- ๋ฉ์ธ์ง ์ปจ๋ฒํฐ๊ฐ ๋ฉ์ธ์ง๋ฅผ ์ฝ์ ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด
HTTP ์๋ต ๋ฐ์ดํฐ ์์ฑ
@ResponseBody
,HttpEntity(ResponseEntity)
๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ- ๋ฉ์ธ์ง ์ปจ๋ฒํฐ๊ฐ ๋ฉ์์ง๋ฅผ ์ธ ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด
canWrite()
๋ฅผ ํธ์ถํ๋ค.- ๋์ ํด๋์ค ํ์
์ ์ง์ํ๋๊ฐ.
- ์) return์ ๋์ ํด๋์ค ( byte[] , String , HelloData )
- HTTP ์์ฒญ์ Accept ๋ฏธ๋์ด ํ์
์ ์ง์ํ๋๊ฐ.(๋ ์ ํํ๋ @RequestMapping ์ produces )
- ์) text/plain , application/json
- ๋์ ํด๋์ค ํ์
์ ์ง์ํ๋๊ฐ.
- canWrite() ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด write() ๋ฅผ ํธ์ถํด์ HTTP ์๋ต ๋ฉ์์ง ๋ฐ๋์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ค
- ๋ฉ์ธ์ง ์ปจ๋ฒํฐ๊ฐ ๋ฉ์์ง๋ฅผ ์ธ ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด
When receiving a new request, Spring will use the “Accept” header to determine the media type that it needs to respond with. It will then try to find a registered converter that's capable of handling that specific media type. Finally, it will use this to convert the entity and send back the response. The process is similar for receiving a request which contains JSON information. The framework will use the “Content-Type” header to determine the media type of the request body.
์๋ก์ด request๋ฅผ ๋ฐ์ผ๋ฉด, ์คํ๋ง์ "Accept" ํค๋๋ฅผ ์ฌ์ฉํด์ ์๋ตํ media type์ ๊ฒฐ์ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ํน์ media type์ ์ฒ๋ฆฌํ ์ ์๋ converter๋ฅผ ์ฐพ์ผ๋ ค๊ณ ์๋ํ๋ค. ๋ง์ง๋ง์ผ๋ก ์ด๋ฅผ ์ฌ์ฉํด์ ์ํฐํฐ๋ฅผ ๋ณํํ๊ณ ์๋ต์ ๋ค์ ๋ณด๋ธ๋ค. ๋ํ, ์คํ๋ง์ "Content-Type" ํค๋๋ฅผ ์ฌ์ฉํด์ request body์ media type์ ๊ฒฐ์ ํ๋ค.
Example
- the Client sends a GET request to /foos with the Accept header set to application/json – to get all Foo resources as JSON
- the Foo Spring Controller is hit and returns the corresponding Foo Java entities
- Spring then uses one of the Jackson message converters to marshall the entities to JSON
๐ Reference