TIL

Bean Validation

Bean Validation

Bean Validation 애노테이션 적용

@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;

Bean Validation - 에러 코드

NotBlank 라는 오류 코드를 기반으로 MessageCodesResolver를 통해 다양한 메시지 코드가 순서대로생성된다.

@NotBlank

@Range

메시지 등록

errors.properties

# Bean Validation 추가 
NotBlank={0} 공백X 
Range={0}, {2} ~ {1} 허용
Max={0}, 최대{1}

BeanValidation 메시지 찾는 순서

  1. 생성된 메시지 코드 순서대로 messageSource에서 메시지 찾기
  2. 애노테이션의 message 속성 사용 @NotBlank(message = "공백! {0}")
  3. 라이브러리가 제공하는 기본 값 사용 -> 공백일 수 없습니다.

Bean Validation - 오브젝트 오류

글로벌 오류 추가

if (item.getPrice() != null && item.getQuantity() != null) {
		int resultPrice = item.getPrice() * item.getQuantity();  
		if (resultPrice < 10000) {   
				bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null); 
		}
}

Bean Validation - groups

동일한 모델 객체를 등록할 때와 수정할 때 각각 다르게 검증하는 방법을 알아보자

방법 2가지

BeanValidation groups 기능 사용

  1. groups를 체크하기 위한 인터페이스를 만든다
  2. 적용하고 싶은 필드에 groups를 적용한다.
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;
  1. 컨트롤러 Validated 어노테이션에 추가해준다.

@Validated(SaveCheck.class)

@Validated(UpdateCheck.class)

참고: @Valid에는 groups를 적용할 수 있는 기능이 없다. 따라서 groups를 사용하려면 @Validated 를 사용해야 한다.

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

Form 전송 객체 분리

수정의 경우 등록과 수정은 완전히 다른 데이터가 넘어온다. 생각해보면 회원 가입시 다루는 데이터와 수정시 다루는 데이터는 범위에 차이가 있다. 예를 들면 등록시에는 로그인id, 주민번호 등등을 받을 수 있지만, 수정시에는 이런 부분이 빠진다. 그리고 검증 로직도 많이 달라진다. 그래서

Bean Validation - HTTP 메시지 컨버터

@Valid , @ValidatedHttpMessageConverter (@RequestBody )에도 적용할 수 있다

@PostMapping("/add") 
public Object addItem(
		@RequestBody @Validated ItemSaveForm form, 
		BindingResult bindingResult
)

@ModelAttribute vs @RequestBody

@ModelAttribute는 각각의 필드 단위로 세밀하게 적용된다.

HttpMessageConverter@ModelAttribute와 다르게 각각의 필드 단위로 적용되는 것이 아니라, 전체 객체 단위로 적용된다.