@Valid, @Validated

:(:(·2025년 3월 16일

4

목록 보기
1/2

@Valid

필드, DTO에 JSR-303, JSR-380 표준 검증 을 적용한다.

DTO에서 @Valid 적용

import jakarta.validation.constraints.*;

public class UserDTO {

    @NotBlank(message = "이름은 필수 입력 값입니다.")
    private String name;

    @Email(message = "올바른 이메일 형식이 아닙니다.")
    private String email;

    @NotNull(message = "나이는 필수 입력 값입니다.")
    @Min(value = 18, message = "나이는 18세 이상이어야 합니다.")
    private Integer age;

    // Getter, Setter 추가
}

Controller에서 @Valid 적용

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping("/")
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
        return ResponseEntity.ok("User created successfully");
    }
}

예외 처리 커스텀

기본적으로 @Valid가 실패하면 Spring Boot는 MethodArgumentNotValidException을 발생시킴 이를 커스텀하여 메시지 커스텀 가능

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> 
            errors.put(error.getField(), error.getDefaultMessage()));
        return ResponseEntity.badRequest().body(errors);
    }
}

Valid에서 사용할 수 있는 검증 어노테이션

1. 공통 어노테이션

- @NotNull: 값이 null이면 안 됨
- @NotEmpty: 값이 null이 아니면서 비어 있으면 안 됨
- @NotBlank: 공백을 포함한 빈 문자열도 허용되지 않음

2. 숫자 검증

- @Min(value): 최소값 지정
- @Max(value): 최대값 지정
- @Positive: 양수만 허용
- @Negative: 음수만 허용
- @PositiveOrZero: 0 또는 양수 허용
- @NegativeOrZero: 0 또는 음수 허용

문자열 관련 검증

- @Size(min, max): 문자열 길이 제한
- @Pattern(regexp): 정규식 패턴 적용
- @Email: 이메일 형식 검증

날짜 관련 검증

- @Future: 미래 날짜만 허용
- @Past: 과거 날짜만 허용
- @FutureOrPresent: 현재 또는 미래 날짜 허용
- @PastOrPresent: 현재 또는 과거 날짜 허용

Boolean 관련 검증

- @AssertTrue: 값이 true여야 함
- @AssertFalse: 값이 false여야 함

@Validated

@valid보다 확장된 기능을 제공한다.

  • 그룹검증 가능, 메서드 레벨 검증 가능

예시

기본 DTO생성

import jakarta.validation.constraints.*;

public class UserDTO {

    @NotBlank(message = "이름은 필수 입력 값입니다.")
    private String name;

    @Email(message = "올바른 이메일 형식이 아닙니다.")
    private String email;

    @Min(value = 18, message = "나이는 18세 이상이어야 합니다.")
    private Integer age;

    // Getter & Setter
}

Controller에서 @Validated적용

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping("/")
    public ResponseEntity<String> createUser(@Validated @RequestBody UserDTO userDTO) {
        return ResponseEntity.ok("User created successfully");
    }
}

@Validated의 확장 기능 - 그룹 검증

그룹 검증이 필요한이유

  • 회원 가입 시: 이름, 이메일, 나이 필수
  • 회원 정보 수정 시: 이름, 이메일만 필수
  • 두 상황에서 검증 기준이 다르므로 그룹 검증을 사용하여 다르게 처리할 수 있음

그룹검증 정의

public interface CreateUser {}
public interface UpdateUser {}

DTO에서 그룹 지정

public class UserDTO {

    @NotBlank(groups = CreateUser.class, message = "이름은 필수 입력 값입니다.")
    private String name;

    @Email(groups = {CreateUser.class, UpdateUser.class}, message = "올바른 이메일 형식이 아닙니다.")
    private String email;

    @Min(value = 18, groups = CreateUser.class, message = "나이는 18세 이상이어야 합니다.")
    private Integer age;
}

Controller에서 그룹 검증 적용

@PostMapping("/create")
public ResponseEntity<String> createUser(@Validated(CreateUser.class) @RequestBody UserDTO userDTO) {
    return ResponseEntity.ok("User created successfully");
}

@PutMapping("/update")
public ResponseEntity<String> updateUser(@Validated(UpdateUser.class) @RequestBody UserDTO userDTO) {
    return ResponseEntity.ok("User updated successfully");
}

@Validated의 확장 기능 - 메서드 레벨 검증

메서드 검증이 필요한 이유

  • Controller뿐만 아니라 Service 계층에서도 데이터 검증을 수행할 수 있어야 함
  • Service에서 잘못된 데이터가 들어오면 예외를 발생시켜야 함

@Validated를 이용한 Service 검증

@Service
@Validated
public class UserService {

    public void validateUser(@Valid UserDTO userDTO) {
        // 비즈니스 로직 수행
        System.out.println("Valid User: " + userDTO.getName());
    }
}

Controller에서 호출

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/validate")
    public ResponseEntity<String> validateUser(@RequestBody UserDTO userDTO) {
        userService.validateUser(userDTO);
        return ResponseEntity.ok("User validation passed");
    }
}

0개의 댓글