์ด๋ฒ ๊ณผ์ ๋ Spring Boot + JPA + MySQL๋ก ์ผ์ (Schedule) CRUD๋ฅผ ๋ง๋ค๊ณ ,
Lv2๋ถํฐ๋ User ์ฐ๊ด๊ด๊ณ, Lv4์์๋ Cookie/Session ๊ธฐ๋ฐ ๋ก๊ทธ์ธ ์ธ์ฆ๊น์ง ์ ์ฉํ๋ ๊ฒ์ด ๋ชฉํ์๋ค.
๊ฐ๋ฐ ํ๊ฒฝ
- Java 17
- Spring Boot
- Spring Data JPA
- MySQL
- Validation
- Lombok
- Postman
ํ๋ก์ ํธ ํจํค์ง ๊ตฌ์กฐ
kr.spartaclub.develop_scheduleapp
โฃ config
โฃ controller
โฃ dto
โฃ entity
โฃ repository
โ service
๊ณตํต ์ค์ : JPA Auditing (createdAt / updatedAt ์๋)
Lv1๋ถํฐ ์ผ์ ์์ฑ/์์ ์๊ฐ์ ์๋ต์ ํฌํจํด์ผ ํด์ Auditing์ ๋จผ์ ์ก์๋ค.
1) JPA Auditing ํ์ฑํ
JpaAuditingConfig.java
- @EnableJpaAuditing ๋ถ์ด๋ฉด JPA๊ฐ ์ํฐํฐ ์ ์ฅ/์์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํด์ ์๊ฐ์ ์๋์ผ๋ก ์ฑ์์ค๋ค.
@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {
}
2) BaseTimeEntity
BaseTimeEntity.java
- @MappedSuperclass : ์์ํ ์ํฐํฐ ํ ์ด๋ธ ์ปฌ๋ผ์ผ๋ก ํฌํจ๋จ
- @EntityListeners(AuditingEntityListener.class) : auditing ์ด๋ฒคํธ ๊ฐ์ง
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
Lv1. ์ผ์ CRUD (username ๊ธฐ๋ฐ)
Lv1์ ์ ์ ํ ์ด๋ธ์ด ์์ด์, ์ผ์ ์ username์ ๋ฌธ์์ด๋ก ์ ์ฅํ๋ ๋ฐฉ์์ผ๋ก ์์ํ๋ค.
Lv1 ์๊ตฌ์ฌํญ(์์ฝ)
- ์ผ์ CRUD ๊ตฌํ
- ์์ฑ/์ ์ฒด์กฐํ/๋จ๊ฑด์กฐํ/์์ /์ญ์
- createdAt / updatedAt ์๋ต์ ํฌํจ
Lv1 ์ค๊ณ ํฌ์ธํธ
- ์์ง User ํ ์ด๋ธ์ด ์์ผ๋๊น ์์ฑ์(username)๋ ๋ฌธ์์ด๋ก ๋ฐ๋๋ค
- Controller -> Service -> Repository ํ๋ฆ์ผ๋ก ๋ถ๋ฆฌ
- ์ํฐํฐ๋ DB ๊ตฌ์กฐ, DTO๋ ์์ฒญ/์๋ต ์ ์ฉ์ผ๋ก ๋ถ๋ฆฌ
Lv1์์ ํต์ฌ์ผ๋ก ๋ง๋ ํ์ผ๋ค
- controller/ScheduleController
- service/ScheduleService
- repository/ScheduleRepository
- entity/Schedule, entity/BaseTimeEntity
- dto/ScheduleRequest, dto/ScheduleResponse, dto/ScheduleUpdateRequest
- config/JpaAuditingConfig
์ฝ๋ ํ๋ฆ(์์ฝ)
- Controller์์ ์์ฒญ ๋ฐ์
- Service์์ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ(์ ์ฅ/์กฐํ/์์ /์ญ์ )
- Repository(JPA) ๋ก DB ์ ๊ทผ
- ๊ฒฐ๊ณผ๋ฅผ Response DTO๋ก ๊ฐ์ธ์ ๋ฐํ
Lv1 DTO/Entity ์ญํ ๋ถ๋ฆฌ
- ScheduleRequest: ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ด๋ ๊ฐ๋ง ๋ฐ์(username/title/content)
- ScheduleUpdateRequest: ์์ ์ ํ์ํ ๊ฐ๋ง ๋ฐ์(title/content)
- ScheduleResponse: ํด๋ผ์ด์ธํธ์๊ฒ ๋ด๋ ค์ค ๊ฐ๋ง ๋ด์(id/username/title/content/createdAt/updatedAt)
์ด ๋ถ๋ฆฌ๋ฅผ ํด๋๋ฉด, ๋์ค์ Lv2์์ username์ ์์ ๊ณ userId๋ก ๋ฐ๊พธ๋ ์์ ์ด ํจ์ฌ ํธํด์ง(์ค์ ๋ก ๊ทธ๋ฌ์).
API ๋ชฉ๋ก
- POST /api/schedules : ์ผ์ ์์ฑ
- GET /api/schedules : ์ ์ฒด ์กฐํ
- GET /api/schedules/{id} : ๋จ๊ฑด ์กฐํ
- PATCH /api/schedules/{id} : ์์
- DELETE /api/schedules/{id} : ์ญ์
Postman ๊ฒ์ฆ ์์ (Lv1)
1) ์ผ์ ์์ฑ
POST /api/schedules
{
"username": "jimin",
"title": "์ฒซ ์ผ์ ",
"content": "CRUD ์์!"
}

2) ์ ์ฒด ์กฐํ
GET /api/schedules

3) ๋จ๊ฑด ์กฐํ
GET /api/schedules/{id}

4) ์์
PATCH /api/schedules/{id}
{
"title": "์์ ๋ ์ ๋ชฉ",
"content": "์์ ๋ ๋ด์ฉ"
}

5) ์ญ์
DELETE /api/schedules/{id}

Lv2. User CRUD + Schedule ์ฐ๊ด๊ด๊ณ (userId ๊ธฐ๋ฐ)
Lv2๋ถํฐ๋ ์ผ์ ์ด username ๋ฌธ์์ด์ ์ ์ฅํ๋๊ฒ ์๋๋ผ,
User๋ฅผ ์ฐธ์กฐ(FK)ํ๋ ๊ตฌ์กฐ๋ก ๋ฐ๊ฟ์ผ ํ๋ค.
- ๊ธฐ์กด: Schedule.username (String)
- ๋ณ๊ฒฝ: Schedule.user (ManyToOne)
ํต์ฌ ๊ฐ๋ : ์ฐ๊ด๊ด๊ณ(ManyToOne)
Schedule์ ์์ฑ์(User)๋ฅผ ๊ฐ์ง๋ค.
ํ ๋ช
์ ์ ์ ๊ฐ ์ฌ๋ฌ ๊ฐ์ ์ผ์ ์ ์์ฑํ ์ ์์ผ๋๊น ๊ด๊ณ๋ ์ด๋ ๊ฒ ๋๋ค.
- User 1 : Schedule N
-> Schedule ์ ์ฅ์์๋ ManyToOne
Lv2 ์๊ตฌ์ฌํญ
- User CRUD ์ถ๊ฐ
- ์ผ์ ์์ฑ ์ ์ ์ ์ ์ฐ๊ด๊ด๊ณ๋ก ์ ์ฅ
- ์ผ์ ์๋ต์์ username์ User์์ ๊ฐ์ ธ์จ ๊ฐ์ด์ด์ผ ํจ
Lv2์์ ๋ฐ๋ ์
Schedule์ด ๋ ์ด์ username(String)์ ์ ์ฅํ์ง ์๊ณ , user(User)๋ฅผ ์ฐธ์กฐํ๋๋ก ๋ณ๊ฒฝ
Lv2 ํต์ฌ ๋ณ๊ฒฝ 1) User ์ํฐํฐ ์ถ๊ฐ
- entity/User ์์ฑ
- ์ด๋ฉ์ผ์ unique ์ฒ๋ฆฌ(์ค๋ณต ๊ฐ์ ๋ฐฉ์ง)
@Entity
@Table(name="users")
public class User extends BaseTimeEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable=false, length=50)
private String username;
@Column(nullable=false, length=100, unique=true)
private String email;
}
Lv2 ํต์ฌ ๋ณ๊ฒฝ 2) Schedule ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ ์ถ๊ฐ
- Schedule.user ํ๋ ์ถ๊ฐ
- @ManyToOne + @JoinColumn(name="user_id") ๋ก FK ์์ฑ
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
์ฌ๊ธฐ์ ์ค์ DB์ user_id ์ปฌ๋ผ์ด ์๊ธฐ๊ณ , schedules ํ ์ด๋ธ์ด users๋ฅผ ์ฐธ์กฐํ๊ฒ ๋จ.
Lv2 ํต์ฌ ๋ณ๊ฒฝ 3) ScheduleRequest๊ฐ userId๋ฅผ ๋ฐ๋๋ก ๋ณ๊ฒฝ
๊ธฐ์กด Lv1:
- username์ ๋ฐ์
Lv2:
- userId๋ฅผ ๋ฐ์
@NotNull(message="userId๋ ํ์์
๋๋ค.")
private Long userId;
Lv2 ํต์ฌ ๋ณ๊ฒฝ 4) Service์์ userId๋ก User๋ฅผ ์กฐํํด์ Schedule ์ ์ฅ
ScheduleService.create()์์:
- userRepository.findById(userId) ๋ก ์ ์ ์กด์ฌ ํ์ธ
- ๊ทธ User๋ก Schedule ์์ฑ ํ save
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> new IllegalArgumentException("ํด๋น ์ ์ ๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค. id=" + request.getUserId()));
Schedule saved = scheduleRepository.save(new Schedule(user, request.getTitle(), request.getContent()));
return new ScheduleResponse(saved);
User ์์ฑ API (Lv2)
POST /api/users
{
"username": "jimin",
"email": "jimin@test.com"
}

Postman ๊ฒ์ฆ ์์ (Lv2)
1) ์ ์ ์์ฑ ํ id ํ์ธ
- ์๋ต์์ id=1 ๊ฐ์ ๊ฐ ํ์ธ
2) ์ผ์ ์์ฑ (userId๋ก)
POST /api/schedules
{
"userId": 1,
"title": "Lv2 ์ผ์ ",
"content": "์ ์ ์ฐ๊ด๊ด๊ณ๋ก ์์ฑ"
}

3) ์ผ์ ์ ์ฒด ์กฐํ
GET /api/schedules

4) ์ ์ ๋ช ์์ ํ ์ผ์ ๋ค์ ์กฐํ
PATCH /api/users/1
{
"username": "jimin2",
"email": "jimin2@test.com"
}
๊ทธ ๋ค์ GET /api/schedules ๋ค์ ์คํ
- ์ผ์ ์๋ต์์ username์ด jimin2๋ก ๋ฐ๋์ด ๋ณด์ด๋ฉด Schedule์ด username์ ์ ์ฅํ๊ฒ ์๋๋ผ User๋ฅผ ์ฐธ์กฐํ๋ค๋ ์ฆ๊ฑฐ


Lv3. ์ ์ ์ password ํฌํจ / ํ์๊ฐ์ ํํ ๊ฐํ
Lv3์์ ๋๋ ํ์๊ฐ์
์
๋ ฅ์ password๋ฅผ ์ถ๊ฐํ๋ค.
(์ดํ Lv4 ๋ก๊ทธ์ธ ๊ตฌํ์ ์ํด ํ์)
- User์ password ์ปฌ๋ผ ์ถ๊ฐ
- UserRequest DTO์ password ์ถ๊ฐ
Lv3 ์๊ตฌ์ฌํญ
- ํ์๊ฐ์ ํํ ๊ฐํ(๋ก๊ทธ์ธ ์ค๋น ๋จ๊ณ)
Lv3์์ ์ถ๊ฐ๋ ๊ฒ
- User์ password ์ปฌ๋ผ ์ถ๊ฐ
- DTO(UserRequest ๋ฑ)์ password ํ๋ ์ถ๊ฐ + Validation
@Column(nullable=false)
private String password;
์ ์ ํ์๊ฐ์ ํ ์คํธ

๋น๋ฐ๋ฒํธ 4์๋ฆฌ๋ง ์ ๋ ฅํ์ ๊ฒฝ์ฐ: ์ค๋ฅ
-> ์ค๋ฅ๋ฉ์์ง๋ ๋์ ๊ธฐ๋ฅ์์ ๊ตฌํ ์์

๋น๋ฐ๋ฒํธ ์ ๋ ฅํ์ง ์์์ ๊ฒฝ์ฐ: ์ค๋ฅ
-> ์ค๋ฅ๋ฉ์์ง๋ ๋์ ๊ธฐ๋ฅ์์ ๊ตฌํ ์์

์ด ๋จ๊ณ์์ 400์ด ๋ฐ ์๋ ์๋๋ฐ,
์์ธ์ฒ๋ฆฌ๋ Lv5์์ ํ๋ฏ๋ก “์ง๊ธ์ 400๋ง ํ์ธ๋๋ฉด OK”๋ก ์งํํ๋ค.
Lv4. ๋ก๊ทธ์ธ(์ธ์ฆ) - Cookie/Session ๊ธฐ๋ฐ
Lv4 ํต์ฌ์ ์ธ์ (HttpSession)์ ํ์ฉํด์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ๋ ๊ฒ.
๊ฐ๋ ์ ๋ฆฌ (Session / Cookie)
- ๋ก๊ทธ์ธ ์ฑ๊ณตํ๋ฉด ์๋ฒ๊ฐ ์ธ์ ์ ๋ง๋ค๊ณ ํด๋ผ์ด์ธํธ(Postman)์๊ฒ JSESSIONID ์ฟ ํค๋ฅผ ๋ด๋ ค์ค๋ค
- ์ดํ ์์ฒญ๋ง๋ค ํด๋ผ์ด์ธํธ๊ฐ ์ฟ ํค๋ฅผ ๊ฐ์ด ๋ณด๋ด๋ฉด ์๋ฒ๋ ์, ์ด ์ฌ์ฉ์๋ ๋ก๊ทธ์ธ ๋์ด ์๊ตฌ๋”๋ฅผ ํ๋จํ ์ ์๋ค
Lv4 ์๊ตฌ์ฌํญ
- ์ด๋ฉ์ผ + ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธ
- Cookie/Session์ผ๋ก ๋ก๊ทธ์ธ ์ํ ์ ์ง
- ํ์ํ API์์ ์ธ์ ์ ํ์ฉํด์ ์ธ์ฆ ์ฒดํฌ
Lv4์์ ์ถ๊ฐ๋ ํ์ผ๋ค
- controller/AuthController
- dto/LoginRequest
- service/AuthService ๋๋ UserService์ ๋ก๊ทธ์ธ ๋ก์ง ์ถ๊ฐ
Lv4 ํต์ฌ ๊ตฌํ 1) ๋ก๊ทธ์ธ API
- POST /api/auth/login
- email/password ๊ฒ์ฆ ์ฑ๊ณต ์
- HttpSession์ ๋ก๊ทธ์ธ ์ ์ id ์ ์ฅ
์์ ํ๋ฆ:
session.setAttribute(LOGIN_USER_ID, user.getId());
Lv4 ํต์ฌ ๊ตฌํ 2) ๋ก๊ทธ์์ API
- POST /api/auth/logout
- ์ธ์ ๋ฌดํจํ
session.invalidate();
Lv4 ํต์ฌ ๊ตฌํ 3) ์ผ์ ์์ฑ์ ์ธ์ ์ธ์ฆ ์ ์ฉ
Lv2๊น์ง ์ผ์ ์์ฑ์ userId๋ฅผ body๋ก ๋ฐ์๋๋ฐ
Lv4๋ถํฐ๋ ๋ก๊ทธ์ธ ์ธ์
์์ userId๋ฅผ ๊บผ๋ด์ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝ.
- ํด๋ผ์ด์ธํธ๋ userId๋ฅผ ๋ณด๋ด์ง ์๋๋ค
- ์๋ฒ๊ฐ ์ธ์ ์์ ๊บผ๋ธ id๋ก๋ง ์์ฑํ๋ค
@PostMapping
public ResponseEntity<ScheduleResponse> create(@RequestBody ScheduleRequest request, HttpSession session) {
Long loginUserId = (Long) session.getAttribute(AuthController.LOGIN_USER_ID);
if (loginUserId == null) {
throw new IllegalArgumentException("๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค.");
}
return ResponseEntity.ok(scheduleService.create(loginUserId, request));
}
Postman ๊ฒ์ฆ ์์ (Lv4)
1) ํ์๊ฐ์ (password ํฌํจ)
POST /api/users
{
"username": "jimin3",
"email": "jimin3@test.com",
"password": "11223344"
}

2) ๋ก๊ทธ์ธ (์ธ์ ์ฟ ํค ๋ฐ๊ธ)
POST /api/auth/login
{
"email": "jimin3@test.com",
"password": "11223344"
}

์๋ต ํค๋์์ Set-Cookie: JSESSIONID=... ํ์ธ

3) ์ผ์ ์์ฑ (์ด์ userId ๋ณด๋ด์ง ์์)
POST /api/schedules
{
"title": "์ธ์
์ผ์ ",
"content": "๋ก๊ทธ์ธ ์ํ๋ก ์์ฑ"
}

4) ๋ก๊ทธ์์ ํ ์ผ์ ์์ฑ ์ฌ์๋
POST /api/auth/logout
๊ทธ ๋ค์ ๋ค์ POST /api/schedules ์์ฒญ



-> ์ค๋ฅ ๋ฐ์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์
ํธ๋ฌ๋ธ์ํ ์ ๋ฆฌ
1) Auditing์ธ๋ฐ updatedAt์ด ์ ๋ฐ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์
ํ์
PATCH ํ ์๋ต์ ๋ดค๋๋ฐ updatedAt์ด createdAt์ด๋ ๋๊ฐ์ด ๋ณด์๋ค.

์์ธ(๊ฐ๋ฅ์ฑ)
- ์์ฒญ์ ๋๋ฌด ๋นจ๋ฆฌ ์ฐ์์ผ๋ก ๋ณด๋ด์ ์๊ฐ์ด ๊ฐ์ ์ด๋ก ์ฐํ
- ํน์ update๊ฐ ์ค์ ๋ก flush/dirty checking ๋๊ธฐ ์ ์ ์๋ต์ ๋ง๋ ๊ฒฝ์ฐ
ํด๊ฒฐ/ํ์ธ ๋ฐฉ๋ฒ
- Postman์์ ์์ ์์ฒญ์ ๋ช ์ด ํ ์ ๋๊ณ ๋ค์ ์คํ
- DB์์ ์ง์ ํ์ธ (select) ํน์ GET ์กฐํ๋ก updatedAt ๋ณํ ํ์ธ
2) @NotBlank๋ฅผ Long(userId)์ ๊ฑธ์ด์ ํฐ์ง (HV000030)
ํ์
No validator could be found for constraint 'NotBlank' validating type 'Long'
์์ธ
- @NotBlank๋ ๋ฌธ์์ด(String) ์ ์ฉ์ด๋ค.
- ์ซ์(Long)์ ์ฐ๋ฉด ๊ฒ์ฆ๊ธฐ๊ฐ ์์ด์ ์์ธ ๋ฐ์.
ํด๊ฒฐ
- Long์๋ @NotNull์ ์จ์ผ ํ๋ค.
@NotNull(message="userId๋ ํ์์
๋๋ค.")
private Long userId;
3) 500 Internal Server Error๋ก ์ผ์ ์์ฑ์ด ์คํจ
ํ์
Postman์์ ์ผ์ ์์ฑ ์ 500์ด ๋ฐ์ํ๋ค.
์ฒดํฌํ๋ ๊ฒ
- userId๊ฐ ์ค์ ์กด์ฌํ๋์ง (GET /api/users)
- DB ํ ์ด๋ธ ๊ตฌ์กฐ ๋ณ๊ฒฝ์ด ๋ฐ์๋์๋์ง (user_id ์ปฌ๋ผ ์กด์ฌ ์ฌ๋ถ)
- Schedule ์์ฑ์๊ฐ (User, title, content)๋ก ๋ง๊ฒ ๋์ด ์๋์ง
๊ฒฐ๋ก
๋๋ถ๋ถ ์ด๋ฐ 500์
- ์ํฐํฐ/DTO ํ๋ ํ์ ๋ถ์ผ์น
- FK ์ปฌ๋ผ ๋ฏธ์์ฑ/์คํค๋ง ๋ฏธ๋ฐ์
- ์กด์ฌํ์ง ์๋ userId๋ก ์์ฑ ์๋
์ด ์ ์ค ํ๋์๋ค.
4) ํ์๊ฐ์ ์ Duplicate entry (email unique)
ํ์
Duplicate entry 'jimin2@test.com' for key 'users...'
์์ธ
- User.email์ unique=true๊ฐ ๊ฑธ๋ ค์์ด์
- ๊ฐ์ ์ด๋ฉ์ผ๋ก ๋ค์ ํ์๊ฐ์ ์ DB์์ ๋งํ
ํด๊ฒฐ
- ์ด๋ฉ์ผ์ ๋ค๋ฅธ ๊ฐ์ผ๋ก ํ ์คํธ
- ํน์ ๊ธฐ์กด ์ ์ ๋ ์ฝ๋ ์ญ์ ํ ์ฌ์๋
ํ๊ณ
์ฌ์ค ์ง๋ ๊ณผ์ ๋๋ ๋
๊ฐ ๋๋ฌธ์ ์ ๋๋ก ๊ตฌํํ์ง ๋ชปํด์ ์์ฌ์์ด ๋ง์ด ๋จ์์๋ค.
๊ตฌ์กฐ๋ฅผ ๊น๊ฒ ๊ณ ๋ฏผํ๊ธฐ๋ณด๋ค๋ ์ผ๋จ ๋์๊ฐ๊ฒ ๋ง๋๋ ๊ฒ์ ์ง์คํ ์๋ฐ์ ์์๊ณ , ์์ฑ๋์ ๋ํ ์์ฌ์์ด ์ปธ๋ค.
์ด๋ฒ ๊ณผ์ ๋ ์๊ฐ์ด ๋๋ํ์ง ์์์ง๋ง,
๊ทธ๋๋ ์ ๋ฒ๋ณด๋ค๋ ํจ์ฌ ์ ๊ฒฝ ์จ์ ๊ตฌ์กฐ๋ฅผ ์ก๊ณ , ๋ ๋ฒจ๋ณ ์๊ตฌ์ฌํญ์ ์ ํํ ์ดํดํ๊ณ , ๋จ๊ณ์ ์ผ๋ก ๊ตฌํํด๋๊ฐ ์ ์์๋ ์ ์ด ์ค์ค๋ก ๋ง์กฑ์ค๋ฝ๋ค.
ํนํ ์ด๋ฒ ๊ณผ์ ๋ฅผ ํตํด ๊นจ๋ฌ์ ์ ์
- ์ฒ์ ์ค๊ณ๋ฅผ ์ด๋ป๊ฒ ํ๋๋์ ๋ฐ๋ผ ์ดํ ์์ ๋์ด๋๊ฐ ์์ ํ ๋ฌ๋ผ์ง๋ค
- DTO์ Entity๋ฅผ ๋ถ๋ฆฌํด๋๋ ๊ฒ์ด ์ผ๋ง๋ ์ค์ํ์ง ์ฒด๊ฐํ๋ค
- ์ฐ๊ด๊ด๊ณ๋ฅผ ์ ์ฉํ๋ฉด ๋จ์ ๋ฌธ์์ด ์ ์ฅ๊ณผ๋ ์ฐจ์์ด ๋ค๋ฅด๋ค
- ์ธ์ ์ธ์ฆ์ ๊ฐ๋ ์ผ๋ก ์๋ ๊ฒ๊ณผ ์ค์ ๊ตฌํ์ ์์ ํ ๋ค๋ฅด๋ค
- ์๋ฌ๋ฅผ ๋ง์ฃผ์ณค์ ๋ ๋นํฉํ์ง ์๊ณ ํ๋์ฉ ์์ธ์ ์ขํ๊ฐ๋ ๊ณผ์ ์ด ์ค์ํ๋ค
์ด์ ๋์ ๊ธฐ๋ฅ์ ํตํด ์์ธ์ฒ๋ฆฌ์ Validation๊น์ง ์ ๋ฆฌํ๋ฉด์
ํ๋ก์ ํธ๋ฅผ ๋ ๋ค๋ฌ์ด๋ณด๊ณ ์ถ๋ค.