[Spring Boot] Validation annotation

SeongWon Oh·2021년 9월 5일
0

Spring Framework

목록 보기
10/33
post-thumbnail

Request Validation이란?

HTTP request를 통해 Post Request와 같이 데이터를 받는 request를 받을 경우 데이터가 옳바른 형식인지, 옳바른 값인지 확인을 하고 만약 옳지 않은 값이 들어온다면 Bad request를 보내야 할 것이다.

{
  "name": "홍길동",
  "age":15,
  "email":"qwewqd",
  "phoneNumber":"0111111"
}

예를 들어 위의 Json형식의 데이터가 POST request의 Body로 넘어왔다고 생각해보자. 위의 데이터를 보면 Email형식이 맞지 않고 전화번호의 형식 또한 일반적인 xxx-xxxx-xxxx의 형태가 아닌 것을 확인 할 수 있다.

오늘은 이러한 Request의 잘못된 Data를 Validation하는 방법에 대해 알아보고자 한다.


초기의 Validation방법

과고에는 Request body의 validation을 아래와 같이 if문을 사용하여 값의 오류를 체크하고
조건에 만족하지 못하면 bad request를 보내는 식으로 오류를 발생시켰다.
하지만 이러한 방식은 적은 data에 대해서 조건을 걸면 크게 문제가 없지만 여러개의 data에 대해 하나씩 조건을 걸기에는 코드의 길이가 길어지고 복잡해질 것이다. 또한 구현에 따라 Service logic과의 분리가 필요하며 코드가 흩어져 있는 경우 어디에서 검증을 하는지 알기 어려우며 재사용의 한계가 있다.

    @PostMapping("/user")
    public ResponseEntity user(@RequestBody User user){
        if(user.getAge() >= 90)
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(user);
        return ResponseEntity.ok(user);
    }

그래서 요즘에는 이러한 방법을 사용하지 않고 대신 validation annotation을 사용하여 쉽게 확인을 한다.


Validation annotation

Valicatoin annotation의 종류

  • @AssertFalse -> 주석이 달린 요소는 거짓이어야한다.
  • @AssertTrue -> 주석이 달린 요소는 참이어야한다.
  • @Email -> 주석이 달린 문자열은 이메일 형식이어야한다.
  • @Future -> 주석이 달린 요서는 미래의 날짜, 또는 시간이어야한다.
  • @Past -> 주석이 달린 요서는 과거의 순간, 날짜 또는 시간이어야한다.
  • @Max(value=) -> 주석이 달린 요소는 value보다 작거나 같아야한다.
  • @Min(value=) -> 주석이 달린 요소는 value보다 크거나 같아야한다.
  • @NotBlank -> 주석이 달린 요소는 Null이 아니어야하며 하나 이상의 공백이 아닌 문자를 포함해야한다.
  • @NotEmpty -> 주석이 달린 요서는 Null이거나 비어있으면 안된다.
  • @Pattern(regexp=, message=) -> 주석이 달린 문자열은 regexp에 지정된 정규식과 일치하여야한다.
  • @Size(min=, max=) -> 주석이 달린 요소의 크기는 해당 범위 내에 있어야한다.

초기 Setting

Gradle dependencies에 implementation 'org.springframework.boot:spring-boot-starter-validation'추가하기


Validation annotation사용하기

public class User {

    @NotBlank // 공백 허용안함
    private String name;

    @Max(value = 90)
    private int age;

    @Email // -> email형식이 아닌 데이터가 들어오면 오류 발생시킨다.
    private String email;

    @Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "핸드폰 번호의 약식과 맞지 않습니다. xxx-xxxx-xxxx")
    // 받아들이는 문자의 형태를 직접 제한하는 방법 (정규식을 사용)
    // message에는 error가 발생했을 때 출력할 메세지를 적는다.
    private String phoneNumber;
    
    .....
    
}

Validatoin annotation을 사용하기 위해서는 DTO객체의 variable위에 데이터의 제한을 하고싶은 annotation을 추가해줘야한다.

위의 User class를 보면 name의 경우는 공백을 제한하기 위해 @NotBlank를 추가하였으며, age의 경우 @Max값을 90으로 제한하여 90이상의 값이 들어오면 Error를 발생시키는 등의 제한을 하였다.
또한 email의 경우 @Email annotation을 통해 email형식이 들어오는지 확인을 해주며, PhoneNumber의 경우는 @Pattern과 정규식을 통해 전화번호 형태를 제한하였다.
(정규식의 경우 필요에 따라 구글을 통해 찾아보고 사용하면 된다.)

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user){
        return ResponseEntity.ok(user);
    }

Validation annotation이 사용된 class를 사용하여 Request를 받기 위해서는 Method의 parameter에 @Valid를 추가해줘야한다.

위의 코드를 실행하였을 때 결과를 확인해보자

validation annotation을 추가하기만 하였음에도 불구하고 형식이 맞지 않는 data를 전송하였을 때 HTTP status 400을 return하는 것을 확인할 수 있었습니다.


Error 내용 return하기

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user, BindingResult bindingResult){
       
        if(bindingResult.hasErrors()){
            StringBuilder sb = new StringBuilder();
            bindingResult.getAllErrors().forEach(objectError -> {
                FieldError field = (FieldError) objectError;
                String message = objectError.getDefaultMessage();

                System.out.println("Field : "+ field.getField());
                System.out.println(message);

                sb.append("Field : "+ field.getField());
                sb.append("message: "+message);
                sb.append("\n\n");
            });
            // 조건에 맞지 않는다면 Badrequest와 error출력
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(sb.toString());
        }

        return ResponseEntity.ok(user);
    }


Reference

profile
블로그 이전했습니다. -> https://seongwon.dev/

0개의 댓글