ํด๋ผ์ด์ธํธ HTTP ์์ฒญ๋ถํฐ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์๋ตํ๊ธฐ๊น์ง์ ๊ณผ์
์๋
ํ์ธ์ Mambo ์
๋๋ค. ์ค๋์ ํด๋ผ์ด์ธํธ์ HTTP ์์ฒญ๋ถํฐ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์
์ ์๋ต๊น์ง์ ๊ณผ์ ์ ๋ํ์ฌ ์ด์ผ๊ธฐ๋ฅผ ํด๋ณด๋ ค๊ณ ํฉ๋๋ค. ์ ๊ฐ ์งํํ๋ ๊ณต๋ถ๋ฐฉ์ ์ค ํ๋๋ OKKY์ ์ฌ๋ผ์ค๋ ์ง๋ฌธ๋ค์ ์ดํด๋ณด๋ฉด์ ๋ฌธ์ ์ ์ ํ์
ํ๊ณ ํด๊ฒฐ์ฑ
์ ์ฐพ์๋ณด๋ ๊ณผ์ ์ ์งํํ๋ ๊ฒ์
๋๋ค. ๊ทธ๋ฐ๋ฐ OKKY์ ๋ฑ๋ก๋๋ ์ง๋ฌธ๋ค ์ค ๋๋ถ๋ถ์ด AJAX
์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๊ณ ์คํ๋ง ์ปจํธ๋กค๋ฌ
์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋๊ฒ ์๋๋ค๋ ์ ํ์ด ๋ง์ ํธ์
๋๋ค. ํด๋น ์ง๋ฌธ ์์ฑ์๋ค์ ์คํ๋ง ๊ฒฝํ์ด ๋ง์ง ์์ ์ด๋ณด ๊ฐ๋ฐ์ ์ด๊ฑฐ๋ ์คํ๋ง์ ๋ํ ์ดํด์์ด ๋น ๋ฅด๊ฒ ์์ ๋ฅผ ํตํด ํ์ตํ ๊ตญ๋น์ง์ ์๊ฐ์์ผ๋ก ๋ณด์
๋๋ค.
๊ตญ๋น์ง์์ ๋ํ ๋นํ๋ก ๋๊ปด์ง ์ ์์ผ์๊ฒ ์ต๋๋ค๋ง, ์คํ๋ง์ ์ฌ๋ฌ๊ฐ์ง ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ ์ด ๋ณตํฉ์ ์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ ์์ํฌ๋ก ์ผ๋ฐ์ ์ผ๋ก ์ปดํจํฐ ๊ณตํ๊ณผ์์ ๋ฐฐ์ฐ๋ ์ ๊ณต ์ง์๊ณผ๋ ๋ณ๊ฐ๋ก ์ฝ๊ฒ ์ดํดํ๊ธฐ์๋ ์ด๋ ต์ต๋๋ค. ๊ทธ๋ฌ๋๊น ๋น์ ๊ณต์์ด๊ธฐ ๋๋ฌธ์ ์ด๋ ค์ด ๊ฒ์ด ์๋๋ผ ๊ฐ๋ ์ ์ผ๋ก ์ด๋ ค์ด ๊ฒ์ด๋ ์ฐ์ธํดํ์ง ์์ผ์ ๋ ๋ฉ๋๋ค.
4๋
๋์ ์คํ๋ง ๊ธฐ๋ฐ์ผ๋ก ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ๋ฐํ๊ณ ์๋ ์ ๋ํ ์คํ๋ง์ ์ ๋๋ก ์ดํดํ์ง๋ ๋ชปํ์ต๋๋ค. ์ฒ์์ ํ ๋น๋์ด ์์ฑํ์ ํ ๋น์ ์คํ๋ง 3.1
์์ ์ ์์์ ์ฝ๋ค๊ฐ ๋ค๋ถํฐ ์ฝ๋ค๊ฐ ์ดํด๊ฐ ์๋์ ๋์ถฉ์ด๋ผ๋ ์ต์ํ 4๋ฒ์ ์ฝ์ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์์ ์ธ๊ธํ ์ง๋ฌธ๋ค์ ์คํ๋ง์ ๊ฐ๋
์ ์ดํด๋ฅผ ๋ชปํ๋ค๊ธฐ๋ณด๋ค๋ HTTP ์น ์์ฒญ ๊ณผ์ ์ ๋ํ ์ดํด๊ฐ ๋ถ์กฑํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค. ์คํ๋ง์ ํฌํจ๋ ์ฌ๋ฌ๊ฐ์ง ๋ชจ๋ ์ค ์น ์์ฒญ๊ณผ ๊ด๋ จ๋ ๋ชจ๋์ spring-web
๊ณผ spring-webmvc
์ธ๋ฐ์. ์ด ๋ชจ๋๋ค์ ์ฌ๋ฌ๋ถ์ด ์คํ๋ง ๊ธฐ๋ฐ์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฑํ๋๋ฐ ๋์์ ์ ๊ณตํ๋ ํด๋์ค๋ค์ด ํฌํจ๋์ด์์ต๋๋ค.
์ด ๊ธ์ ์ฃผ์ ๋ด์ฉ์ธ ํด๋ผ์ด์ธํธ์ HTTP ์์ฒญ๋ถํฐ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ต๊น์ง์ ๊ณผ์ ์ ์ ๋๊ฐ์ ๋ชจ๋์ด ์ ๊ณตํ๋ ํด๋์ค๋ค์ ์ฐ๊ด์ฑ์ ์ฐพ์๊ฐ๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค. ์ด ๊ธ์ ํตํด HTTP ์์ฒญ๊ณผ ์๋ต ๊ณผ์ ์ ์ดํดํ์ ๋ค๋ฉด ์ ๊ฐ ์์ ์ ์์ฑํ์๋ ์ด๋ณด ๋ฐ ์ ์ ๊ฐ๋ฐ์๋ค์ ์ํ spring to ajax์ ๋ํ ์ ๋ฆฌ์ ์ฌ๋ฌ๊ฐ์ง ์ผ์ด์ค๋ฅผ ์ข ๋ ์ฝ๊ฒ ๋ฐ์๋ค์ผ ์ ์์๊ฑฐ๋ผ ๋ด ๋๋ค.
๊ด๋ จ ์ฝ๋ : kdevkr/spring-demo-ajax
HTTP ์์ฒญ
๋จผ์ , ์น ๋ธ๋ผ์ฐ์ ์ ๊ฐ์ ํด๋ผ์ด์ธํธ์์ HTTP ์์ฒญ์ ์ํํ๋ ๊ณผ์ ์ ์ดํดํด์ผํฉ๋๋ค. MDN ๊ฐ๋ฐ์ ๋ฌธ์์์๋ HTTP ๋ฉ์์ง์ ๋ํด ์์ธํ๊ฒ ์ค๋ช ํด์ฃผ๊ณ ์์ต๋๋ค.
HTTP ๋ฉ์์ง
์ ๊ทธ๋ฆผ์์์ฒ๋ผ ์ฌ๋ฌ๋ถ์ด ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ์ด๋ค ์น ์ฌ์ดํธ๋ก ์ ๊ทผํ๋ ๊ฒ๋ ์์ ๊ฐ์ ๋ฉ์์ง๋ฅผ ์์ฒญํ๊ณ ์๋ต๋ฐ์ต๋๋ค. ์๋ฅผ ๋ค์ด, OKKY ์ฌ์ดํธ์ ์ ์ํ๊ธฐ ์ํด์ okky.kr
์ฃผ์๋ฅผ ์
๋ ฅํ๋ฉด ์น ๋ธ๋ผ์ฐ์ ๊ฐ ๋์ ํด์ ๋ค์๊ณผ ๊ฐ์ ์ ๋ณด๋ก HTTP ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ์๋ต์ ๋ฐ์ ๊ฒ์ ๋ธ๋ผ์ฐ์ ์์ ๋ณด์ฌ์ฃผ๋ ๊ฒ์
๋๋ค.
์ง๊ธ ์ด ๊ธ์ ๋ณด๊ณ ๊ณ์๋๊น ์ด ๊ณผ์ ์ ๋ค ์ดํดํ์คํ ์ง์ :)
HTTP Headers
์์ ๊ทธ๋ฆผ์์ ์น ๋ธ๋ผ์ฐ์ ๋ ์์ฒญ ํค๋(Request Headers)์ ๋ฌด์ธ๊ฐ ๋ง์ด ํฌํจํ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์์๊ฒ๋๋ค. ์ด HTTP ์์ฒญ ํค๋๋ HTTP ์์ฒญ์ ๋ํ ๋ถ๊ฐ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ค๊ณ ๋ณผ ์ ์๋๋ฐ์. ์ฌ๋ฌ๊ฐ์ง ํค๋๋ฅผ ํตํด์ ์์ฒญ์๋ฅผ ์๋ณํ ์ ์๊ฒ ํ๊ฑฐ๋ ์ธ์ฆ ์ ๋ณด๋ฅผ ํฌํจํ๊ธฐ๋ ํ๊ณ ์๋ฒ์๊ฒ ์์ฒญ์ ๋ํด ๋ด๊ฐ ์๋ต๋ฐ์ผ๋ ค๋ ํํ๋ฅผ ์๋ ค์ฃผ๊ธฐ๋ ํฉ๋๋ค.
Accept, Accept-Encoding, Accept-Language๋ ์ปจํ ์ธ ํ์(Content negotiation)์ด๋ผ๊ณ ํด์ HTTP ์์ฒญ์ ๋ํ์ฌ ์๋ตํ๋ ์๋ฒ๊ฐ ์ด๋ค ํํ๋ก ๋ด๋ ค์ฃผ๋๊ฒ ๊ฐ์ฅ ์๋ง๋ ๊ฒ์ธ์ง ์๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ HTTP ์์ฒญ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ํฌํจํด์ ๋ณด๋ผ๋ ํฌํจ๋๋ ์ปจํ ํธ ํ์ (Content-Type)๋ ์๊ณ ํ์ผ ๋ค์ด๋ก๋ํ ๋ ์ฌ์ฉ๋๋ Content-Disposition ํค๋๋ ์์ฃ .
์ฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์๊ณ ์์ด์ผํ๋ ์์ฒญ ํค๋๋ Accept
, Content-Type
์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค. Accept ํค๋๋ ์๋ฒ๊ฐ ์๋ตํ๊ธฐ ์ํด HTTP ๋ฉ์์ง๋ฅผ ๊ตฌ์ฑํ ๋ ์๋ง๋ ํํ๋ก ์ ๊ณตํด๋ฌ๋ผ๋ ์ ๋ณด์ด๊ณ Content-Type ํค๋๋ HTTP ๋ฉ์์ง์ ํฌํจ๋ ๋ฐ์ดํฐ๊ฐ ์ด๋ค ํํ๋ก ๊ตฌ์ฑ๋๋์ง๋ฅผ ์๋ฒ์๊ฒ ์๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค. ๋ฐ๋ผ์, ํด๋ผ์ด์ธํธ์์ HTTP ์์ฒญํ ๋ HTTP ๋ฉ์์ง์ ํฌํจ๋๋ ๋ฉ์์ง ํํ์ ๋ฐ๋ผ Content-Type ํค๋๋ฅผ ์ ๊ณตํด์ผํ๊ณ ์๋ฒ๋ก๋ถํฐ ํน์ ๋ฉ์์ง ํํ๋ก ๋ฐ๊ณ ์ถ๋ค๋ฉด Accept ํค๋์ ์๋ง๋ ๊ฐ์ ์ง์ ํด์ผํ์ฃ .
์ ์์์์ OKKY ์๋ฒ๋ ์น ๋ธ๋ผ์ฐ์ ๊ฐ ์์ฒญํ Accept ํค๋ ์ค ์ฒซ๋ฒ์งธ์ธ text/html์ผ๋ก HTTP ๋ฉ์์ง๋ฅผ ์๋ตํ์ต๋๋ค.
Accept
Accept ํค๋์ ๊ฐ์ <MIME_type>/<MIME_subtype>
ํํ๋ก ๊ตฌ์ฑํ๋๋ฐ ๋๋ถ๋ถ */*
์ผ๋ก ์ง์ ํ์ฌ ์๋ฒ๊ฐ ์์์ ์๋ต ๋ฉ์์ง ํํ๋ฅผ ๊ตฌ์ฑํ๊ฑฐ๋ AJAX์ผ๋ก ์์ฒญํ๋ ๊ฒฝ์ฐ application/json
์ผ๋ก ์ค์ ํ๊ธฐ๋ ํ์ฃ .
๋ค์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ Accept ๊ฐ์ด๋ฉฐ ์ด์ธ์๋ ๋ง์ผ๋ ํ๋ฒ ์ฐพ์๋ณด์๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค.
- text/plain, text/html, text/css, text/javascript
- image/png, image/jpeg
- application/json, application/xml, application/octet-stream
Content-Type
Content-Type ํค๋๋ HTTP ๋ฉ์์ง์ ํฌํจ๋ ๋ฐ์ดํฐ์ ํํ๋ฅผ ์๋ ค์ฃผ๋ ๊ฐ์ด๋ผ๊ณ ํ์ต๋๋ค. OKKY์ ๋ก๊ทธ์ธํ๊ธฐ ์ํด์ ๊ตฌ๊ธ OAuth ์ธ์ฆ์ ๋ํ HTTP ์์ฒญ ์ ๋ณด๋ฅผ ํ์ธํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋จ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ตฌ๊ธ ๊ณ์ ์ผ๋ก ์ธ์ฆ ์ ํฌํจํ๋ ์์ฒญ ๋ฐ์ดํฐ๊ฐ ํผ ๋ฐ์ดํฐ
ํํ๋ก ๊ตฌ์ฑ๋์ด์๋ค๋ ๊ฒ์ ์๋ ค์ฃผ๊ธฐ ์ํด์ Content-Type์ application/x-www-form-urlencoded
์ ์ง์ ํ์์ต๋๋ค.
๊ตฌ๊ธ ์ธ์ฆ ์๋ฒ๋ ๊ตฌ๊ธ ๊ณ์ ์ธ์ฆ์ ๋ํ ๊ฒฐ๊ณผ๊ฐ JSON ํํ์ ๋ฌธ์์ด์ธ ๊ฒ์ ์๋ ค์ฃผ๊ธฐ ์ํด์ Content-Type์ application/json
์ ์ง์ ํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ์๋ฒ๋ก ์ด๋ค ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด์ผํ๋ ์์ฒญ์ด๋ผ๋ฉด ์์ฒญ ๋ฉ์์ง๋ฅผ ๊ตฌ์ฑํ๊ณ ๋ฉ์์ง ํํ์ ๋ฐ๋ผ Content-Type์ ์ง์ ํด์ผํจ์ ์ ์ ์์ต๋๋ค.
์คํ๋ง ์น ๋ชจ๋
์คํ๋ง 5๋ถํฐ๋ ๋ฆฌ์กํฐ๋ธ ์คํ ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฑํ ์ ์๋ ๋ชจ๋์ด ์์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ ์๋ธ๋ฆฟ ๊ธฐ๋ฐ์ spring-webmvc
๋ชจ๋์ ํตํด HTTP ์์ฒญ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ์์๋ณด๋๋ก ํฉ์๋ค. ๋ชจ๋ ์ด๋ฆ์์ ํ์ธํ ์ ์๋ฏ์ด ์๋ธ๋ฆฟ ๊ธฐ๋ฐ์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ MVC ์ํคํ
์ฒ ํํ๋ก ๋์ํฉ๋๋ค. ์คํ๋ง ์น ๋ชจ๋์๋ ๋ชจ๋ HTTP ์์ฒญ์ ์ง์
์ ์ด ๋๋ DispatcherServlet ํด๋์ค๊ฐ ์์ผ๋ฉฐ HTTP ์์ฒญ์ ๋ํ ํธ๋ค๋ฌ๋ฅผ ์ฐพ์ ์ฒ๋ฆฌ๋ฅผ ์์ํ๊ฒ ๋ฉ๋๋ค.
DispatcherServlet
๋ค์์ DispatcherServlet ํด๋์ค์ doDispatch ํจ์์ ์ผ๋ถ๋ถ์ ๋๋ค.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
}
๊ต์ฅํ ๋จ์ํ ์ฝ๋๋ผ๊ณ ํ ์ ์๋๋ฐ์. ํ์ฌ ์ฒ๋ฆฌ์ค์ธ ์์ฒญ์ ๋ํ ํธ๋ค๋ฌ๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ noHandlerFound ํจ์๋ฅผ ํธ์ถํด์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํฌ ์ง 404 NotFound ์๋ต์ ์ ๊ณตํ ์ง ๊ฒฐ์ ํ๊ณ ํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋ ํธ๋ค๋ฌ๊ฐ ์๋ค๋ฉด ํด๋น ํธ๋ค๋ฌ์ ๋ํ ํธ๋ค๋ฌ ์ด๋ํฐ๋ฅผ ์ฐพ์ ์ฒ๋ฆฌ๋ฅผ ์ํํ์ฃ . ํธ๋ค๋ฌ๋ฅผ ์ฐพ์์ง๋ง ๋ค์ ํธ๋ค๋ฌ ์ด๋ํฐ๋ฅผ ์ฐพ์ ์ฒ๋ฆฌ๊ฐ ๋๋๋กํ๋ ์ด์ ๊ฐ ๊ถ๊ธํ์ง ์์ผ์ ๊ฐ์? ๊ทธ๋ผ ํธ๋ค๋ฌ ์ด๋ํฐ(HandlerAdapter)๋ฅผ ์ฐพ์๊ฐ๋ณด๋๋ก ํฉ์๋ค.
HandlerAdapter
HandlerAdapter๋ ์ธํฐํ์ด์ค๋ก ์ถ์ํ๋์ด์์ผ๋ ์ค์ ๋์์ ์ํํ๋ ๊ตฌํ์ฒด๋ฅผ ์ฐพ์์ผ ํฉ๋๋ค.
๋ค๋ฅธ ํด๋์ค์ ๋ฌ๋ฆฌ AbstractHandlerMethodAdapter๋ ์ถ์ํด๋์ค๋ก ๋์ด์์ผ๋ ํ๋ฒ ๋ ํด๋์ค๋ฅผ ์ฐพ์๋ด ๋๋ค.
ํ๋ฒ์ด๋ผ๋ ์คํ๋ง์ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ์ ๋ถ๋ค์ด๋ผ๋ฉด ๋์ ๋ค์ด์ค๋ ๊ฒ์ด ์์ต๋๋ค. ๋ฐ๋ก RequestMapping
์ด๋
ธํ
์ด์
์
๋๋ค. RequestMappingHandlerAdapter ํด๋์ค์ ์ฃผ์์ ์ดํด๋ณด๋ฉด ํธ๋ค๋ฌ ํจ์์ ์ ์ธ๋ RequestMapping์ ์ง์ํ๋ AbstractHandlerMethodAdapter์ ํ์ฅ
์ด๋ผ๊ณ ํฉ๋๋ค. ๊ทธ๋ฌ๋๊น ์ฌ๋ฌ๋ถ์ด @RequestMapping์ด๋ @GetMapping, @PostMapping๋ฑ์ ์ด๋
ธํ
์ด์
์ ์ ์ธํ์ฌ ์ปจํธ๋กค๋ฌ์ ํธ๋ค๋ฌ ํจ์๋ฅผ ์์ฑํ๋ฉด RequestMappingHandlerAdapter๋ฅผ ํตํด ์ฒ๋ฆฌ๊ฐ ์ํ๋๋ค๋ ๊ฑฐ์ฃ .
์ง์ ์ฐพ์๋ณด์๋ ๋ถ๋ค์ด๋ผ๋ฉด RequestMappingHandlerAdapter์ ์๋ง์ ํจ์ ์ค์์ handleInternal์ผ๋ก ์์ฒญ์ด ์ฒ๋ฆฌ๋จ์ ํ์ธํ ์ ์์๊ฒ๋๋ค. ๊ทธ๋ฆฌ๊ณ invokeHandlerMethod๋ฅผ ํธ์ถํด์ ์ฌ๋ฌ๋ถ์ด ์์ฑํ ํธ๋ค๋ฌ ํจ์๋ฅผ ์คํํฉ๋๋ค.
์ invokeHandlerMethod๋ ์คํ๋ง 5 ๊ธฐ์ค์ ์ฝ๋์ธ๋ฐ ์คํ๋ง 4.2๊ฐ ๋ช ์๋์ด์๋ ๊ฒ์ ๋ณด๋ฉด ์ด์ ์๋ ๋ค๋ฅธ ํจ์๋ฅผ ํธ์ถํ์ ๊ฒ ๊ฐ์ต๋๋ค. ์คํ๋ง 4.2 ์ด์ ๋ฒ์ ์ผ๋ก ๊ฐ๋ฐํ๊ณ ์์ผ์ ๋ถ๋ค์ด๋ผ๋ฉด ์ง์ ์ฐพ์๋ณด์๊ธฐ ๋ฐ๋๋๋ค. ๊ท์ฐฎ์์โฆใ ใ
RequestMappingHandlerAdapter๋ ์คํ๋ง 3.1๋ถํฐ ์ถ๊ฐ๋์์ผ๋ RequestMappingHandlerAdapter๋ฅผ ๋ฐ๋ก ์ฐพ์ผ์๋ฉด ๋ฉ๋๋ค.
์ฌ๋ฌ๋ถ์ด ์์ฑํ ์ปจํธ๋กค๋ฌ์ ํธ๋ค๋ฌ ํจ์๋ฅผ ํธ์ถํ๋ ๋ถ๋ถ์ด๋ฏ๋ก ์ฝ๋๋ฅผ ์ข ์์ธํ ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
์์ง๊น์ง ์ฉ๋๋ ๋ชจ๋ฅด๊ฒ ์ผ๋ ํธ๋ค๋ฌ ํจ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก WebDataBinderFactory, ModelFactory, ServletInvocableHandlerMethod๋ฅผ ๊ตฌ์ฑํ๊ณ ServletInvocableHandlerMethod๋ฅผ ํตํด ServletWebRequest์ ModelAndViewContainer๋ก ํธ๋ค๋ฌ ํจ์๋ฅผ ์คํํ๊ณ ์ฒ๋ฆฌํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฒ๋ฆฌํ๋ ๋ถ๋ถ์ด ServletInvocableHandlerMethod๋ก ๊ฐ์ธ์ ธ์๋ ๊ฒ ๊ฐ์ผ๋ ๋ค์ ์ฐพ์๊ฐ๋ด ์๋ค.
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
invokeForRequest ํจ์๋ก ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ๋ฆฌํด๋ ๊ฐ์ returnValueHandlers๋ก ๋ค์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ฝ๋์ ์์๋ฅผ ๋ณผ๋ invokeForRequest๊ฐ ์ฌ๋ฌ๋ถ์ด ์์ฑํ ํธ๋ค๋ฌ ํจ์๊ฐ ํธ์ถ๋๋ ๋ถ๋ถ์ด๊ณ ํธ๋ค๋ฌ ํจ์์์ ๋ฆฌํดํ ๊ฐ์ ์คํ๋ง์์ returnValueHandlers๋ก ๋ค์ ์ฒ๋ฆฌํ๋ ๊ฑฐ๋ผ๊ณ ์์ํ ์ ์์ต๋๋ค.
returnValueHandlers ์ ํ์ ์ฐพ์๋ณด๋ฉด HandlerMethodReturnValueHandlerComposite
์ธ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. HandlerMethodReturnValueHandlerComposite๋ HandlerMethodReturnValueHandler
๊ตฌํ์ฒด๋ก HandlerMethodReturnValueHandler์ ๋ชฉ๋ก์ ํตํด ์ฌ๋ฌ๋ถ์ด ํธ๋ค๋ฌ ํจ์์์ ๋ฆฌํดํ ์ ํ์ ๋ฐ๋ผ HandlerMethodReturnValueHandler์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ๊ตฌํ๋์ด์์ต๋๋ค.
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
๊ทธ๋ฌ๋ฉด ์ฌ๋ฌ๋ถ์ด ํธ๋ค๋ฌ ํจ์์์ ๋ฆฌํดํ ๊ฐ์ ๋ฐ๋ผ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํ๋ HandlerMethodReturnValueHandler ๊ตฌํ์ฒด๊ฐ ์๋ค๋ ๊ฒ์ผ๋ก ์ดํดํ ์ ์์ต๋๋ค.
HandlerMethodReturnValueHandler
HandlerMethodReturnValueHandler ๊ตฌํ์ฒด๋ฅผ ์ฐพ์๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋์ต๋๋ค.
์ฌ์ค HandlerMethodReturnValueHandler ๊ตฌํ์ฒด ๋ชฉ๋ก์ ์คํ๋ง ๊ณต์ ๋ ํผ๋ฐ์ค๋ฅผ ์ฐธ๊ณ ํ์๋ ๋ถ๋ค์ด๋ผ๋ฉด Handler Methods Return Values์์ ํ์ธํ์ จ์ ๊ฒ๋๋ค.
์ด ๊ธ์ ๋ณด๋ ๋๋ถ๋ถ์ ์ด๋ณด ๊ฐ๋ฐ์๋ ๋ ํผ๋ฐ์ค๋ฅผ ์ฐธ๊ณ ํ์ง ์์ ์ ์์ต๋๋ค. ์ด๊ฒ ๋ฐ๋ก ๊ณต์ ๋ ํผ๋ฐ์ค๋ฅผ ์ฐธ๊ณ ํ๋ ์ด์ ๋ผ๊ณ ํ ์ ์๊ฒ ์ฃ ?
๊ฐ๋จํ๊ฒ ์ ๋ฆฌํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Return Value | HandlerMethodReturnValueHandler | Description |
---|---|---|
String | ViewNameMethodReturnValueHandler | ViewResolver ๊ตฌํ์ฒด์ ์ํด View Name์ผ๋ก ์ฒ๋ฆฌ |
View | ViewMethodReturnValueHandler | View ์ธ์คํด์ค๋ก ๋ ๋๋ง |
Map | MapMethodProcessor | Map์ ModelAndView ์์ฑ์ผ๋ก ์ฒ๋ฆฌ |
Model | ModelMethodProcessor | Model์ Map์ผ๋ก ๋ณํํ์ฌ ModelAndView ์์ฑ์ผ๋ก ์ฒ๋ฆฌ |
@ResponseBody | AbstractMessageConverterMethodProcessor | ๋ฆฌํด ๊ฐ์ HttpMessageConverter ๊ตฌํ์ฒด๋ก ๋ณํํด์ ์๋ต |
void | ModelAndViewMethodReturnValueHandler | ServletResponse ๋๋ @ResponseStatus๋ก ์ฒ๋ฆฌ |
ModelAndView | ModelAndViewMethodReturnValueHandler | View, Model Attritube, Response Status๋ก ์ฒ๋ฆฌ |
์ฌ๋ฌ๋ถ์ด ์์ฑํ ์ปจํธ๋กค๋ฌ ํธ๋ค๋ฌ ํจ์๊ฐ ๋ฆฌํดํ ๊ฐ์ @ResponseBody
์ด๋
ธํ
์ด์
์ ๋ช
์ํ๋ ๊ฒ์ AbstractMessageConverterMethodProcessor
๋ฅผ ํตํด ๋ฉ์์ง ์ปจ๋ฒํฐ๋ก ๋ณํํด์ ์๋ตํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๋ํ, @ResponseBody ์์ด Map
์ ๋ฆฌํดํ๋ค๋ ๊ฒ์ MapMethodProcessor
์ ํตํด Map์ ์๋ ๊ฐ๋ค์ ModelAndView์ ์ ํธ๋ฆฌ๋ทฐํธ๋ก ๋ฃ์ด์ ์๋ตํ๋ค๋ ๊ฒ์ ์๋ฏธํ์ฃ .
๊ฒฐ๊ตญ @ResponseBody
๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋ฆฌํด ๊ฐ์ ๋ํ ๋ฉ์์ง ์ปจ๋ฒํฐ
๋ฅผ ์๊ณ ์์ด์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด, OKKY์ ๊ณต์ ํ ์คํ๋ง ๋ฒ์ ๋ณ Jackson ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๋ฉ์์ง ์ปจ๋ฒํฐ ์ ๋ณด์ ๋ฐ๋ฅด๋ฉด ์คํ๋ง ๋ฒ์ ์ ๋ฐ๋ผ JSON์ผ๋ก ๋ณํํ๊ธฐ ์ํ ๋ฉ์์ง ์ปจ๋ฒํฐ ์ง์์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๋ถ์ด ์ฌ์ฉ์ค์ธ ์คํ๋ง ๋ฒ์ ์ ๋ฐ๋ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กดํด์ผํ๊ณ ์๋ง๋ ๋ฉ์์ง ์ปจ๋ฒํฐ๊ฐ ๋ฑ๋ก๋์ด์์ด์ผํจ์ ๋ปํฉ๋๋ค.
์คํ๋ง 4 ์ด์
์ ๋ฒ์ ์ ์ฌ์ฉ์ค์ธ๋ฐ ๋๋ถ๋ถ์ ๋ธ๋ก๊ทธ์์ ์ ์ํ๋ MappingJacksonHttpMessageConverter
๋ ๋ฏธ์ง์ํ๊ธฐ ๋๋ฌธ์ org.codehaus.jackson
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กด์ฑ์ ๊ฐ์ง๊ณ ์๋ค๊ณ ํด๋ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ ๋ฑ๋ก๋์ง ์์ต๋๋ค. ๋ฐ๋๋ก ์คํ๋ง 4 ๋ฏธ๋ง
์ ๋ฒ์ ์ ์ฌ์ฉ์ค์ธ๋ฐ MappingJackson2HttpMessageConverter
๋ฅผ ๋ฑ๋กํ๊ณ com.fasterxml.jackson.core
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กดํ๋ ๊ฒ๋ ์๋ฏธ ์๋ ํ์๋ผ๊ณ ํ ์ ์์ฃ .
์ด๋ ๊ฒ ์คํ๋ง ๋ฒ์ ์ ๋ฐ๋ผ ์์กดํด์ผํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ์ด ์กด์ฌํจ์ ๋ฐ๋ผ ์์กด์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ์ ๊ด๋ฆฌํ๋
Spring Framework (Bill of Materials)์ ์ ๊ณตํ๊ธฐ๋ ํฉ๋๋ค.
์ฌ๊ธฐ๊น์ง ํ์ธํ ๋ฐ๋ก๋ HandlerAdapter๋ก ์ฌ๋ฌ๋ถ์ด ์์ฑํ ํธ๋ค๋ฌ๋ฅผ ์ฐพ์ ํธ์ถํ๊ณ ํธ๋ค๋ฌ ํจ์์ ๋ฆฌํด๊ฐ์ ๋ฐ๋ผ HandlerMethodReturnValueHandler๋ก ์๋ตํ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ๋์น ๋น ๋ฅด์ ๋ถ๋ค์ ํ๊ฐ์ง ๊ณผ์ ์ ๋นผ๋จน์๋ค๊ณ ๋๋ผ์ค ๊ฒ์
๋๋ค. ๋ฐ๋ก HTTP ์์ฒญ์ ํฌํจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ถ๋ถ์ธ๋ฐ ์คํ๋ง์์๋ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ
์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ณผ์ ์
๋๋ค. ์ด ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ๊ณผ์ ์ RequestMappingHandlerAdapter์ invokeHandlerMethod์ ์ด๋ฏธ ํฌํจ๋์ด์์ต๋๋ค.
๋ฐ๋ก WebDataBinderFactory๋ฅผ ๋ง๋ค๊ณ ServletInvocableHandlerMethod์ setHandlerMethodArgumentResolvers๋ก HandlerMethodArgumentResolverComposite๋ฅผ ์ค์ ํ๋ ๋ถ๋ถ์ ๋๋ค.
WebDataBinder
WebDataBinder๋ HTTP ์์ฒญ ํ๋ผ๋ฏธํฐ๋ฅผ ์๋ฐ ๋น์ฆ ์ค๋ธ์ ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉํ๋๋ฐ ์ฌ๋ฌ๋ถ์ด HTTP ์์ฒญ ์ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ์ ์กํ๊ฑฐ๋ ํผ ๋ฐ์ดํฐ ํ์์ผ๋ก ๋ณด๋ด๋ ๊ฒฝ์ฐ ์คํ๋ง์ WebDataBinder๋ก ์ฌ๋ฌ๋ถ์ ๋๋ฉ์ธ ํด๋์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์ ํฉ๋๋ค. ์ด๋ JavaBeans ์คํ์ ๋ฐ๋ฅด๋ฏ๋ก ํ๋กํผํฐ ํํ์๊ณผ Getter, Setter์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉํฉ๋๋ค.
HandlerMethodArgumentResolver
HandlerMethodReturnValueHandler๊ฐ ๋ฆฌํด ๊ฐ์ ๋ฐ๋ผ ์๋ต์ ์ฒ๋ฆฌํ๋ค๋ฉด HandlerMethodArgumentResolver๋ ์ปจํธ๋กค๋ฌ ํธ๋ค๋ฌ ํจ์์ ์กด์ฌํ๋ ๋งค๊ฐ๋ณ์ ์ ํ์ ๋ฐ๋ผ ๋ฐ์ดํฐ ์ฃผ์ ์ ํด์ฃผ๋ ์ญํ ์ ์ํํฉ๋๋ค. HandlerMethodArgumentResolver๋ ์ธํฐํ์ด์ค ์ด๋ฏ๋ก ์ค์ ๋ก ๋์์ ์ํํ๋ ๊ตฌํ์ฒด๋ฅผ ์ฐพ์์ผํฉ๋๋ค.
์คํ๋ง 5 ๊ธฐ์ค์ RequestMappingHandlerAdapter์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ฉ๋๋ HandlerMethodArgumentResolver ๋ชฉ๋ก์ด ์์ต๋๋ค.
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
if (KotlinDetector.isKotlinPresent()) {
resolvers.add(new ContinuationHandlerMethodArgumentResolver());
}
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new PrincipalMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
์ฌ๋ฌ๋ถ์ด ์ฃผ๋ก ์ฌ์ฉํ๊ฑฐ๋ ๋๋ถ๋ถ์ ์์ ์์ ์ฌ์ฉํ๋ ๋ช๊ฐ์ง HandlerMethodArgumentResolver ๊ตฌํ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Argument Type | HandlerMethodArgumentResolver | Description |
---|---|---|
@RequestParam | RequestParamMethodArgumentResolver | |
@PathVariable | PathVariableMethodArgumentResolver | |
@ModelAttribute | ServletModelAttributeMethodProcessor | |
@RequestBody | RequestResponseBodyMethodProcessor | |
@RequestPart, MultipartFile, Part | RequestPartMethodArgumentResolver | |
WebRequest, ServletRequest, MultipartRequest, InputStream | ServletRequestMethodArgumentResolver | |
HttpSession, Principal, Locale, TimeZone, ZoneId | ServletRequestMethodArgumentResolver | |
ServletResponse, OutputStream, Writer | ServletResponseMethodArgumentResolver |
์๋ฅผ ๋ค์ด, @ModelAttribute
๋ฅผ ํธ๋ค๋ฌ ํจ์ ๋งค๊ฐ๋ณ์์ ์ ์ธํ๋ ๊ฒ์ ServletModelAttributeMethodProcessor
์ ์ํด WebDataBinder๋ก ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ํํ๋ ๊ฒ์ด๋ฉฐ @RequestBody
๋ฅผ ํธ๋ค๋ฌ ํจ์ ๋งค๊ฐ๋ณ์์ ์ ์ธํ๋ ๊ฒ์ RequestResponseBodyMethodProcessor
์ ์ํด HTTP ์์ฒญ ํ์ด๋ก๋๋ฅผ ๋งค๊ฐ๋ณ์ ํ์์ผ๋ก ๋ฉ์์ง ์ปจ๋ฒํฐ๋ก ๋ณํํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
์ฌ๊ธฐ๊น์ง ํ์ธํจ์ผ๋ก์จ ์คํ๋ง ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ ํธ๋ค๋ฌ ํจ์๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ฐ๋ผ ์ด๋ป๊ฒ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉํ๊ณ ๋ฆฌํด๊ฐ์ ๋ฐ๋ฅธ ์๋ต์ ์ฒ๋ฆฌํ๋ ์ง ์๊ฒ๋์์ต๋๋ค. ์์ธํ๊ฒ ์์๋ณธ ๊ฒ์ ์๋๊ธฐ ๋๋ฌธ์ ์์ฌ์์ด ์์ง๋ง ์์ฒญ๊ณผ ์๋ต ๊ณผ์ ์์ ์ฌ์ฉ๋๋ ํด๋์ค๋ง ์์๋ ๋ฌด๋ฐฉํฉ๋๋ค.
์๊ฐ์ด ์๋ค๋ฉด ๊ฐ ํด๋์ค๊ฐ ์ด๋ค์์ผ๋ก ์์ฑ๋์ด์๋์ง๋ฅผ ํ์ธํด๋ณด์๋ ๊ฒ๋ ์ฌ๋ฌ๋ถ์ ์ฝ๋ ์์ฑ ์คํ์ผ์ ๋์์ด ๋ฉ๋๋ค. ์คํ๋ง ํ๋ ์์ํฌ๋ฅผ ๋ด๋นํ๋ ๊ฐ๋ฐ์๋ค์ ์ฌ๋ฌ๋ถ๋ณด๋ค ํ์คํ ๋ฐ์ด๋ ๊ฐ๋ฐ์์ด๊ณ ์ ํด์ง ์คํ์ผ์ ๋ฐ๋ผ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
์์ฒญ ์๋ต ์ผ์ด์ค
๊ทธ๋ฅ ๋ง๋ฌด๋ฆฌํ๊ธฐ์๋ ์์ฌ์์ด ๋ง์ผ๋ฏ๋ก OKKY์ ์ฌ๋ผ์ค๋ ์ง๋ฌธ๊ธ ์ค HTTP ์์ฒญ๊ณผ ์๋ต์ ๋ํ ์ฌ๋ฌ๊ฐ์ง ์ผ์ด์ค๋ฅผ ์ ๋ฆฌํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
415 Unsupported Media Type
ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ํ์ฌ ์๋ฒ๊ฐ 415 ์ค๋ฅ๋ฅผ ์๋ตํ๋ ๊ฒฝ์ฐ ํธ๋ค๋ฌ ํจ์๊ฐ ํด๋ผ์ด์ธํธ๊ฐ ์ค์ ํ Content-Type ์ ํ์ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒ์ ๋งํฉ๋๋ค.
https://okky.kr/article/558309
์ ์ง๋ฌธ๊ธ์ ์ผ์ฐจ์ ์ธ ๋ฌธ์ ์ ์ ์ปจํธ๋กค๋ฌ ํธ๋ค๋ฌ ํจ์๋ application/x-www-form-urlencoded
๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์์ฑํด๋๊ณ ์ ์ ํด๋ผ์ด์ธํธ์์๋ application/json
์ผ๋ก ์์ฒญํด๋ฒ๋ ธ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ Content-Type์ ์ ์์ ์ผ๋ก ์ค์ ํด๋ ๋ ๋ค๋ฅธ ๋ฌธ์ ์ ์ ๋ดํฌํ๊ณ ์์์ต๋๋ค. ์ด ๊ธ์์ ๋ค๋ฃจ์๋ ์คํ๋ง ๋ฒ์ ๋ณ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์กด์ฑ์ด ๋ค๋ฅด๋ค๋ ๋ถ๋ถ์
๋๋ค. ์ง๋ฌธ์๋ ์คํ๋ง 4 ์ด์๋ถํฐ ์ฌ์ฉํ ์ ์๋ Jackson 2 ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ์๊ณ vernum๋์ด ๋จ๊ธฐ์ ๋งํฌ๋ก ํด๊ฒฐํ์ ๊ฒ ๊ฐ์๋ณด์ด๋๋ฐ ํด๋น ๋งํฌ๋ก ๋ค์ด๊ฐ๋ณด๋ฉด MappingJacksonHttpMessageConverter๋ฅผ ์ฌ์ฉํ๊ณ org.codehaus.jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กด์ฑ์ ์ถ๊ฐํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
406 Not Acceptable
ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ํ์ฌ ์๋ฒ๊ฐ 406 ์ค๋ฅ๋ฅผ ์๋ตํ๋ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ๊ฐ ์ง์ ํ Accept ํค๋์ ๋ฐ๋ผ ์๋ฒ์์ HTTP ๋ฉ์์ง๋ฅผ ๊ตฌ์ฑํ ์ ์์์ ๋งํฉ๋๋ค.
https://okky.kr/article/876362
https://okky.kr/article/878053
https://okky.kr/article/878257
์ ์ง๋ฌธ์๋์ ๋ฌด๋ ค 3๋ฒ์ด๋ 406 ์ค๋ฅ์ ๋ํ ์ง๋ฌธ์ ํ์ง๋ง ์ ์ด์ HTTP ์์ฒญ๊ณผ ์๋ต์ ๋ํ ์ดํด๊ฐ ์์๊ธฐ ๋๋ฌธ์ ๋ต๋ณํด์ฃผ์๋ ๋ถ๋ค์ด ๋ญ๋ฅผ ๋ฐ๊ฟ๋ฐ๋ผ ์ด๊ฑธ ์ง์ ํด๋ผํด์ค๋ ๋ฐ๊ฟ๋ดค๋๋ฐ ์๋๋ค๋ ๋ง๋ง ๋ํ์ดํ์ญ๋๋ค.
ํธ๋ค๋ฌ ํจ์์์ System.out์ ์ ์ถ๋ ฅ๋๋ค๋ ๊ฒ์ ๋ณด๋ฉด ํธ๋ค๋ฌ ํจ์ ๋ฆฌํด๊ฐ์ HTTP ์๋ต์ผ๋ก ๋ณํํ ๋ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ํ์์ผ๋ก ๋ฐ๊พธ์ง ๋ชปํ๋ค๋ ๊ฒ์ ์์ํ ์ ์๊ฒ ์ต๋๋ค. ์ด ๊ธ์์ @ResponseBody๋ฅผ ์ ์ธํ๋ฉด ์๋ต ์ ํ์ ๋ฐ๋ฅธ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ์ฐพ์ ์๋ต์ผ๋ก ๋ณํํ๋ ๊ฒ์ ํ์ธํ์์ต๋๋ค. ๊ทธ๋์ ๋ฉ์์ง ์ปจ๋ฒํฐ๊ฐ ์ ๋ฑ๋ก๋์ด์๋์ง๋ฅผ ์์ฌํด๋ด์ผํฉ๋๋ค. ์ด๋ถ์ ๊ฒฝ์ฐ Jackson 2 ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กด ํ๊ณ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ก MappingJacksonHttpMessageConverter ๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋ชป๋ ๊ตฌ์ฑ์ ํ์ ์ ๋ฐ์ํ์ จ์ ๊ฒ๋๋ค. MappingJacksonHttpMessageConverter๋ ์คํ๋ง ์น ๋ชจ๋์ด ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๋ ๋์ง ์๊ฒ ์ง๋ง MappingJacksonHttpMessageConverter๊ฐ ํ์๋ก ํ๋ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ๊ท์น
์คํ๋ง ๋ฟ๋ง ์๋๋ผ Jackson ์ด๋ Lombok๊ณผ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก JavaBeans
์คํ์ ๋ฐ๋ผ ๋์ํฉ๋๋ค. ๋ค์ ๋งํด์ HTTP ์์ฒญ์ ํฌํจ๋ ๋ฐ์ดํฐ๋ฅผ ์๋ฐ ๋๋ฉ์ธ ํด๋์ค์ ์ฃผ์
ํ๊ธฐ ์ํ ๊ท์น
์ด ์๋ค๋ ๋ง์ธ๋ฐ์.
๋จผ์ , ๋ค์ ์ง๋ฌธ์ ์ดํด๋ด ์๋ค.
https://okky.kr/article/532781
์ ์ง๋ฌธ์ ๊ฒฝ์ฐ @RequestBody ์ด๋
ธํ
์ด์
์ ์ง์ ํด์ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์๋ํ์ผ๋ DTO์ ๋ฐ์ดํฐ๊ฐ ์ฃผ์
๋์ง ์์ ์ํฉ์
๋๋ค. ๊ทธ๋ฐ๋ฐ DTO์๋ ํ๋๋ช
์ UpperCase๋ก ์์ฑํ์
จ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ผ๋ฐ์ ์ธ ์๋ฐ ๋ค์ด๋ฐ ๊ท์น์ ๋ฐ๋ผ ์๋ฌธ์๋ก ์์ํ๋ ์นด๋ฉ ์ผ์ด์ค๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉํ๋๋ก ๋์ด์์ต๋๋ค. ํ๋๋ช
์ ๋ฐ๊ฟ์ ํด๊ฒฐํ์ ์ง๋ ๋ชจ๋ฅด๊ฒ ์ผ๋ ๋ง์ฝ, ํ๋๋ช
์ UpperCase๋ก ํ๊ณ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด ํด๋์ค ๋จ์๋ก @JsonNaming
์ ์ ์ธํ๊ฑฐ๋ ํ๋์ @JsonProperty
๋ฅผ ์ง์ ํ์๋ฉด ๋ฉ๋๋ค.
๋๋ฒ์งธ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ๊ท์น์ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋๋ ์์น๋ผ๊ณ ํ ์ ์์ต๋๋ค.
https://okky.kr/article/780096
์ ์ง๋ฌธ์ HTTP ์์ฒญ ํ์ด๋ก๋์ ๋ฐ์ดํฐ๋ฅผ ํฌํจ์ํค๊ณ @Modelattribute๋ฅผ ์ ์ธํ์ฌ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์๋ํ๋ ค๊ณ ํ์ ๊ฒฝ์ฐ์
๋๋ค. @Modelattribute๋ URL์ ํฌํจ๋๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ
๋๋ ํผ ๋ฐ์ดํฐ
ํ์์ผ๋ก๋ถํฐ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ํํ๊ธฐ ๋๋ฌธ์ HTTP ์์ฒญ ํ์ด๋ก๋๊ฐ ํผ ๋ฐ์ดํฐ ํ์์ด ์๋๋ฏ๋ก @Modelattribute
๋ก๋ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ํํ ์ ์์ต๋๋ค.
ํด๋น ์ง๋ฌธ์๋๋ ์ ๋ง๋ก @Modelattribute๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์๋ค๋ฉด ํด๋ผ์ด์ธํธ์์ Content-Type์ application/json์ด ์๋ application/x-www-form-urlencoded ํ์์ผ๋ก ๋ณด๋ด์ผ๊ฒ ์ฃ ?
๋๋ง์น๋ฉฐ
์์์ผ๋ถํฐ ํด๊ทผํ๊ณ ๋์ ์งฌ์งฌํ ์์ฑํ ๊ธ์ด๋ฏ๋ก ์ ์ฒด์ ์ผ๋ก ์ ๋ฆฌ๊ฐ ์๋์์ ์ ์์ต๋๋ค. ์ด ๋ถ๋ถ์ ์ํดํด์ฃผ์๊ธฐ ๋ฐ๋ผ๋ฉฐ ์คํ๋ง ๊ฒฝํ์ด ๋ง์ง ์์ผ์ ๊ฐ๋ฐ์ ๋ถ๋ค์๊ฒ ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋์์ผ๋ฉด ํ๋ ๋ฐ๋จ์ ๋๋ค. ์ด์์ผ๋ก ํด๋ผ์ด์ธํธ HTTP ์์ฒญ๋ถํฐ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์๋ตํ๊ธฐ๊น์ง์ ๊ณผ์ ์ ๋ง์น๋๋ก ํ๊ฒ ์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค.