์•ˆ๋…•ํ•˜์„ธ์š” 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 ๋ฉ”์‹œ์ง€

์ถœ์ฒ˜ : MDN HTTP Messages

์œ„ ๊ทธ๋ฆผ์—์„œ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ๋ถ„์ด ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์–ด๋–ค ์›น ์‚ฌ์ดํŠธ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ๋„ ์œ„์™€ ๊ฐ™์€ ๋ฉ”์‹œ์ง€๋ฅผ ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต๋ฐ›์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, OKKY ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•˜๊ธฐ ์œ„ํ•ด์„œ okky.kr ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋Œ€์‹ ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •๋ณด๋กœ HTTP ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์€ ๊ฒƒ์„ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

[GET] okky.kr

์ง€๊ธˆ ์ด ๊ธ€์„ ๋ณด๊ณ  ๊ณ„์‹œ๋‹ˆ๊นŒ ์ด ๊ณผ์ •์€ ๋‹ค ์ดํ•ดํ•˜์‹คํ…Œ์ง€์š” :)

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๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ถ”์ƒํ™”๋˜์–ด์žˆ์œผ๋‹ˆ ์‹ค์ œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ตฌํ˜„์ฒด๋ฅผ ์ฐพ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

HandlerAdapter ๊ตฌํ˜„์ฒด

๋‹ค๋ฅธ ํด๋ž˜์Šค์™€ ๋‹ฌ๋ฆฌ AbstractHandlerMethodAdapter๋Š” ์ถ”์ƒํด๋ž˜์Šค๋กœ ๋˜์–ด์žˆ์œผ๋‹ˆ ํ•œ๋ฒˆ ๋” ํด๋ž˜์Šค๋ฅผ ์ฐพ์•„๋ด…๋‹ˆ๋‹ค.

RequestMappingHandlerAdapter

ํ•œ๋ฒˆ์ด๋ผ๋„ ์Šคํ”„๋ง์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ž‘์„ฑํ•˜์‹ ๋ถ„๋“ค์ด๋ผ๋ฉด ๋ˆˆ์— ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ RequestMapping ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. RequestMappingHandlerAdapter ํด๋ž˜์Šค์˜ ์ฃผ์„์„ ์‚ดํŽด๋ณด๋ฉด ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์— ์„ ์–ธ๋œ RequestMapping์„ ์ง€์›ํ•˜๋Š” AbstractHandlerMethodAdapter์˜ ํ™•์žฅ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์—ฌ๋Ÿฌ๋ถ„์ด @RequestMapping์ด๋‚˜ @GetMapping, @PostMapping๋“ฑ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ์˜ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋ฉด RequestMappingHandlerAdapter๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋œ๋‹ค๋Š” ๊ฑฐ์ฃ .

์ง์ ‘ ์ฐพ์•„๋ณด์‹œ๋Š” ๋ถ„๋“ค์ด๋ผ๋ฉด RequestMappingHandlerAdapter์˜ ์ˆ˜๋งŽ์€ ํ•จ์ˆ˜ ์ค‘์—์„œ handleInternal์œผ๋กœ ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  invokeHandlerMethod๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์—ฌ๋Ÿฌ๋ถ„์ด ์ž‘์„ฑํ•œ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Spring 4.2+ invokeHandlerMethod

์œ„ invokeHandlerMethod๋Š” ์Šคํ”„๋ง 5 ๊ธฐ์ค€์˜ ์ฝ”๋“œ์ธ๋ฐ ์Šคํ”„๋ง 4.2๊ฐ€ ๋ช…์‹œ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ณด๋ฉด ์ด์ „์—๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์Šคํ”„๋ง 4.2 ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ์œผ์‹  ๋ถ„๋“ค์ด๋ผ๋ฉด ์ง์ ‘ ์ฐพ์•„๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๊ท€์ฐฎ์•„์š”โ€ฆใ… ใ… 

RequestMappingHandlerAdapter๋Š” ์Šคํ”„๋ง 3.1๋ถ€ํ„ฐ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋‹ˆ RequestMappingHandlerAdapter๋ฅผ ๋ฐ”๋กœ ์ฐพ์œผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ์ž‘์„ฑํ•œ ์ปจํŠธ๋กค๋Ÿฌ์˜ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์ด๋ฏ€๋กœ ์ฝ”๋“œ๋ฅผ ์ข€ ์ž์„ธํžˆ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

invokeHandlerMethod
@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๋กœ ๊ฐ์‹ธ์ ธ์žˆ๋Š” ๊ฒƒ ๊ฐ™์œผ๋‹ˆ ๋‹ค์‹œ ์ฐพ์•„๊ฐ€๋ด…์‹œ๋‹ค.

ServletInvocableHandlerMethod.invokeAndHandle
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์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

HandlerMethodReturnValueHandlerComposite
@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 ๊ตฌํ˜„์ฒด

์‚ฌ์‹ค HandlerMethodReturnValueHandler ๊ตฌํ˜„์ฒด ๋ชฉ๋ก์€ ์Šคํ”„๋ง ๊ณต์‹ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋Š” ๋ถ„๋“ค์ด๋ผ๋ฉด Handler Methods Return Values์—์„œ ํ™•์ธํ•˜์…จ์„ ๊ฒ๋‹ˆ๋‹ค.

์ด ๊ธ€์„ ๋ณด๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์ดˆ๋ณด ๊ฐœ๋ฐœ์ž๋Š” ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ฐธ๊ณ ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ฐ”๋กœ ๊ณต์‹ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ฐธ๊ณ ํ•˜๋Š” ์ด์œ ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Return ValueHandlerMethodReturnValueHandlerDescription
StringViewNameMethodReturnValueHandlerViewResolver ๊ตฌํ˜„์ฒด์— ์˜ํ•ด View Name์œผ๋กœ ์ฒ˜๋ฆฌ
ViewViewMethodReturnValueHandlerView ์ธ์Šคํ„ด์Šค๋กœ ๋ Œ๋”๋ง
MapMapMethodProcessorMap์„ ModelAndView ์†์„ฑ์œผ๋กœ ์ฒ˜๋ฆฌ
ModelModelMethodProcessorModel์„ Map์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ModelAndView ์†์„ฑ์œผ๋กœ ์ฒ˜๋ฆฌ
@ResponseBodyAbstractMessageConverterMethodProcessor๋ฆฌํ„ด ๊ฐ’์„ HttpMessageConverter ๊ตฌํ˜„์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์‘๋‹ต
voidModelAndViewMethodReturnValueHandlerServletResponse ๋˜๋Š” @ResponseStatus๋กœ ์ฒ˜๋ฆฌ
ModelAndViewModelAndViewMethodReturnValueHandlerView, 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 ๋ชฉ๋ก์ด ์žˆ์Šต๋‹ˆ๋‹ค.

RequestMappingHandlerAdapter.getDefaultArgumentResolvers
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 TypeHandlerMethodArgumentResolverDescription
@RequestParamRequestParamMethodArgumentResolver
@PathVariablePathVariableMethodArgumentResolver
@ModelAttributeServletModelAttributeMethodProcessor
@RequestBodyRequestResponseBodyMethodProcessor
@RequestPart, MultipartFile, PartRequestPartMethodArgumentResolver
WebRequest, ServletRequest, MultipartRequest, InputStreamServletRequestMethodArgumentResolver
HttpSession, Principal, Locale, TimeZone, ZoneIdServletRequestMethodArgumentResolver
ServletResponse, OutputStream, WriterServletResponseMethodArgumentResolver

์˜ˆ๋ฅผ ๋“ค์–ด, @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 ์š”์ฒญ๋ถ€ํ„ฐ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‘๋‹ตํ•˜๊ธฐ๊นŒ์ง€์˜ ๊ณผ์ •์„ ๋งˆ์น˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.