TIL

24.09.04 TIL - Bean Validation

개발공명 2024. 9. 8. 11:18

오늘 배운 것

  • validation
  • Bean Validation 종류
  • Bean Validation 적용
  • Validation 예외 처리

 

Validation이란

백엔드 서버에서 입력 값을 검증해야 할 때가 있습니다. 

 

예를 들어 Java에서는 null 값이 있어서 입력 값으로 null 값이 들어왔을 때 제대로 된 처리를 하지 않으면 NullPointException이 발생합니다. 

 

이런 NullPointException을 예방하기 위해서 Validation 즉 검증 과정이 필요하다. 

 

비즈니스 요구사항으로 'id는 소문자, 숫자로만 구성되고 6~10자로 구성되어야 한다' 이런 것이 있을 수 있습니다. 

 

이럴 때 입력 값으로 들어온 id가 비즈니스 요구 사항에 맞는지 검증 과정이 필요하다. 

 

이전에는 이런 검증은 프론트엔드에서 다 하기 때문에 백엔드에서는 또 할 필요가 있나 싶은 생각이 있었다. 

 

그런데 백엔드에서도 한번 더 하는 것이 좋다고 한다. 

 

Bean Validation 종류

Spring에서는 Validation을 쉽게 적용할 수 있게, 간편하게 사용할 수 있는 여러 annotation을 제공한다. 

 

이런 annotation들이 없다면 직접 각 값들에 대한 검증 로직을 작성해야 하는 번거로움이 있다. 

 

@NotNull null 불가 @Size 문자열, 컬렉션, 배열, 맵 등의 크기
@NotEmpty null, "" 불가 @Positive 양수
@NotBlank null, "", " " 불가 @Negative 음수
@Max 최대 값 @Email Email 형식
@Min 최소 값 @Pattern 정규 표현식

 

위의 annotation 말고도 굉장히 많은 검증을 위한 annotation들이 있다. 

 

이런 annotation을 entity나 dto의 필드에 붙여서 해당 필드에 대해서 검증을 하는 것이다. 

 

다양한 annotation들은 아래에서 확인해 볼 수 있다. 

 

https://jakarta.ee/specifications/bean-validation/3.0/apidocs/

 

Overview (Jakarta Bean Validation API 3.0.0)

 

jakarta.ee

 

Bean Validation 적용

Bean Validation을 프로젝트에 적용해보자. 

 

우선 build.gradle에 Validation dependency를 추가해줘야 한다. 

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

 

 

그리고 dto의 필드에 bean validation annotation들을 추가하는 것이다. 

import jakarta.validation.constraints.*;
import lombok.Getter;

@Getter
public class ProductRequestDto {
    @NotBlank
    private String name;
    @Email
    private String email;
    @Positive(message = "양수만 가능합니다.")
    private int price;
    @Negative(message = "음수만 가능합니다.")
    private int discount;
    @Size(min=2, max=10)
    private String link;
    @Max(10)
    private int max;
    @Min(2)
    private int min;
}

 

 

이렇게 하면 끝이 아니다. 

 

Bean Validation 기능을 수행하려면 @Valid라는 annotation을 사용해야 한다. 

 

Bean Validation이 적용된 객체에 Bean Validation 기능 수행하려면 파라미터에서 @Valid를 붙여주면 된다. 

@PostMapping("/validation")
@ResponseBody
public ProductRequestDto testValid(@RequestBody @Valid ProductRequestDto requestDto) {
    return requestDto;
}

 

꼭 Controller에서만 하는 것이 아니고 Service에서도 아래와 같이 사용할 수 있다. 

public Product createProduct(@Valid ProductRequestDto requestDto){
		...
}

 

 

이렇게 메서드의 파라미터로 넘어오는 객체에 @Valid를 붙여 해당 객체에 적용된 Bean Validation을 수행하는 것이다. 

 

Bean Validation이 실패하면 예외가 발생하고 메서드가 수행되지 않는다. 

 

Validation 예외 처리

Bean Validation이 실패하면 예외가 발생한다.

 

이때 Bean Validation이 실패했을 때 예외 처리를 따로 할 수 있다. 

 

바로 BindingResult를 사용하는 방법이다. 

 

예외가 발생하면 BindingResult 객체에 오류에 대한 정보가 담긴다. 

 

BindingResult는 파라미터로 받아올 수 있다. 

@PostMapping("/user/signup")
public String signup(@Valid SignupRequestDto requestDto, BindingResult bindingResult) {
    // Validation 예외처리
    List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    if(fieldErrors.size() > 0) {
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            log.error(fieldError.getField() + " 필드 : " + fieldError.getDefaultMessage());
        }
        return "redirect:/api/user/signup";
    }

    userService.signup(requestDto);

    return "redirect:/api/user/login-page";
}

 

 

bindingResult.getFieldErrors() 메서드로 오류가 난 필드들을 하나씩 가지고 올 수 있다.

  • 발생한 오류들에 대한 정보가 담긴 List<FieldError> 리스트를 가져온다.
  • getField와 getDefaultMessage 메서드로 필드와 지정한 에러 메시지 가져올 수 있다.
  • 위의 코드는 예외 처리로 회원 가입 페이지로 redirect한 것이다.

 

정리

입력 값을 검증하거나 DB에 Entity를 저장할 때 저장된 값을 검증할 필요가 있다. 

 

프론트엔드에서 할 수도 있지만 백엔드에서 한번 더 하는 것이 좋다. 

 

다양한 Bean Validation annotation과 Bean Validation 기능을 수행하는 @Valid annotation으로 검증할 수 있다. 

'TIL' 카테고리의 다른 글

24.09.06 TIL - CSRF  (0) 2024.09.08
24.09.05 TIL - Effective Java Item 63  (1) 2024.09.08
24.09.03 TIL - Spring Security Login with JWT  (0) 2024.09.08
24.09.02 TIL - Spring Security 동작 원리  (0) 2024.09.07
24.08.28 - JWT in Spring  (6) 2024.08.30