๐Ÿ๏ธ Spring/Web MVC

๐Ÿง ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ ์‹œ์Šคํ…œ์˜ ์ธ์ˆ˜๋ฅผ ์œ„ํ•ด ๊ธฐ๋Šฅ์ /๋น„๊ธฐ๋Šฅ์  ์š”๊ตฌ์‚ฌํ•ญ์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๊ฐœ๋ฐœ์ด ์™„๋ฃŒ๋˜์—ˆ์Œ์„ ์ฆ๋ช…ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ์œ„์™€ ๊ฐ™์ด ์‹œ์Šคํ…œ์˜ ์ธ์ˆ˜๋ฅผ ์œ„ํ•ด ์ž‘์„ฑํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ฆ‰ ์ธ์ˆ˜ํ…Œ์Šค์˜ ๋ชฉ์ ์€ ์‚ฌ์šฉ์ž๋“ค์ด ์›ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋Œ€๋กœ ๊ธฐ๋Šฅ์ด ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด๋ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ, ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿง RestAssured ์ฝ”๋“œ ์ˆจ๊ธฐ๊ธฐ ์ธ์ˆ˜ํ…Œ์ŠคํŠธ๋Š” ๊ทธ ๋ชฉ์ ์— ๋”ฐ๋ผ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ์‚ฌ๋žŒ๋“ค์ด ๋ณด๋”๋ผ๋„ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ๊ฐœ๋ฐœ๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ๊ฐ์ถ”์–ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์ดˆ์ ์„ ๋‘์–ด ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์˜ˆ์‹œ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์‚ดํŽด๋ณด..
๐Ÿง ์„œ๋ก  ์Šคํ”„๋ง์—์„œ๋Š” ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ํ†ตํ•ด, ์ปจํŠธ๋กค๋Ÿฌ(ํ•ธ๋“ค๋Ÿฌ)๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „๊ณผ ํ›„์— ์ถ”๊ฐ€์ ์ธ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ์ฆ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”. ์ธํ„ฐ์…‰ํ„ฐ์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ธํ„ฐ์…‰ํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ์–ด๋–ค ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ์„ค๋ช…์˜ ํŽธ์˜๋ฅผ ์œ„ํ•ด HandlerExecutionChain๋ถ€ํ„ฐ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿง HandlerExecutionChain HandlerExecutionChain์€ ์œ„์™€ ๊ฐ™์ด ํ•ธ๋“ค๋Ÿฌ์™€, ํ•ด๋‹น ํ•ธ๋“ค๋Ÿฌ์— ์ ์šฉ๋  ์ธํ„ฐ์…‰ํ„ฐ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. (@Controller์— @RequestMapping์œผ๋กœ ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.) ์ฆ‰ HandlerExecution..
๐Ÿง ์„œ๋ก  ์Šคํ”„๋ง์—์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก @ExceptionHandler ์™€ @ControllerAdvice๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค. ์ด ๋‘˜์˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ ์–ด๋–ค ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๊ฐ€๋ฉฐ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿง ์Šคํ”„๋ง์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ • ์šฐ์„  ์Šคํ”„๋ง์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •๋ถ€ํ„ฐ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SpringAppliction์˜ run ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ, refreshContext()๋ฅผ ํ†ตํ•ด ๋นˆ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์˜์กด๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ์˜ ํ˜ธ์ถœ์„ ๋”ฐ๋ผ๊ฐ€๋‹ค๋ณด๋ฉด AbstractApplicationContext์˜ refresh()๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๊ณณ์—์„œ๋Š” finishBeanFactoryInitialization() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ด์ „ ๊ณผ์ •๋“ค์—์„œ ๋“ฑ๋ก๋˜์ง€..
์ €๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ, MockMvc + RestDocs๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ์™€ ๋ฌธ์„œํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (RestAssured์€ ์•„์ง ์จ๋ณธ์ ์ด ์—†๊ณ , ์–ธ์  ๊ฐ€ ๊ณต๋ถ€ํ•ด์•ผ์ง€ ํ•˜๊ณ  ์ผ๋‹จ์„ ๋ฏธ๋ค„๋‘” ์ƒํƒœ์ž…๋‹ˆ๋‹น..ใ… ใ… ) ์•„๋ฌดํŠผ MockMvc๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ, ์ €๋งŒ ๊ทธ๋Ÿฐ๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, ํ•ด๋‹น ๊ณผ์ •์ด ์ž˜ ์ต์ˆ™ํ•ด์ง€์ง€๋„ ์•Š์„ ๋ฟ๋”๋Ÿฌ, static import๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๊ณ , ๊ฐ™์€ ์ฝ”๋“œ์˜ ์ค‘๋ณต์ด ๋„ˆ๋ฌด ๋งŽ์•„์ ธ์„œ ์กฐ๊ธˆ ๊ท€์ฐฎ์•„ ํ•˜๋˜ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ณ ์ž, ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์ ์šฉํ•˜์—ฌ ์กฐ๊ธˆ ์ƒ๊ฐ ์—†์ด? MockMvc ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ด ๋ณด์•˜๋Š”๋ฐ์š”, ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ๊ณต์œ ํ•ด๋ณด๊ณ ์ž ๊ธ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ๊ฐ€ ์กฐ๊ธˆ ์•ˆ ์ด์  ์ˆ˜ ์žˆ๊ณ , ์ œ๊ฐ€ ์ฃผ๋กœ ์“ฐ๋Š” ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐ„ํŽธํ™”๋ฅผ ํ•˜๊ณ ์ž ํ•˜์˜€๊ธฐ..
๐Ÿง ์ƒํ™ฉ ์ธ์ฆ ์‹œ JWT๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ์„ ์ง„ํ–‰ํ•˜๋ฉฐ, ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ์„ ์ œ์™ธํ•œ ๋ชจ๋“  URL์— ๋Œ€ํ•ด์„œ ์ธ์ฆ ๊ด€๋ จ Interceptor๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋“ฑ๋กํ•ด ๋‘” ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์ธํ„ฐ์…‰ํ„ฐ์—์„œ๋Š” AccessToken์ด ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ throw ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋Š”๋ฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ์˜€์Šต๋‹ˆ๋‹ค. @Component public class LogInInterceptor implements HandlerInterceptor { // ์ƒ๋žต @Override public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { AccessToken token = extractA..
๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋ง์”€๋“œ๋ฆฌ๋ฉด JSON ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ๋ฅผ ์œ„ํ•ด ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. @Controller public class MemberController { @GetMapping("/") public MemberDto getInfo(){ return new MemberDto("์‹ ๋™ํ›ˆ",12)); } } ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹น์—ฐํ•˜๊ฒŒ๋„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” @Controller๋ฅผ @RestController๋กœ ๋ฐ”๊พธ์–ด์ฃผ๊ฑฐ๋‚˜, @ResponseBody๋ฅผ ๋ถ™์—ฌ์ฃผ์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ResponseEntity๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ResponseEntity๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. @Controller public class MemberContr..
@RequestBody๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด MappingJackson2HttpMessageConverter๊ฐ€ ObjectMapper๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ”์ธ๋”ฉํ•ด์ค๋‹ˆ๋‹ค. ์ฆ‰ @RequestBody์˜ ๋ฐ”์ธ๋”ฉ ์กฐ๊ฑด์€ ObjectMapper์˜ ๋ฐ”์ธ๋”ฉ ์กฐ๊ฑด๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ณผ์ •์€ ๋งจ ๋งˆ์ง€๋ง‰์— ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ๊ธฐ๋ณธ์ ์ธ ์ƒํ™ฉ์—์„œ ๋ฐ”์ธ๋”ฉ์ด ๋˜๋Š” ์กฐ๊ฑด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ์กฐ๊ฑด (๋ชจ๋“  ์ ‘๊ทผ์ œ์–ด์ž) ๊ธฐ๋ณธ์ƒ์„ฑ์ž + (public) Getter ๊ฐ€๋Šฅ (๋ชจ๋“  ์ ‘๊ทผ์ œ์–ด์ž) ๊ธฐ๋ณธ์ƒ์„ฑ์ž + (๋ชจ๋“  ์ ‘๊ทผ์ œ์–ด์ž) Setter ๊ฐ€๋Šฅ ๋ถˆ๊ฐ€๋Šฅํ•œ ์กฐ๊ฑด ๊ธฐ๋ณธ์ƒ์„ฑ์ž๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ƒ์„ฑ์ž๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ (๋ชจ๋“  ์ ‘๊ทผ์ œ์–ด์ž) ๊ธฐ๋ณธ์ƒ์„ฑ์ž + (public์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ ‘๊ทผ์ œ์–ด์ž) Getter ObjectMapper ์กฐ๊ฑด ๋ณ€๊ฒฝํ•˜๊ธฐ object..
์ƒํ™ฉ 1 - String ํƒ€์ž…์˜ List์ธ ๊ฒฝ์šฐ "๋ฆฌ์ŠคํŠธ๋ช…" : [ "์š”์†Œ1", "์š”์†Œ2", "์š”์†Œ3", "์š”์†Œ4" ] ์š”์†Œ์˜ " "๋Š” ์ƒ๋žต๊ฐ€๋Šฅ ์˜ˆ์‹œ public class Blog { private String address; private List visitor = new ArrayList(); public List getVisitor() { return visitor; } public String getAddress() { return address; } public Blog() { } } ํ…Œ์ŠคํŠธ์ฝ”๋“œ @SpringBootTest class ObjectMapperTest { private ObjectMapper objectMapper = new ObjectMapper(); private static ..
๋ง ๋ž‘
'๐Ÿ๏ธ Spring/Web MVC' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ธ€ ๋ชฉ๋ก