Contents
see ListSpring Validation이란?
Spring Validation은 Java Bean Validation(JSR-380)을 기반으로 입력값 검증을 어노테이션으로 선언적으로 처리하는 프레임워크입니다. 컨트롤러에서 DTO 유효성 검사를 간단하게 수행할 수 있습니다.
언제 사용하나요?
- 회원가입, 로그인 폼에서 필수값/이메일/비밀번호 형식 검증
- API 요청 파라미터 유효성 검사
- 비즈니스 로직 수행 전 데이터 무결성 확보
의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>주요 어노테이션
public class UserDto {
@NotBlank(message = "이름은 필수입니다")
private String name;
@Email(message = "이메일 형식이 아닙니다")
private String email;
@Size(min = 8, max = 20, message = "비밀번호는 8-20자")
private String password;
@Min(value = 1, message = "나이는 1 이상")
@Max(value = 150, message = "나이는 150 이하")
private int age;
@Pattern(regexp = "^01[016789]-\\d{3,4}-\\d{4}$",
message = "휴대폰 번호 형식이 아닙니다")
private String phone;
}컨트롤러에서 검증
@PostMapping("/users")
public ResponseEntity<?> createUser(
@Valid @RequestBody UserDto dto,
BindingResult result) {
if (result.hasErrors()) {
List<String> errors = result.getFieldErrors()
.stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(errors);
}
return ResponseEntity.ok(userService.create(dto));
}커스텀 Validator 만들기
// 커스텀 어노테이션
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
String message() default "유효하지 않은 전화번호";
Class<?>[] groups() default {};
Class<?>[] payload() default {};
}
// Validator 구현
public class PhoneValidator
implements ConstraintValidator<Phone, String> {
@Override
public boolean isValid(String value,
ConstraintValidatorContext ctx) {
if (value == null) return true;
return value.matches("^01[016789]-\\d{3,4}-\\d{4}$");
}
}그룹별 검증
// 그룹 인터페이스
public interface OnCreate {}
public interface OnUpdate {}
// DTO에서 그룹 지정
public class UserDto {
@Null(groups = OnCreate.class)
@NotNull(groups = OnUpdate.class)
private Long id;
@NotBlank(groups = {OnCreate.class, OnUpdate.class})
private String name;
}
// 컨트롤러에서 그룹 적용
@PostMapping
public void create(@Validated(OnCreate.class) @RequestBody UserDto dto) {}
@PutMapping
public void update(@Validated(OnUpdate.class) @RequestBody UserDto dto) {}글로벌 예외 처리
@RestControllerAdvice
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidation(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(e ->
errors.put(e.getField(), e.getDefaultMessage())
);
return ResponseEntity.badRequest().body(errors);
}
}자주 쓰는 어노테이션 정리
| 어노테이션 | 설명 |
|---|---|
| @NotNull | null 불가 |
| @NotEmpty | null, "" 불가 |
| @NotBlank | null, "", " " 불가 |
| @Size | 문자열/컬렉션 크기 |
| 이메일 형식 | |
| @Past/@Future | 과거/미래 날짜 |
| @Positive | 양수만 |