POST /api/memos { "title": "", ... }
PUT /api/memos/{id} { "title": " ", ... }
이전에는 Service에서 validateTitle()로 막고 ApiException을 던졌다.
이번엔 요청 DTO + @Valid 로 검증하고, 실패는 MethodArgumentNotValidException → 400.
| 이전 (Service 검증) | 이번 (Bean Validation) | |
|---|---|---|
| 검증 위치 | MemoService.validateTitle() | MemoRequestDto 필드 어노테이션 |
| 실패 예외 | ApiException (직접 throw) | MethodArgumentNotValidException (Spring이 throw) |
| 요청 타입 | MemoVO (조회 조건 필드 포함) | MemoRequestDto (create/update 전용) |
MemoVO는 목록 조회용 keyword / offset 등이 섞여 있다.
쓰기 API는 필요한 필드만 받는 DTO로 분리하는 게 맞다.
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.3.Final</version>
</dependency>
Spring 4.3 기준이라 Hibernate Validator 5.x 사용.
(@NotBlank는 org.hibernate.validator.constraints.NotBlank)
public class MemoRequestDto {
@NotBlank(message = "title은 필수입니다")
private String title;
private String content;
private String status;
// getter / setter
}
title만 @NotBlank — 빈 문자열·공백만 있어도 실패"title은 필수입니다"@Valid@PostMapping
public void insert(@Valid @RequestBody MemoRequestDto request) {
memoService.insertMemo(request.getTitle(), request.getContent(), request.getStatus());
}
@PutMapping("/{id}")
public void update(@PathVariable int id, @Valid @RequestBody MemoRequestDto request) {
memoService.updateMemo(id, request.getTitle(), request.getContent(), request.getStatus());
}
@Valid가 있어야 DTO 어노테이션 검증이 돈다@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNotValidException e) {
String message = "입력값이 올바르지 않습니다";
FieldError fieldError = e.getBindingResult().getFieldError();
if (fieldError != null && fieldError.getDefaultMessage() != null) {
message = fieldError.getDefaultMessage();
}
Map<String, String> error = new HashMap<>();
error.put("message", message);
return ResponseEntity.badRequest().body(error);
}
응답 예:
{ "message": "title은 필수입니다" }
기존 ApiException(404 등) 핸들러는 그대로 둔다.
검증은 Controller 진입 전에 끝나므로 Service에서는 제거.
insert / update는 저장만 담당.
Create (400)
POST http://localhost:8080/playground/api/memos
{ "title": "", "content": "내용", "status": "READY" }
Update (400)
PUT http://localhost:8080/playground/api/memos/1
{ "title": " ", "content": "내용", "status": "READY" }
정상 (200)
{
"title": "제목",
"content": "내용",
"status": "READY"
}
POST / PUT 시 title 빈값 → 400 Bad Request{ "message": "title은 필수입니다" } (이전과 동일)Controller: @Valid @RequestBody MemoRequest
→ Bean Validation 실패 시 MethodArgumentNotValidException
→ GlobalExceptionHandler: 400 + message JSON
pom.xml validation 의존성MemoRequestDto + @NotBlank@ValidMethodArgumentNotValidExceptionvalidateTitle() 제거ApiException@Valid + Binding 예외