Web/Spring

Spring Bean Validation 적용하기

기존의 미션들에서 검증기능을 구현하려면 하나하나 다 짜주어야 했습니다.

 

블랙잭 미션의 수많은 검증코드들..

 

 

이제 스프링 부트 프로젝트에서는 @Validated 를 이용해 쉽게 유효성 검증을 수행할 수 있습니다.

 

이번 시간에는 간단하게 Bean Validation을 내 프로젝트에 적용시켜봅니다.

 

 

Bean Validation

 

스프링의 Bean Validation은 클래스 필드에 annotation을 적용하여 해당 필드에게 제약조건을 정의하는 구조입니다.

 

public class LineRequest {

    @NotBlank(message = "이름을 입력해주세요.")
    private String name;

 

앞으로 위의 코드처럼 필드에선 @NotBlank 어노테이션 만으로도 검증이 가능합니다.

 

 

 

 

 

 

적용 방법

순서는 간략하게 아래와 같습니다.

  1. 의존성 추가
  2. 검증하고 싶은 매개변수에 @Validated 어노테이션 붙이기
  3. 검증하고 싶은 필드에 검증 어노테이션 붙이기
  4. @ExceptionHandler로 예외처리하기

 

 

 

 

1. 의존성추가

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

 

참고로

 

implementation 'org.springframework.boot:spring-boot-starter-web'

가 추가가 되어있다고 하더라도 implementation 'org.springframework.boot:spring-boot-starter-validation' 도 따로 추가해주어야 합니다!

 

 

 

 

2. 검증하고 싶은 객체 앞에 @Validated 어노테이션 붙이기

 

 

저는 LineRequest 객체의 필드를 검증하고 싶으므로 매개변수의 인자인 LineRequest 앞에 @Validated 를 붙여주었습니다.

 

 

 

 

 

3. 검증하고 싶은 필드에 어노테이션 붙이기

 

 

저는 name을 검증하기 위해 name필드 앞에 어노테이션을 붙여주었습니다.

 

추가로, 보이는 것 처럼 원하는 default message도 지정할 수 있습니다.

 

아래와 같은 어노테이션들이 더 존재하고, 검증 어노테이션 더 보기 에 방문하시면 더 많은 검증 어노테이션을 볼 수 있습니다.

 

 

4. @ExceptionHandler로 예외처리하기

 

Bean Validation은 @Validated로 검증한 객체가 유효하지 않다면 BindingResult 에 결과를 담습니다.

그래서 컨트롤러 자체에서 BindingResult를 이용해 예외를 핸들링 해줄 수 있는데요.

controller에서 bindingresult를 주입받아 사용하는 방법

 

 

ExceptionHandler에서 BindException을 잡아서도 사용할 수 있습니다.

단, 이때 컨트롤러에서 BindingResult를 주입받지 않아야 합니다.

또한, exception의 bindingResult에서 fieldErrors의 메세지를 가져와 body에 담아줄 수도 있습니다.

 

 

이전에 LineRequest에 지정한 메세지도 잘 나오는 것을 볼 수 있습니다.

 

 

name에 null을 지정하고 요청을 보내면 Bad Request가 오는 테스트도 통과합니다.

    @Test
    @DisplayName("name을 지정하지 않고 요청하면 bad request 예외를 반환해야 한다.")
    void emptyName() {
        LineRequest lineRequest = new LineRequest(
            null,
            "bg-red-600",
            stationId1,
            stationId2,
            10
        );

        RestAssured.given().log().all()
            .contentType(MediaType.APPLICATION_JSON_VALUE)
            .body(lineRequest)
            .when()
            .post("/lines")
            .then().log().all()
            .statusCode(HttpStatus.BAD_REQUEST.value());
    }