코딩 하는 가든

spring - validation (유효성 검사) 하기 본문

Spring (boot)

spring - validation (유효성 검사) 하기

가든리 2020. 9. 7. 23:13

Validation을 해보자

웹 개발을 하다 보면 서버에 들어온 요청이 서버에서 요구하는 스펙에 잘 맞게 들어왔는지 검사해야 할 필요가 있습니다.

 

예를 들어 회원가입을 할 때 이름은 필수로 들어와야 한다던지, 나이는 0보다 커야 한다던지 같은 것 입니다.

 

물론 이런 식으로 들어온 요청에 대해 검사를 할 수도 있을 것입니다.

//이름이 비어있으면 exception을 던진다.
if (request.getName() == null) {
	throw Exception;
}

// 나이가 0보다 작으면 exception을 던진다.
if (request.getAge() < 0) {
	throw Exception;
}

 

하지만 점점 커지는 웹 어플리케이션 에서 위처럼 요청에 대한 검사를 하다 보면 필드가 늘어남에 따라 코드의 대부분이 유효성 검사 코드로 뒤덮일 것입니다.

 

스프링에서는 이런 상황을 방지하기 위해서 손쉽게 Validation을 하기 위 전략 중 하나로 Hibernate Bean Validator를 사용할 수 있습니다.

 

Hibernate Bean Validator는 유효성 검사를 해야 하는 필드에 @NotEmpty, @NotNull, @Max와 같은 어노테이션을 붙여줌으로써 유효성 검사를 진행할 수 있습니다.

 

 

Bean Validator 사용 하기

먼저 Hibernate bean validator에 대한 의존성 설정을 해야 합니다.

 

pom.xml

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>6.1.5.Final</version>
</dependency>

 

스프링 부트 + gradle를 사용할 경우는 다음과 같이 해줍니다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-validation'

	// 기타 의존성
}

 

 

예시를 위해 간단한 회원가입 시 사용할 Dto 클래스를 만들어 보았습니다.

public class MemberDto {
    
    private String realName;
    
    private String password;
    
    private String nickName;
    
    private int age;
}

 

회원 가입을 위해서는 [이름, 비밀번호, 닉네임, 나이]가 필요합니다.

 

@RestController
public class MemberController {

    @PostMapping("/member")
    public String createMember(@RequestBody MemberDto memberDto) {
        System.out.println("memberDto.getRealName() = " + memberDto.getRealName());
        System.out.println("memberDto.getPassword() = " + memberDto.getPassword());
        System.out.println("memberDto.getNickName() = " + memberDto.getNickName());
        System.out.println("memberDto.getAge() = " + memberDto.getAge());
        // 비지니스 로직이 들어가는 자리.
        return "성공!";
    }
}

간단하게 "/member"에 MemberDto를 RequestBody로 받아보았습니다.

 

아래 보이는 것처럼 Postman을 통해 요청을 보내 보니 요청이 제대로 도달한 것을 알 수 있습니다.

 

하지만 여기서 RealName이나 Password를 보내지 않으면 어떻게 될까요?

Password를 빼고 보내도 Password가 null로 찍힐 뿐 요청을 처리하는데 아무 문제가 없었습니다.

 

하지만 우리는 요청으로 받는 Request의 Body에 RealName과 Password가 Null이면 요청을 거부하고 예외 처리를 해주고 싶습니다.

 

그럴 때는 아래와 같이 RequestBody를 받는 부분 앞에 @Valid 어노테이션을 붙여줍니다.

 

그리고 Dto 클래스에 가서 Non-Nullable 하게 만들고 싶은 필드에 @NotNull 어노테이션을 달아줍니다.

public class MemberDto {

    @NotNull
    private String realName;

    @NotNull
    private String password;

    private String nickName;
    
    private int age;
}

 

이 상태에서 다시 Password를 빼고 요청을 보내보면!?

클라이언트에서 요청을 잘못했다는 400 status code와 함께 에러 리스폰스를 응답해 준 것을 볼 수 있습니다.

 

서버 쪽에는 아래와 같이 MethodArgumentNotValidException이 발생하게 됩니다.

Resolved [org.springframework.web.bind.MethodArgumentNotValidException: 
Validation failed for argument [0] in public java.lang.String 
garden.practice.validation.MemberController.createMember
(garden.practice.validation.MemberDto): 
[Field error in object 'memberDto' on field 'password': rejected value [null];
codes [NotNull.memberDto.password,NotNull.password,NotNull.java.lang.String,NotNull]; 
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberDto.password,password]; 
arguments []; default message [password]]; default message [널이어서는 안됩니다]] ]

 

우리는 이런 에러를 exception handler를 통해 응답에 메세지를 담아 넘겨주는 등의 행위를 할 수 있을 것입니다.

 

Bean Validator 에는 @NotNull 어노테이션뿐 아니라 @NotEmpty, @Max, @Min, @Length와 같은 여러 가지 어노테이션이 존재합니다.

 

어떤 어노테이션이 존재하는지는 공식 문서 (docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-builtin-constraints) 에 가면 자세히 나와 있습니다.

 

또한 javax.validation.constraints 패키지에 가면 어노테이션의 구성을 볼 수 도 있으니 궁금하신 분들은 찾아보시길 바랍니다.

 

이렇게 Bean Validation의 사용법에 대해 알아보았습니다.