[Spring Boot] Validation

Hood·2025년 3월 10일
0

Spring Boot

목록 보기
6/14
post-thumbnail

✍ Back-End 지식을 늘리자!

백엔드 개발자를 준비하며 생기는 의문들을 정리한 포스트입니다.


들어가기 전

Api에서 json데이터로 사용자에게 입력을 받다보면 간단하게 빈 값이 있는지 유효한 값을 넣고 있는지를
확인해야 할 때가 생깁니다. 이번 포스트에서는 사용자의 입력이 유효하지 않다면 화면에
오류 메시지를 표시하는 Validation 에 대해 알아볼까 합니다.


What is Valid?

Valid를 번역하면 유효한 이라는 형용사입니다.
그렇다면 Validation은 검증이라는 단어가 되며
이말은 즉 증명한 것을 실제 환경이나 조건에서 확인하고 정하는 의미입합니다.
그래서 Spring Boot에서는 시스템에 올바른 형식의 데이터가 입력되는지 확인하는 작업을 합니다.

예를 들어?

이메일을 클라이언트로 부터 전달받는 경우 String 타입의 데이터를 전달받지만,
그것이 이메일 형식을 지키는지 확인할 필요가 있습니다.

검증이 왜 필요할까?

현재 DTO 생성하면 그저 객체를 담는 그릇의 역할만 수행하고 있습니다.
예를 들어 제목이 비어도 API는 성공을 반환하고 데이터베이스에 공백 그대로 저장되게 됩니다.
그렇다면 요구사항에 따라서 DTO의 프로퍼티 당 적절한 Validation이 필요하게 됩니다.


Spring Boot에서는 어떻게 사용할 수 있을까?

1. 의존성 추가

Spring Boot는 Validation 라이브러리를 사용하면 개발자가 손쉽게 DTO에서 다양한 프로퍼티의
Validation 기능을 수행할 수 있습니다.

dependencies {implementation("org.springframework.boot:spring-boot-starter-validation")
	
}

Validation 라이브러리는 간단한 어노테이션을 이용해서 DTO 프로퍼티에서 손쉽게
Validation 작업을 할 수 있도록 도와줍니다.

2. 어노테이션

종류에 따라서 다음과 같은 어노테이션들이 존재합니다.

  • @NotNull: 해당 값이 null이 아닌지 검증함
  • @NotEmpty: 해당 값이 null이 아니고, 빈 스트링("") 아닌지 검증함 (" "은 허용됨)
  • @NotBlank: 해당 값이 null이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증함
  • @AssertTrue: 해당 값이 true인지 검증함
  • @Size: 해당 값이 주어진 값 사이에 해당하는지 검증함(String, Collection, Map, Array에도 적용 가능)
  • @Min: 해당 값이 주어진 값보다 작지 않은지 검증함
  • @Max: 해당 값이 주어진 값보다 크지 않은지 검증함
  • @Pattern: 해당 값이 주어진 패턴과 일@NotNull: 해당 값이 null이 아닌지 검증함
  • @NotEmpty: 해당 값이 null이 아니고, 빈 스트링("") 아닌지 검증함 (" "은 허용됨)
  • @NotBlank: 해당 값이 null이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증함
  • @AssertTrue: 해당 값이 true인지 검증함
  • @Size: 해당 값이 주어진 값 사이에 해당하는지 검증함(String, Collection, Map, Array에도 적용 가능)
  • @Min: 해당 값이 주어진 값보다 작지 않은지 검증함
  • @Max: 해당 값이 주어진 값보다 크지 않은지 검증함
  • @Pattern: 해당 값이 주어진 패턴과 일치하는지 검증함

3. Valid 기능 사용

위의 어노테이션을 필요에 따라 DTO 클래스의 프로퍼티 위에 적절한 어노테이션을 붙여주며 검증하며
사용하고자 하는 API에도 @Valid 어노테이션을 파라미터 앞에 붙여주면 사용할 수 있습니다.

예시

//DTO
data class PostRequestDto(
    var id : Long?,

    @field:NotBlank(message = "제목은 반드시 입력해야 됩니다!")
    var title : String,

    @field:NotBlank(message = "내용은 반드시 입력해야 됩니다!")
    var post : String,

    @field:Min(value = 1, message = "유효하지 않은 사용자입니다.")
    var userId : Long,

    var isPublic : Boolean
)
/**
* 게시글을 생성하는 Api
*/
@PostMapping
private fun postPost(@Valid @RequestBody postRequestDto: PostRequestDto) 
    : ResponseEntity<BaseResponse<PostResponseDto>>
{
    val result = postService.postPosts(postRequestDto)
    return ResponseEntity.status(HttpStatus.CREATED).body(BaseResponse(data = result))
}

4. Exception

그렇다면 해당 Validation을 통과하지 못할 경우 MethodArgumentNotValidException이 발생합니다.
이를 이용해서 ExceptionHandling이 가능합니다.

다음은 @field:NotBlank(message = "제목은 반드시 입력해야 됩니다!") 유효성 검사를 통과하지 못한 오류이며
MethodArgumentNotValidException을 핸들링하여 BaseResponse에 해당 오류를 넣은 것입니다.
이처럼 ExcoptionHandling이 가능합니다.

@RestControllerAdvice
class CommonExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException::class)
    protected fun methodArgumentNotValidExceptionHandler(
        exception: MethodArgumentNotValidException
    ) : ResponseEntity<BaseResponse<Map<String, String>>> {
        var errors = mutableMapOf<String, String>()
        exception.bindingResult.allErrors.forEach { error ->
            val fieldName = (error as FieldError).field
            val errorMsg = error.defaultMessage
            errors[fieldName] = errorMsg ?: "에러 메시지가 존재하지 않습니다!"
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(
            BaseResponse(
                status = ResultStatus.ERROR.name,
                data = errors,
                resultMsg = ResultStatus.ERROR.msg,
            )
        )
    }
}


📌 결론

ExceptionHanding을 통한 요구사항에 맞는 유효성 검사를 구축해봅시다.

profile
달을 향해 쏴라, 빗나가도 별이 될 테니 👊

0개의 댓글