본문 바로가기
Spring Study/MVC 패턴

[MVC 패턴] 검증2 - Bean Validation

by 정재인 2023. 8. 24.

Bean Validation

- Bean Validation은 특정한 구현체가 아닌 Bean Validation 2.0(JSR-380)이라는 기술 표준이다.

- 검증 애노테이션과 여러 인터페이스의 모음이다.

 

스프링 MVC에서 Bean Validator 사용하는 방법

스프링 부트가 spring-boot-starter-validation 라이브러리를 넣으면 자동으로 Bean Validator를 인지하고 스프링에 통합한다.

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

 

Bean Validation 애노테이션 적용 코드

package hello.itemservice.domain.item;

import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class Item {

    private Long id;
    
    @NotBlank
    private String itemName;
    
    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;
        
    @NotNull
    @Max(9999)
    private Integer quantity;
    
    public Item() {
    }
    
    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    } 
}
  • @NotBlank: 빈값 + 공백만 있는 경우를 허용하지 않는다.
  • @NotNull: null을 허용하지 않는다.
  • @Range(min = 1000, max = 1000000): 범위 안의 값이어야 한다.
  • @Max(9999): 최대 9999까지만 허용한다.

 

Bean Validation - groups

동일한 모델 객체를 등록할 때와 수정할 때 각각 다르게 검증하는 방법이다.

 

저장용 groups 생성

package hello.itemservice.domain.item;

public interface SaveCheck {
}

 

수정용 groups 생성

package hello.itemservice.domain.item;

public interface UpdateCheck {
}

 

Item - groups 적용

package hello.itemservice.domain.item;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class Item {

    @NotNull(groups = UpdateCheck.class) //수정시에만 적용 
    private Long id;
      
    @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    private String itemName;
      
    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Range(min = 1000, max = 1000000, groups = {SaveCheck.class, UpdateCheck.class})
    private Integer price;
    
    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Max(value = 9999, groups = SaveCheck.class) //등록시에만 적용 
    private Integer quantity;
      
    public Item() {
    }
    
    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    } 
}

groups 기능은 실제 잘 사용되지 않는다. 실무에서는 주로 등록용 폼 객체와 수정용 폼 객체를 분리해서 사용하기 때문이다.

 


Form 전송 객체 분리

- 실무에서는 groups를 잘 사용하지 않는다. 등록시 폼에서 전달하는 데이터가 Item 도메인 객체와 딱 맞지 않기 때문이다.

- 그래서 보통 Item을 직접 전달받는 것이 아니라, 복잡한 폼 데이터를 컨트롤러까지 전달할 객체를 만들어서 전달한다.

 

폼 데이터 전달에 Item 도메인 객체 사용

HTML Form → Item → Controller → Item → Repository

  • 장점: Item 도메인 객체를 컨트롤러, 레포지토리까지 직접 전달해서 중간에 Item을 만드는 과정이 없어 간단하다.
  • 단점: 간단한 경우에만 적용할 수 있다. 수정 시 검증이 중복될 수 있고 groups를 사용해야 한다.

 

폼 데이터 전달을 위한 별도의 객체 사용

HTML Form → ItemSaveForm → Controller → Item 생성 → Repository

  • 장점: 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해서 데이터를 전달 받을 수 있다. 보통 등록과 수정용으로 별도의 폼 객체를 만들기 때문에 검증이 중복되지 않는다.
  • 단점: 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가된다.

 

 

ItemSaveForm - Item 저장용 폼

package hello.itemservice.web.validation.form;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class ItemSaveForm {
    @NotBlank
    private String itemName;
      
    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;
      
    @NotNull
    @Max(value = 9999)
    private Integer quantity;
}

 

ItemUpdateForm - Item 수정용 폼

package hello.itemservice.web.validation.form;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class ItemUpdateForm {
    @NotNull
    private Long id;
      
    @NotBlank
    private String itemName;
     
    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;

    //수정에서는 수량은 자유롭게 변경할 수 있다. 
    private Integer quantity;
}

댓글