🧭
@ModelAttribute,@RequestBody
@Valid,@Validated는
@ModelAttribute와@RequestBody모두에 적용할 수 있음- 다만, 데이터 바인딩 방식과 검증 실패 시 동작은 완전히 다름
🧷 @RequestBody 사용 시 검증 흐름
📜 DTO 클래스
@Data
public class ExampleRequestDto {
@NotBlank
private String field1;
@NotNull
@Range(min = 1, max = 150)
private Integer field2;
}
💡 컨트롤러
@PostMapping("/example")
public Object save(
@Validated @RequestBody ExampleRequestDto dto,
BindingResult bindingResult
) {
if (bindingResult.hasErrors()) {
return bindingResult.getAllErrors(); // JSON 반환
}
return dto;
}
🧪 Rest API 요청 3가지 경우
1. 성공 요청
🖼️ 결과:
→ Controller 정상 호출
→ DTO 반환
2. 변환 실패 (JSON → DTO 불가)
field2에 숫자가 아닌 문자열 입력🖼️ 결과:
→ JSON 변환 단계에서 실패
→ Controller 호출 ❌
→ Validation 진행 ❌
→ HTTP 400 Bad Request
⚠️ DTO 변환 실패는 검증 단계까지 가지 못함
3. 검증 실패 (DTO 변환은 성공)
field2 = 1000 (조건: 최대 150)🖼️ 결과:
→ DTO 변환 성공
→ Controller 호출됨
→ bindingResult.hasErrors() = true
→ FieldError / ObjectError 응답
🧩 정리: @ModelAttribute vs @RequestBody
| 항목 | @ModelAttribute | @RequestBody |
|---|---|---|
| 바인딩 방식 | 필드 단위 바인딩 | 객체 단위 바인딩 |
| 실패 시 | 실패한 필드만 제외하고 나머지 검증 진행 | JSON 전체 변환 실패 시 Controller 호출 ❌ |
| Controller 호출 여부 | 대부분 호출됨 | JSON 파싱 실패 시 호출 ❌ |
| 검증 적용 시점 | 바인딩 후, 개별 필드 기준 | 변환 후, 전체 객체 기준 |
→ @ModelAttribute는 일부 실패해도 나머지 필드는 검증 가능
→ @RequestBody는 객체로 전체 변환이 성공해야 검증 적용 가능
🛠️ 추가 팁
bindingResult.getAllErrors()FieldError, ObjectError 모두 포함 (자동 JSON 변환됨)📌 DTO 분리의 중요성
Request DTO는 API 목적에 맞게 따로 분리해서 사용하는 것이 안전