Hamutaro - Hamtaro 4

Backend 56

[Spring] ๋กœ๊น… ๋ ˆ๋ฒจ(Logging Level)

๋กœ๊น… ๋ ˆ๋ฒจ ์ข…๋ฅ˜ (๋‚ฎ์Œ -> ๋†’์Œ)๋ ˆ๋ฒจ์˜๋ฏธ์‚ฌ์šฉ ๋ชฉ์ TRACE๊ฐ€์žฅ ์ƒ์„ธ๋‚ด๋ถ€ ํ๋ฆ„, ๋ณ€์ˆ˜ ๊ฐ’ ์ถ”์ DEBUG๋””๋ฒ„๊น…์šฉ๊ฐœ๋ฐœ ์ค‘ ๋ฌธ์ œ ๋ถ„์„INFO์ผ๋ฐ˜ ์ •๋ณด ์ •์ƒ ํ๋ฆ„ ๊ธฐ๋กWARN๊ฒฝ๊ณ ๋น„์ •์ƒ ์ƒํ™ฉ์ด์ง€๋งŒ ๋™์ž‘์€ ๊ฐ€๋ŠฅERROR์˜ค๋ฅ˜์˜ˆ์™ธ ๋ฐœ์ƒ, ๊ธฐ๋Šฅ ์‹คํŒจ ๋ ˆ๋ฒจ๋ณ„ ์ •ํ™•ํ•œ ์‚ฌ์šฉ ๊ธฐ์ค€ TRACE๋ฉ”์„œ๋“œ ์ง„์ž… / ์ข…๋ฃŒํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’๋ฐ˜๋ณต๋ฌธ ๋‚ด๋ถ€ ์ƒํƒœ์šด์˜์—์„œ๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉ ์•ˆ ํ•จ, ์„ฑ๋Šฅ ์ €ํ•˜ ์œ„ํ—˜ ์žˆ์Œlog.trace("ํšŒ์› ์กฐํšŒ ์‹œ์ž‘ - memberId={}", memberId); DEBUG์ฟผ๋ฆฌ ์‹คํ–‰ ์ „ / ํ›„์กฐ๊ฑด ๋ถ„๊ธฐ ๊ฒฐ๊ณผ๋‚ด๋ถ€ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๊ฐœ๋ฐœ ์„œ๋ฒ„๊นŒ์ง€๋งŒ ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒŒ ์ผ๋ฐ˜์ log.debug("ํ† ํฐ ์ƒ์„ฑ ์™„๋ฃŒ - userId={}", userId); INFO์ค‘์š”ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ์ด๋ฒคํŠธ๋กœ๊ทธ์ธ ์„ฑ๊ณต๊ฒฐ์ œ ์™„๋ฃŒ์šด์˜ ํ™˜๊ฒฝ ๊ธฐ๋ณธ ๋ ˆ๋ฒจlog.info("ํšŒ์› ..

Backend/Spring 2026.02.17

[SpringBoot] MDC์™€ TraceId๋กœ ์š”์ฒญ ๋‹จ์œ„ ๋กœ๊ทธ ์ถ”์ ํ•˜๊ธฐ

๋ฌธ์ œ ์ƒํ™ฉ Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋‹ค ๋ณด๋ฉด ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.๋™์‹œ์— ์—ฌ๋Ÿฌ ์š”์ฒญ์ด ๋“ค์–ด์˜ดController, Service, Repository, Filter, ExceptionHandler์—์„œ ๋กœ๊ทธ๊ฐ€ ์ฐํž˜๋กœ๊ทธ๊ฐ€ ์„œ๋กœ ์„ž์ž„๋กœ๊ทธ์ธ ์„ฑ๊ณต - memberId=1ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต - memberId=3๋‹‰๋„ค์ž„ ์ค‘๋ณตJWT ์ธ์ฆ ์„ฑ๊ณต -> ์–ด๋–ค ์š”์ฒญ์—์„œ ๋ฐœ์ƒํ•œ ๋กœ๊ทธ์ธ์ง€ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์Œ ํ•ด๊ฒฐ ์ „๋žต - ์š”์ฒญ ๋‹จ์œ„ Trace ID์š”์ฒญ๋งˆ๋‹ค ๊ณ ์œ ํ•œ ID๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ์š”์ฒญ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  ๋กœ๊ทธ์— ๋™์ผํ•œ ID๋ฅผ ํฌํ•จ์‹œ์ผœ์„œ ํ•ด๊ฒฐ์ด๋ฅผ Correlation ID, TraceId ๋ผ๊ณ  ํ•จ์Šคํ”„๋ง์—์„œ๋Š” ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด MDC๋ฅผ ์‚ฌ์šฉ MDC๋ž€ ๋ฌด์—‡์ธ๊ฐ€?MDC (Mapped Diagnostic Context)..

Backend/Spring 2026.02.17

[Java] ์‹œ๊ฐ„์˜ ๊ธธ์ด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” Duration

ํŒจํ‚ค์ง€ ๊ฒฝ๋กœimport java.time.Duration;"์–ผ๋งˆ ๋™์•ˆ" ์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ์ฒด Duration ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ฟ ํ‚ค ๋งŒ๋ฃŒ์‹œ๊ฐ„ ์„ค์ •ํ•  ๋•ŒResponseCookie cookie = ResponseCookie.from("refreshToken", token) .maxAge(Duration.ofDays(7)) .build(); Redis TTL ์„ค์ •ํ•  ๋•ŒredisTemplate.opsForValue() .set(key, value, Duration.ofDays(7)); ์ฃผ์š” ๋ฉ”์„œ๋“œDuration.ofSeconds(30);Duration.ofMinutes(15);Duration.ofHours(2);Duration.ofDays(7); ์ดˆ ๋‹จ์œ„ ์ˆซ์ž๋กœ ๋ฐ”๊พธ๊ธฐlong seconds = Du..

Backend/Java 2026.02.13

[Spring] Bearer ํ† ํฐ ์ธ์ฆ ๊ตฌ์กฐ ์ดํ•ดํ•˜๊ธฐ

BearerHTTP ์ธ์ฆ ๋ฐฉ์‹ ์ค‘ ํ•˜๋‚˜HTTP ์š”์ฒญ ํ—ค๋”Authorization: Bearer {accessToken}Authorization : ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด๋Š” ํ—ค๋”Bearer : ์ธ์ฆ ๋ฐฉ์‹ (Type){accessToken} : ์‹ค์ œ ์ธ์ฆ ํ† ํฐ ์™œ Bearer ๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๊ฐ€Bearer์€ ์ง์—ญํ•˜๋ฉด '์†Œ์ง€์ž' ๋ผ๋Š” ๋œป์ด ํ† ํฐ์„ ์†Œ์ง€ํ•˜๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ์€ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋กœ ๊ฐ„์ฃผ์„œ๋ฒ„๋Š” ํ† ํฐ์„ ๋ˆ„๊ฐ€ ๋“ค๊ณ  ์™”๋Š”์ง€ ํ™•์ธํ•˜์ง€ ์•Š์Œํ† ํฐ ์„œ๋ช…์ด ์œ ํšจํ•œ์ง€ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์ง€ ์•Š์•˜๋Š”์ง€ํ•„์š”ํ•œ ํด๋ ˆ์ž„์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ Bearer ์ธ์ฆ ๋ฐฉ์‹ ํŠน์ง•Stateless์„œ๋ฒ„๋Š” ์„ธ์…˜์„ ์ €์žฅํ•˜์ง€ ์•Š์Œํ† ํฐ ์ž์ฒด์— ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Œ๋‹จ์ˆœ ๊ตฌ์กฐ์„œ๋ฒ„๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ ๋™์ž‘Authorization ํ—ค๋” ์ถ”์ถœBearer ์ œ๊ฑฐํ† ํฐ ๊ฒ€..

Backend/Spring 2026.02.11

[Spring Security] ์ธ์ฆ(Authentication), ์ธ๊ฐ€(Authorization) ๊ฐœ๋…๊ณผ ์ฐจ์ด

์ธ์ฆ (Authentication) ์ •์˜"์ด ์š”์ฒญ์„ ๋ณด๋‚ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •"๋กœ๊ทธ์ธJWT ํ† ํฐ ๊ฒ€์ฆ์„ธ์…˜ ์ฟ ํ‚ค ๊ฒ€์ฆAPI Key ๊ฒ€์ฆ์ธ์ฆ์˜ ๊ฒฐ๊ณผ์‚ฌ์šฉ์ž๊ฐ€ ํ™•์ธ๋˜๋ฉด SecurityContext์— ์‚ฌ์šฉ์ž ์ •๋ณด(Authentication) ์ €์žฅ๋จ์‚ฌ์šฉ์ž๊ฐ€ ํ™•์ธ๋˜์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์€ ์ข…๋ฃŒ๋จ์ธ์ฆ ์‹คํŒจ ์‹œHTTP Status : 401 Unauthorized-> ์ธ์ฆ = ์‹ ์› ํ™•์ธ ์ธ๊ฐ€ (Authorization) ์ •์˜"์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ด ํ–‰๋™์„ ํ•  ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ๊ณผ์ •"Role (USER, ADMIN, CREATOR)Authority (WRITE_POST, DELETE_POST)๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž ์—ฌ๋ถ€ (๋‚ด ๊ธ€์ธ์ง€?)์ƒํƒœ (๊ตฌ๋… ์—ฌ๋ถ€, ๊ฒฐ์ œ ์—ฌ๋ถ€, ์ •์ง€ ์—ฌ๋ถ€)์ธ๊ฐ€์˜ ๊ฒฐ๊ณผ๊ถŒํ•œ์ด ์žˆ์œผ๋ฉด -> ์š”์ฒญ ๊ณ„์† ์ง„ํ–‰๊ถŒ..

Backend/Spring 2026.02.10

[Spring] @RequiredArgsConstructor์™€ final ํ•„๋“œ์˜ ๊ด€๊ณ„ ์ •๋ฆฌ

@RequiredArgsConstructor@RequiredArgsConstructorfinal ํ•„๋“œ ๋˜๋Š” @NonNull ํ•„๋“œ๋งŒ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ž๋™ ์ƒ์„ฑํ•ด์ฃผ๋Š” Lombok ์–ด๋…ธํ…Œ์ด์…˜์ฃผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž… ์šฉ๋„๋กœ ์‚ฌ์šฉ @RequiredArgsConstructor + final ํ•„๋“œ (๊ถŒ์žฅ ํŒจํ„ด) @RestController@RequiredArgsConstructorpublic class MemberController { private final MemberService memberService;} ์‹ค์ œ๋กœ ์ƒ์„ฑ๋˜๋Š” ์ฝ”๋“œpublic MemberController(MemberService memberService) { this.memberService = memberService;}์ƒ์„ฑ์ž ..

Backend/Spring 2026.02.10

[Spring] API gateway

API Gateway๋ž€?MSA ์—์„œ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์˜ ๋‹จ์ผ ์ง„์ž…์  ์—ญํ• ์„ ํ•˜๋Š” ์„œ๋ฒ„Spring์—์„œ๋Š” ๋ณดํ†ต Spring Cloud Gateway๋ฅผ ์‚ฌ์šฉํด๋ผ์ด์–ธํŠธ -> Gateway -> ๋‚ด๋ถ€ ์„œ๋น„์Šค๋“ค์„œ๋น„์Šค๋“ค์€ ์™ธ๋ถ€์— ์ง์ ‘ ๋…ธ์ถœ๋˜์ง€ ์•Š์Œ API Gateway์˜ ํ•„์š”์„ฑ์„œ๋น„์Šค ์ง์ ‘ ๋…ธ์ถœ์˜ ๋ฌธ์ œ์„œ๋น„์Šค๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์—”๋“œํฌ์ธํŠธ ๊ด€๋ฆฌ ์–ด๋ ค์›€์ธ์ฆ/์ธ๊ฐ€ ๋กœ์ง์ด ๊ฐ ์„œ๋น„์Šค์— ์ค‘๋ณตCORS, ๋กœ๊น…, ๋ชจ๋‹ˆํ„ฐ๋ง ๋ถ„์‚ฐGateway๊ฐ€ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ ์ค‘์•™ํ™”๋ณด์•ˆ/์ธ์ฆ ์ผ๊ด€์„ฑ ํ™•๋ณดํด๋ผ์ด์–ธํŠธ๋Š” Gateway๋งŒ ์•Œ๋ฉด ๋จ Spring Cloud Gateway ํ•ต์‹ฌ ์—ญํ• ์š”์ฒญ ๋ผ์šฐํŒ… (Routing)URL, Header, Method ๊ธฐ์ค€์œผ๋กœ ์„œ๋น„์Šค ๋ถ„๊ธฐ/members/** -> member-service์ธ์ฆ/์ธ๊ฐ€JWT ๊ฒ€์ฆํ† ํฐ ..

Backend/Spring 2026.01.26

[Spring] Spring WebFlux ๋ž€ ๋ฌด์—‡์ธ๊ฐ€

Spring WebFlux ๋ž€?Spring 5 ๋ถ€ํ„ฐ ๋„์ž…๋œ ๋น„๋™๊ธฐ/๋…ผ๋ธ”๋กœํ‚น ์›น ํ”„๋ ˆ์ž„์›ŒํฌReactive Streams ๊ธฐ๋ฐ˜, ์ ์€ ์Šค๋ ˆ๋“œ๋กœ ๋งŽ์€ ์š”์ฒญ ์ฒ˜๋ฆฌ-> ๊ธฐ์กด Spring MVC = Blocking I/O-> WebFlux = Non-Blocking I/O + ์ด๋ฒคํŠธ ๋ฃจํ”„ WebFlux ์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝSpring MVC์˜ ๊ตฌ์กฐ์  ํ•œ๊ณ„์š”์ฒญ 1๊ฑด = ์Šค๋ ˆ๋“œ 1๊ฐœI/O ๋Œ€๊ธฐ๋™์•ˆ ์Šค๋ ˆ๋“œ ์ ์œ ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€ -> ์Šค๋ ˆ๋“œ ๊ณ ๊ฐˆ -> ์‘๋‹ต ์ง€์—ฐWebFlux์˜ ํ•ด๊ฒฐ ๋ฐฉ์‹I/O ๋Œ€๊ธฐ ์ค‘ ์Šค๋ ˆ๋“œ ๋ฐ˜ํ™˜์ด๋ฒคํŠธ๊ฐ€ ์˜ค๋ฉด ๋‹ค์‹œ ์ด์–ด์„œ ์ฒ˜๋ฆฌ์ ์€ ์Šค๋ ˆ๋“œ๋กœ ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌWebFlux = CPU๊ฐ€ ์•„๋‹ˆ๋ผ I/O ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๋ณ‘๋ชฉ์ธ ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ ๋ชจ๋ธ WebFlux ํ•ต์‹ฌ ๊ฐœ๋…Reactive StreamsPublisher : ๋ฐ์ดํ„ฐ ๋ฐœํ–‰S..

Backend/Spring 2026.01.05

[JPA] JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ 2 - ์ฆ‰์‹œ ๋กœ๋”ฉ(EAGER) vs ์ง€์—ฐ ๋กœ๋”ฉ(LAZY)

์ฆ‰์‹œ ๋กœ๋”ฉ (EAGER)์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ํ•จ๊ป˜ ๋ฐ”๋กœ ์กฐํšŒ์กฐํšŒ ์‹œ์ ์— ์กฐ์ธ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰@ManyToOne(fetch = FetchType.EAGER) ์ง€์—ฐ ๋กœ๋”ฉ (LAZY)์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์กฐํšŒ์ฒ˜์Œ์—๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด์—๋งŒ ๋„ฃ์–ด๋‘๊ณ  ํ•„๋“œ ์ ‘๊ทผ ์‹œ์ ์— DB ์กฐํšŒ@ManyToOne(fetch = FetchType.LAZY) ์‹ค์ œ SQL ์ฐจ์ด์˜ˆ์‹œOAuthAccount -> Member (ManyToOne)EAGER๋ฌด์กฐ๊ฑด Member๊นŒ์ง€ ๊ฐ™์ด ์กฐํšŒOAuthAccount account = repository.findById(1L);SELECT oa.*, u.*FROM oauth_accounts oaLEFT JOIN users u ON oa.user_id = u.idWHERE..

Backend/Java 2025.11.12

[JPA] JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ 1 - 1:N, N:1, N:N

JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘JPA๋กœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์ด๋‹ค.RDB๋Š” ํ…Œ์ด๋ธ”๊ณผ FK๋กœ ๊ด€๊ณ„๋ฅผ ๋งบ๊ณ , JPA๋Š” ์ด๋ฅผ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํ˜•ํƒœ๋กœ ํ‘œํ˜„ํ•œ๋‹ค. 1:N (One-To-Many)ํ•˜๋‚˜ -> ์—ฌ๋Ÿฌ ๊ฐœ ๊ด€๊ณ„์˜ˆ์‹œํšŒ์› 1๋ช… -> ์ฃผ๋ฌธ ์—ฌ๋Ÿฌ ๊ฐœ๊ฒŒ์‹œ๊ธ€ 1๊ฐœ -> ๋Œ“๊ธ€ ์—ฌ๋Ÿฌ ๊ฐœํŠน์ง•FK๋Š” ํ•ญ์ƒ N(๋‹ค) ์ชฝ์— ์กด์žฌ์‹ค์ œ๋กœ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ชฝ์€ ๋Œ€๋ถ€๋ถ„ N์ชฝ1์ชฝ์—์„œ 1:N ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ๋งคํ•‘ ์˜ˆ์‹œ (์–‘๋ฐฉํ–ฅ)N:1 + 1:N ์–‘๋ฐฉํ–ฅ ์กฐํ•ฉ@Entityclass Member { @OneToMany(mappedBy = "member") private List orders = new ArrayList();}@Entityclass Order { @ManyToOne @JoinColu..

Backend/Java 2025.11.12