[Spring] SpringBoot 의 Validation

백엔ㄷ현·2024년 10월 16일
유효성 검증을 백엔드에서 제대로 다뤄본게 이번 프로젝트가 처음인거 같다. 이전에는 비즈니스 로직에서 조건문을 통해서 유효성 검증을 했던 기억만 있어서 이번에 스프링부트의 Validation 에 대해 정리하고 기록을 해놓는다.

Spring Boot 의 Validation 은 애플리케이션에서 입력값의 유효성을 검증하는 중요한 기능중에 하나이다. jakarta.validation 또는 javax.validation 표준 어노테이션을 사용하여 유효성 검사를 간편하게 수행 할 수 있도록 지원한다.



1. Validation 기본 원리

유효성 검사는 주로 컨트롤러의 입력 값이나 DTO(Data Transfer Object) 에서 이루어진다.
먼저, Validation 을 사용하기 위한 의존성을 추가해야 한다.

  • 의존성 추가 DI (Dependency Injection)

    <!-- Maven 프로젝트 pom.xml-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    // gradle 프로젝트 build.gradle
    implementation 'org.springframework.boot:spring-boot-starter-validation'
  • 유효성 검사를 위한 주요 어노테이션

    어노테이션설명
    @NotNull: 값이 null이 아닌지 검사
    @NotEmpty: 문자열, 컬렉션 등이 null이거나 비어있지 않은지 검사
    @NotBlank: 문자열이 null, 공백이 아닌지 검사 (공백만 있어도 실패)
    @Size: 문자열, 배열, 컬렉션 등의 크기 또는 길이를 제한
    @Min: 값의 최소값을 제한 (숫자형 데이터)
    @Max: 값의 최대값을 제한
    @Positive: 값이 양수인지 검사
    @Negative: 값이 음수인지 검사
    @Email: 이메일 형식인지 검사
    @Pattern: 정규 표현식을 사용하여 값이 특정 패턴과 일치하는지 검사


2. Validation 를 적용한 예시 코드

  • DTO 클래스에서의 유효성 검사 :

    유효성 검사는 주로 DTO 클래스에서 어노테이션을 통해 이루어진다. 예시 코드를 회원가입 요청에 대한 유효성 검사 코드를 작성했다.
    @Getter
    @NoArgsConstructor
    public class SignupRequestDto {
    	
    	@NotBlank(message = "유저명을 입력하세요.")
    	@Size(min = 3, max = 15, message = "유저명은 3 ~ 15자 이내여야 합니다.")
    	private String username;
    
    	@NotBlank(message = "비밀번호를 입력하세요.")
    	@Size(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.")
    	private String password;
    
    	@NotBlank(message = "이메일을 입력하세요.")
    	@Email(message = "올바른 이메일 형식을 입력하세요.")
    	private String email;
    }
    위와 같이 DTO 클래스에 유효성 검사 어노테이션을 추가하여 사용자 입력 데이터를 검증하게 된다.

  • 컨트롤러에서 유효성 검사 :

    컨트롤러에서 @Valid 또는 @Validated 어노테이션을 사용하여 유효성 검사를 실행한다. 유효성 검사 결과는 BindingResult 객체를 사용하여 확인 할 수 있다.
    @RestController
    @RequestMapping("/api/auth")
    public class UserController {
    
      // 회원가입 요청
      @PostMapping("/signup")
      public ResponseEntity<String> signup(@Valid @RequestBody SignupRequestDto requestDto,
    										BindingResult bindingResult) {
          // 유효성 검사 실패 시 처리
          if (bindingResult.hasErrors()) {
              StringBuilder errorMessage = new StringBuilder();
              bindingResult.getAllErrors().forEach(error -> errorMessage.append(error.getDefaultMessage()).append("\n"));
              return ResponseEntity.badRequest().body(errorMessage.toString());
          }
          
          // 정상적인 회원가입 로직 처리
          return ResponseEntity.ok("회원가입 성공");
      }
    }
    @Valid 요청 바디에 있는 DTO 클래스에 대해 유효성 검사를 수행하게 된다. BindingResult 은 유효성 검사 결과를 받는 객체로, 유효성 검사가 실패했을 때 발생하는 오류 정보를 제공한다.

이외에도 커스텀 유효성 검사나 Validator 구현하는 방법이 있는데 자주 쓰지는 않는 방법이라 생략한다.


3. ExceptionHandler 를 사용한 전역 유효성 검사 처리

전역적으로 유효성 검사 실패를 처리하고 싶은 경우 @ControllerAdvice@ExceptionHandler 를 사용할 수 있다.

@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
      BindingResult bindingResult = ex.getBindingResult();
      StringBuilder errorMessage = new StringBuilder();

      bindingResult.getAllErrors().forEach(error -> errorMessage.append(error.getDefaultMessage()).append("\n"));

      return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMessage.toString());
  }
}



공부, 기록하면서 느낀점

스프링 부트의 Validation 은 아주 편리한 기능인걸 직접 써보면서 체감하였다. 이전에 프로젝트 만들때는 직접 조건문으로 하나하나 유효성 검사를 했었는데 코드도 길어지고 가독성면에서도 한참 떨어진 것을 느꼈다. 이번 과제 프로젝트를 하면서 ExceptionHandler 를 구현해보기는 했지만, 에러 메시지 출력도 뒤죽박죽이고 제대로 작동을 안하는 것 같았다. 좀 더 다듬으면 전역적으로 유효성 검사 실패에 대해 공통적으로 에러를 처리할 수 있을 것 같다.
profile
매일매일 공부한 내용과 코드 기록하겠습니다

0개의 댓글