๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์˜ค๋ธ”์™„10

[Spring Boot] ๊ฐ„๋‹จํ•œ gRPC ๊ตฌํ˜„ํ•˜๊ธฐ ๋ชฉํ‘œ์Šคํ”„๋ง ๋ถ€ํŠธ, java๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ gRPC๋ฅผ ๊ตฌํ˜„ํ•ด ๋ด…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ธก์„ ๋งŒ๋“ค์–ด ๋ณด๊ณ  localhost์—์„œ ์‹คํ–‰ํ•ด ๋ด…๋‹ˆ๋‹ค๊ฐœ๋ฐœ ํ™˜๊ฒฝ Spring Boot version 3.4.0 java version Java 17 build tool Gradle 8.11 database h2 os macOS Sonoma 14.4.1 IDE IntelliJ IDEA CE 2023.3.3  ๐Ÿฆ„ SERVER build.gradleplugins { id 'java' id 'org.springframework.boot' version '3.3.6' id 'io.spring.dependency-management' version '1.1.6' id 'com.google.protobuf' version '0... 2024. 11. 26.
[gRPC]์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ RPC๋ž€ Remote Procedure Call๋„คํŠธ์›Œํฌ ์ƒ์˜ ๋‹ค๋ฅธ ์„œ๋ฒ„๋‚˜ ์‹œ์Šคํ…œ์— ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋งˆ์น˜ ๋กœ์ปฌ ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ”„๋กœํ† ์ฝœํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ์ปฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ -> ์š”์ฒญ์ด ์ง๋ ฌํ™” ๋˜์–ด ๋„คํŠธ์›Œํฌ๋กœ ์ „์†ก -> ์›๊ฒฉ ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ ํ›„ ์‘๋‹ต -> ์‘๋‹ต์ด ์ง๋ ฌํ™” ๋˜์–ด ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ :: ์‚ฌ์šฉ์ž๋Š” ์›๊ฒฉ ์„œ๋ฒ„์™€ ์ง์ ‘ ์ƒํ˜ธ์ž‘์šฉํ•˜์ง€ ์•Š๊ณ  ๋กœ์ปฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ gRPC ํŠน์ง•Google์—์„œ ๊ฐœ๋ฐœํ•œ ์˜คํ”ˆ ์†Œ์Šค RPC ํ”„๋ ˆ์ž„์›Œํฌํ”„๋กœํ† ์ฝœ ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ ์ง๋ ฌํ™”๋‹ค์–‘ํ•œ ์–ธ์–ด ์ง€์› ๋ฐ ์–ธ์–ด ๋…๋ฆฝ์„ฑ์„œ๋กœ ๋‹ค๋ฅธ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์—์„œ๋„ ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ŒHTTP/2 ๊ธฐ๋ฐ˜์—ฌ๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ํ•œ๋ฒˆ์— ๋™์‹œ์— ๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ์Œ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•ํƒœ์˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋น ๋ฅด๊ฒŒ.. 2024. 11. 24.
[Spring Boot] AOP๋ฅผ ํ™œ์šฉํ•œ ์ปค์Šคํ…€ ์• ๋…ธํ…Œ์ด์…˜ ๋งŒ๋“ค๊ธฐ 2024.11.17 - [BE/๐Ÿƒ Spring] - [Spring Boot] AOP ๊ฐœ๋… ์ •๋ฆฌ2024.11.18 - [BE/๐Ÿƒ Spring] - [Spring Boot] AOP ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๊ณผ ์˜ˆ์‹œ์ฝ”๋“œ ํ˜„์žฌ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ถ€ API์—์„œ ์š”์ฒญ/์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ End-to-End ์•”ํ˜ธํ™” ํ•ด์„œ ํ†ต์‹ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค ๋ณด๋‹ˆ Controller ํ˜น์€ ์•”๋ณตํ˜ธํ™”์™€ ๊ด€๋ จ ์—†๋Š” ๋กœ์ง์— ์•”ํ˜ธํ™” ๊ด€๋ จ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์•”๋ณตํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” static object๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉ์„ ํ•ด์™”์—ˆ๋Š”๋ฐ, AOP๋ฅผ ์ด์šฉํ•ด์„œ ์ด๋ฅผ ๊ฐœ์„ ํ•ด ๋ณด๋ฉด ์–ด๋–จ๊นŒ ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๊ฐ€๋กœ์ฑ„ ๋ณตํ˜ธํ™” ํ•ด์„œ ํ‰๋ฌธ๊ฐ’์„ ๋ฐ”๋กœ Controller์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ , ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•˜๊ธฐ ์ „์— ์‘๋‹ต ๊ฐ’์„ .. 2024. 11. 19.
[Spring Boot] AOP ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๊ณผ ์˜ˆ์‹œ์ฝ”๋“œ ์˜์กด์„ฑ ์ถ”๊ฐ€dependencies { implementation 'org.springframework.boot:spring-boot-starter-aop'}  ์‚ฌ์šฉ ๋ฐฉ์‹Aspect ์ •์˜ : @Aspect ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ Aspect ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•œ๋‹คAdvice ์ ์šฉ : @Before, @After, @Around ๋“ฑ ๋‹ค์–‘ํ•œ Advice๋ฅผ ๋ฉ”์„œ๋“œ์— ์ ์šฉํ•œ๋‹ค. ํŠน์ • ์‹œ์ ์— ์–ด๋–ค ์‹คํ–‰ ๋กœ์ง์„ ์‹คํ–‰ํ• ์ง€ ์ •์˜ํ•œ๋‹ค.Pointcut ์„ค์ • : execution ํ‘œํ˜„์‹ ๋“ฑ์„ ํ†ตํ•ด ํŠน์ • ๋ฉ”์„œ๋“œ, ํŒจํ‚ค์ง€ ๋“ฑ์—๋งŒ Aspect๊ฐ€ ์ ์šฉ๋˜๋„๋ก ์„ค์ •ํ•œ๋‹คAOP ํ™œ์„ฑํ™” : @EnableAspectJAuotProxy ์• ๋„ˆํ…Œ์ด์…˜์„ Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•ด AOP๋ฅผ ํ™œ์„ฑํ™” ํ•œ๋‹ค @EnableAspectJA.. 2024. 11. 18.
[Spring Boot] AOP ๊ฐœ๋… ์ •๋ฆฌ ์˜ˆ์‹œ ์ฝ”๋“œ์™€ ์ž์„ธํ•œ ์‚ฌ์šฉ๋ฒ•์€ ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃน๋‹ˆ๋‹ค. AOP๋ž€Aspect-Orineted Programing, ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฝ”๋“œ์—์„œ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ํŠน์ • ๊ด€์‹ฌ์‚ฌ(๊ธฐ๋Šฅ)์„ ๋ถ„๋ฆฌํ™” ํ•˜์—ฌ ์บก์Šํ™”๋ชจ๋“ˆํ™” ํ–ฅ์ƒcross-cutting concerns (ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ) ์ฒ˜๋ฆฌ์— ์œ ์šฉ๋กœ๊น…, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ์ธ์ฆ/๊ถŒํ•œ ๋ถ€์—ฌ, ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ตฌํ˜„๊ณผ ๊ฐ™์€ ํŠน์ • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ AOP๋Š” ์™œ ํ•„์š”ํ• ๊นŒ?๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํŠน์ • ๊ธฐ๋Šฅ์ธ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์คŒํšก๋‹จ ๊ด€์‹ฌ์‚ฌํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์ง์ ‘์ ์ธ ๊ด€๋ จ์ด ์—†๋Š” ๊ด€์‹ฌ์‚ฌํšก๋‹จ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ฉ”์„œ๋“œ ๋งˆ๋‹ค ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋กœ ์ธํ•ด ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€๊ณ , ๋ณ€๊ฒฝ์‹œ ์—ฌ๋Ÿฌ ๊ณณ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€๋ณด์ˆ˜.. 2024. 11. 17.
[MQTT] Spring Boot ์—์„œ MQTT(mosquitto) ์‚ฌ์šฉํ•˜๊ธฐ ํ”„๋ก ํŠธ์—์„œ ํŠน์ • api๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๊ณ  mqtt๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์œˆ๋„์šฐ PC๋‚˜ ํ‚ค์˜ค์Šคํฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ–ˆ๋‹ค. ์ž‘์€ ์–‘์˜ ๋ฐ์ดํ„ฐ ์˜€๊ณ , ์ด์ „์— ๋น„์Šทํ•œ ํ”„๋กœ์ ํŠธ์—์„œ mosquitto๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•œ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ์žˆ์–ด MQTT๋กœ ์ด๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค.๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ Spring Boot ์›น ์„œ๋ฒ„๋Š” publisher๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๊ณ , ์œˆ๋„์šฐ PC๋Š” subscriber, mosquitto๋Š” broker ์—ญํ• ์„ ํ•œ๋‹ค MQTT ํŠน์ง•๊ฒฝ๋Ÿ‰ ํ”„๋กœํ† ์ฝœ ์ตœ์†Œํ™” ๋œ ํ—ค๋”2๋ฐ”์ดํŠธ ์ •๋„์˜ ์ ์€ ์šฉ๋Ÿ‰ ๋ฉ”์„ธ์ง€ -> ์ œํ•œ๋œ ๋Œ€์—ญํญ ํ™˜๊ฒฝ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ Publish/Subscribe ๋ชจ๋ธPublisher (๋ฐœํ–‰ ์ฃผ์ฒด) Broker (์ค‘๊ฐ„์„œ๋ฒ„) Subscriber (๊ตฌ๋… ์ฃผ์ฒด)Publisher๋Š” ํŠน์ • topic์— ๋ฉ”.. 2024. 11. 13.
[Spring Boot] Custom Validation annotation Intro์‚ฌ์šฉ์ž ํ˜น์€ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์š”์ฒญํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”Spring Boot์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” @Valid, @Validated, validation ๊ด€๋ จ ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•จ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ํŠน์ • ์š”๊ตฌ์‚ฌํ•ญ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒ€์ฆ ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ŒSpring Boot์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ •์˜์˜ validation์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ์˜ˆ์ œ์ฝ”๋“œ@Getter@ToString@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)public class RegistUserRequest { @Pattern(regexp = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-].. 2024. 11. 10.
[Spring Boot] RestControllerAdvice๋กœ Validation Exception ํ•ธ๋“ค๋งํ•˜๊ธฐ request ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์„ ์œ„ํ•ด Valid, Validation, Spring Boot์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ Exception์ด ๋ฐœ์ƒํ•œ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ–ˆ์œผ๋‚˜ ์•„๋ฌด๋Ÿฐ ์•ˆ๋‚ด ์—†์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์—๋Ÿฌ์˜ ์›์ธ์„ ์•Œ ์ˆ˜ ์—†๋‹ค. Response์— ์—๋Ÿฌ์˜ ์›์ธ์„ ์ •ํ•ด์ง„ ๊ทœ๊ฒฉ์— ๋งž๊ฒŒ ์ œ๊ณตํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ž‘์—…์„ ๋•๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.  RestControllerAdviceSpring MVC์—์„œ ์ „์—ญ์ ์œผ๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์• ๋„ˆํ…Œ์ด์…˜@ControllerAdvice์™€ ๋‹ค๋ฅธ ์ ์€ @ResponseBody๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— JSON ํ˜•์‹์˜ response๋ฅผ ๋ฐ˜ํ™˜ํ•จ๊ธ€๋กœ๋ฒŒ ์˜ˆ์™ธ์ฒ˜๋ฆฌ, ์‚ฌ์šฉ์ž ์ •์˜ ํ˜•์‹์˜ JSON ๊ตฌ์กฐ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ ์‚ฌ์šฉbasePackages, basePackage.. 2024. 11. 9.
[Spring Boot] Validation์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ ์•Œ์•„๋ณด๊ธฐ ์ด์ „๊ธ€ : 2024.11.07 - [BE/๐Ÿƒ Spring] - [Validation] spring boot validation ์‚ฌ์šฉ๋ฒ•๊ณผ ์ข…๋ฅ˜ :: Spring Boot :: v3.3.5   @Valid์™€ @ValidatedValid์™€ Validated ๊ฒ€์ฆ ์‹คํŒจ์‹œ exception ๋ฐœ์ƒ @Valid @Valid๋Š” jakarta.validation.Valid์— ์†ํ•ด ์žˆ๊ณ  RequestBody๋กœ ์ „๋‹ฌ๋œ ์š”์ฒญ ๊ฐ์ฒด๋ฅผ ๊ฒ€์ฆํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋จ @Validated @Validated๋Š” org.springframework.validation.annotation.Validated์— ์†ํ•ด ์žˆ๊ณ , AOP ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘@RequestParam, @PathVariable์—์„œ ์ „๋‹ฌ๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆController๊ฐ€ ์•„.. 2024. 11. 8.
[Validation] spring boot validation ์‚ฌ์šฉ๋ฒ•๊ณผ ์ข…๋ฅ˜ ValidationSpring Boot์—์„œ๋Š” Validation์„ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์š”์ฒญ์‹œ ์ „์†กํ•œ ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•œ๋‹ค. ์™œ Validation์„ ์‚ฌ์šฉํ• ๊นŒ์ฃผ๋กœ Controller์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ถ€ํ„ฐ ์ „์†ก๋œ ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•จ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, request์‹œ ๋“ค์–ด์˜ค๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๊ฒ€์ฆ ์ฝ”๋“œ๋กœ ์ธํ•ด ์ฝ”๋“œ์˜ ์–‘์ด ๋งŽ์•„ ์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„œ๋น„์Šค ๋กœ์ง์— ๋ฐฉํ•ด๋  ์ˆ˜ ์žˆ์Œ์š”์ฒญ ํ•ญ๋ชฉ์ด ๋งŽ์•„์งˆ ์ˆ˜๋ก ๊ฒ€์ฆ ๊ณผ์ •์ด ๊ธธ์–ด์ง์—ฌ๋Ÿฌ๋ช…์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฒ€์ฆ ๋กœ์ง์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๊ด€์„ฑ์ด ์—†์–ด์งˆ ์ˆ˜ ์žˆ์ŒValidation์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฒ€์ฆ ๋กœ์ง์„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์ž‡์ŒValidation์„ ์‚ฌ์šฉํ•ด์„œ ๊ฒ€์ฆ ๋กœ์ง์„ ๋‹จ์ˆœํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ ์ถ”๊ฐ€implement.. 2024. 11. 7.