๐Ÿ๏ธ Spring

๐Ÿง ์„œ๋ก  ์Šคํ”„๋ง์—์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก @ExceptionHandler ์™€ @ControllerAdvice๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค. ์ด ๋‘˜์˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ ์–ด๋–ค ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๊ฐ€๋ฉฐ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿง ์Šคํ”„๋ง์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ • ์šฐ์„  ์Šคํ”„๋ง์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •๋ถ€ํ„ฐ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SpringAppliction์˜ run ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ, refreshContext()๋ฅผ ํ†ตํ•ด ๋นˆ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์˜์กด๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ์˜ ํ˜ธ์ถœ์„ ๋”ฐ๋ผ๊ฐ€๋‹ค๋ณด๋ฉด AbstractApplicationContext์˜ refresh()๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๊ณณ์—์„œ๋Š” finishBeanFactoryInitialization() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ด์ „ ๊ณผ์ •๋“ค์—์„œ ๋“ฑ๋ก๋˜์ง€..
์ €๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ, MockMvc + RestDocs๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ์™€ ๋ฌธ์„œํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (RestAssured์€ ์•„์ง ์จ๋ณธ์ ์ด ์—†๊ณ , ์–ธ์  ๊ฐ€ ๊ณต๋ถ€ํ•ด์•ผ์ง€ ํ•˜๊ณ  ์ผ๋‹จ์„ ๋ฏธ๋ค„๋‘” ์ƒํƒœ์ž…๋‹ˆ๋‹น..ใ… ใ… ) ์•„๋ฌดํŠผ MockMvc๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ, ์ €๋งŒ ๊ทธ๋Ÿฐ๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, ํ•ด๋‹น ๊ณผ์ •์ด ์ž˜ ์ต์ˆ™ํ•ด์ง€์ง€๋„ ์•Š์„ ๋ฟ๋”๋Ÿฌ, static import๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๊ณ , ๊ฐ™์€ ์ฝ”๋“œ์˜ ์ค‘๋ณต์ด ๋„ˆ๋ฌด ๋งŽ์•„์ ธ์„œ ์กฐ๊ธˆ ๊ท€์ฐฎ์•„ ํ•˜๋˜ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ณ ์ž, ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์ ์šฉํ•˜์—ฌ ์กฐ๊ธˆ ์ƒ๊ฐ ์—†์ด? MockMvc ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ด ๋ณด์•˜๋Š”๋ฐ์š”, ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ๊ณต์œ ํ•ด๋ณด๊ณ ์ž ๊ธ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ๊ฐ€ ์กฐ๊ธˆ ์•ˆ ์ด์  ์ˆ˜ ์žˆ๊ณ , ์ œ๊ฐ€ ์ฃผ๋กœ ์“ฐ๋Š” ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐ„ํŽธํ™”๋ฅผ ํ•˜๊ณ ์ž ํ•˜์˜€๊ธฐ..
์ด ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ๊ฑฐ์˜ 5์‹œ๊ฐ„๋™์•ˆ ๋””๋ฒ„๊น… ํ•ด์„œ ์›์ธ ์ฐพ์•„๋ƒˆ๋Š”๋ฐ, ์•Œ๊ณ ๋ณด๋‹ˆ๊นŒ 1์›” 26์ผ์ธ๊ฐ€(๋ถˆ๊ณผ ํ•œ๋‹ฌ ์ „) ํ•ด๊ฒฐ๋˜์–ด ์žˆ๋”๋ผ๊ตฌ์š”.. ๋‹ค๋งŒ ์•„์ง ์Šคํ”„๋ง๋ถ€ํŠธ jpa dependency ๋ฒ„์ „์— ๋ฐ˜์˜์ด ์•ˆ๋˜์–ด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ๊ทธ๋ƒฅ ์Šฌํผํ•˜๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. ์•„๋งˆ ๊ณง ํ•ด๊ฒฐ๋  ๊ฒƒ ๊ฐ™์€๋ฐ, ํ•ด๋‹น ์˜ค๋ฅ˜๋Š” Hibernate 6.2 ์ด์ „ ๋ฒ„์ „์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๐Ÿง ๋ฌธ์ œ ์ƒํ™ฉ ์žฌํ˜„ ์•„๋ž˜์™€ ๊ฐ™์ด 1๋Œ€ ๋‹ค ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„ One๊ณผ Many๋ฅผ ์ •์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. @Entity public class One { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(fetch = FetchType.LAZY, orphanRemoval =..
๐Ÿง ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ UNIQUE ์ œ์•ฝ์กฐ๊ฑด ์„ค์ •ํ•˜๊ธฐ @Table์˜ uniqueConstraints ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์˜ˆ์‹œ @Table( name="ํ…Œ์ด๋ธ” ์ด๋ฆ„", uniqueConstraints={ @UniqueConstraint( name = "unique ์ œ์•ฝ์กฐ๊ฑด ์ด๋ฆ„", columnNames = { "ํฌํ•จํ•  ์ปฌ๋Ÿผ์ด๋ฆ„ 1", "ํฌํ•จํ•  ์ปฌ๋Ÿผ์ด๋ฆ„ 2" } ), } columnNames๋Š” ํ•„๋“œ๊ฐ€ ์•„๋‹Œ ์ปฌ๋Ÿผ๋ช…๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @Table( uniqueConstraints={ @UniqueConstraint( columnNames={"column1"}) } ) @Table( uniqueConstraints = { @UniqueConstraint(name = "UniqueNumber..
๐Ÿง SecurityBuilder & SecurityConfigurer SecurityBuilder๋Š” ์›น ๋ณด์•ˆ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋นˆ ๊ฐ์ฒด์™€, ์„ค์ • ํด๋ž˜์Šค๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ๊ทธ ์ข…๋ฅ˜๋กœ๋Š” WebSecurity, HttpSecurity๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. SecurityConfigurer์€ Http ์š”์ฒญ๊ณผ ๊ด€๋ จ๋œ ๋ณด์•ˆ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํ•„ํ„ฐ๋“ค์„ ์ƒ์„ฑํ•˜๊ณ , ์—ฌ๋Ÿฌ ์ดˆ๊ธฐํ™” ์ž‘์—…์— ๊ด€์—ฌํ•ฉ๋‹ˆ๋‹ค. SecurityBuilder๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด SecurityConfigurer๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์ดˆ๊ธฐํ™” ์ž‘์—…์€ SecurityBuilder ๋‚ด๋ถ€์—์„œ SecurityConfigurer๋ฅผ ํ†ตํ•ด ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ดˆ๊ธฐํ™” ์ž‘์—…์€ SecurityBuilder์˜ build() ๋‚ด๋ถ€์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์ด init()๊ณผ ..
๐Ÿง ์ƒํ™ฉ ์ธ์ฆ ์‹œ 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..
๐Ÿง N + 1 ๋ฌธ์ œ N + 1 ๋ฌธ์ œ๋Š” ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ ์‚ฌ์ด์—์„œ ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜์˜€์„ ๋•Œ, ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜(N ๊ฐœ)๋งŒํผ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ N + 1์—์„œ, 1์€ ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ์˜ ๊ฐœ์ˆ˜์ด๋ฉฐ, N์€ ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜๋งŒํผ ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ์ฟผ๋ฆฌ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. N + 1๋ณด๋‹ค๋Š”, 1 + N์ด๋ผ ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ, ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ ์ฟผ๋ฆฌ(1 ๋ฒˆ) + ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜(N ๊ฐœ)๋งŒํผ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ (N ๋ฒˆ) ๐Ÿง ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์„ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ๊ฒŒ์‹œ๊ธ€๊ณผ ๋Œ“๊ธ€์„ ์˜ˆ์‹œ๋กœ ์‚ฌ์šฉํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๊ฒŒ์‹œ..
๐Ÿง ์„œ๋ก  ๋„๋ฉ”์ธ ์ด๋ฒคํŠธ๋ฅผ ํ•œ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณด๊ณ ์ž ์ด๋Ÿฐ์ €๋Ÿฐ ์ž๋ฃŒ๋“ค์„ ์ฐธ๊ณ ํ•˜๋ฉฐ ์‚ฌ์šฉ์„ ํ•˜๋˜ ์ค‘์— ๋ฌธ์ œ๊ฐ€ ํ•˜๋‚˜ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ํ•˜๊ณ ์ž ํ–ˆ๋˜ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ชจ์ž„ ์ƒ์„ฑ (๋ชจ์ž„ ์ƒ์„ฑ ์ด๋ฒคํŠธ ๋ฐœํ–‰) -> ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ (๋ชจ์ž„ ๊ธฐ๋ณธ ์—ญํ•  ๋“ฑ๋ก) & ๋ชจ์ž„ ๊ธฐ๋ณธ ์—ญํ•  ๋“ฑ๋ก ์ด๋ฒคํŠธ ๋ฐœํ–‰ -> ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ (๋ชจ์ž„์„ ์ƒ์„ฑํ•œ ํšŒ์›์„ ํšŒ์žฅ์œผ๋กœ ๋“ฑ๋ก) ์šฐ์„  ๋ชจ์ž„๊ณผ, ๋ชจ์ž„์˜ ์—ญํ• , ๋ชจ์ž„ ์ฐธ๊ฐ€์ž๋Š” ๋”ฐ๋กœ๋”ฐ๋กœ ์ˆ˜์ •๋˜๊ณ  ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋‹ค๋ฅธ ์—๊ทธ๋ฆฌ๊ฑฐํŠธ๋ผ ํŒ๋‹จํ•˜์—ฌ ์ด๋“ค์„ ๋ถ„๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์œ„ ์ƒํ™ฉ์—์„œ ์ €๋Š” @TransactionalEventListener๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. @Transactional @Service public class CreateClub implements CreateCl..
๋ง ๋ž‘
'๐Ÿ๏ธ Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ธ€ ๋ชฉ๋ก (3 Page)