클라이언트로부터 입력받은 값을 사용하기 전, 올바른 값이 넘어왔는지 검증이 필요하다. Spring Bean Validation 은 값 또는 객체 내부의 값이 올바른 값인지 확인하는 기능을 제공한다.

Dependency

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

스프링에서 제공하는 Bean 객체 검증을 하기 위해서는 해당 의존성을 추가해야 한다.

값 검증

@GetMapping("/{id}")
public ResponseEntity<LineResponse> showLine(@PathVariable @NotBlank Long id) {
    Line line = lineService.find(id);
    LineResponse lineResponse = LineResponse.of(line);
    return ResponseEntity.ok().body(lineResponse);
}

위의 코드는 입력받은 id 의 Line 을 찾아 반환해주는 메서드이다. 입력받은 파라미터가 빈값인지 null 인지 따로 검증할 수 있다. 하지만 스프링에서는 쉽게 검증할 수 있도록 어노테이션을 제공한다. @NotBlank 는 입력받은 Long 타입의 id 값이 null 이 아니며 빈값이 아닌지 검증한다. 입력받은 파라미터가 다음과 같이 단순한 값일 경우에는 파라미터와 같은 위치에서 간단하게 검증할 수 있다.

객체 검증

@Valid

하지만 객체 내부의 값은 위의 방법으로는 확인이 어렵다. 객체 내부의 값들의 검증을 할 수 있도록 별도의 어노테이션을 제공한다.

@PostMapping
public ResponseEntity<LineResponse> createLine(@RequestBody @Valid LineRequest lineRequest) {
    Line line = new Line(lineRequest.getName(), lineRequest.getColor());
    long lineId = lineService.save(line);
    LineResponse lineResponse = new LineResponse(lineId, line.getName(), line.getColor());
    return ResponseEntity.created(URI.create("/lines/" + lineId)).body(lineResponse);
}

위의 코드는 JSON 으로 입력한 Line 의 정보를 자바 객체로 바꾸어 정보를 등록하는 메서드이다. 객체 내부의 값들 대부분을 검증해야 한다. 검증을 하는 객체임을 알리기 위해 @Valid 어노테이션을 붙여준다. @Valid 는 해당 어노테이션이 붙은 객체 내에 있는 모든 검증을 수행한다. @RequestBody 로 받아온 객체 내부의 값을 검증한다.

public class LineRequest {

    @NotBlank
    private String name;

    @NotBlank
    private String color;

    private Long upStationId;
    private Long downStationId;
    private int distance;

    private LineRequest() {
    }

    public LineRequest(String name, String color, Long upStationId, Long downStationId, int distance) {
        this.name = name;
        this.color = color;
        this.upStationId = upStationId;
        this.downStationId = downStationId;
        this.distance = distance;
    }
		
		// 생략
}

각 값들의 세부 검증은 객체 내부에서 해준다. name 과 color 가 null 또는 빈값이 되지 않도록 하였다.

@Validated

@Validated@Valid 와는 달리 객체 내에서 검증하고 싶은 값을 상황에 맞춰 선택할 수 있다.

ValidationGroups.java

public class ValidationGroups {
    public interface group1 {};
    public interface group2 {};
}

User.java

public class User {

    private Integer id;

    @NotEmpty(groups = {ValidationGroups.group1.class})
    private String account;

    @NotEmpty(groups = {ValidationGroups.group2.class})
    private String password;
}