Bean Validation
특정 구현체 x, 기술 표준
>> 검증 애노테이션과 여러 인터페이스의 모음
>> 일반적으로 사용하는 구현체는 Hibernate Validator
@NotBlank : 빈값 + 공백만 있는 경우를 허용 x
@NotNull : null 을 허용 x
@Range(min = 1000, max = 1000000) : 범위 안의 값이어야 함
@Max(9999) : 최대 9999까지만 허용
스프링 적용
spring-boot-starter-validation 라이브러리를 넣으면 자동으로 Bean Validator를 인지
LocalValidatorFactoryBean을 글로벌 Validator로 등록
>> @NotNull 같은 애노테이션을 보고 검증을 수행
>> @Valid , @Validated 만 적용하면 됨
>> FieldError, ObjectError를 생성해서 BindingResult 에 담아줌
검증 순서
1. @ModelAttribute 각각의 필드에 타입 변환 시도
1-1. 성공하면 다음으로
1-2. 실패하면 typeMismatch로 FieldError 추가
2. Validator 적용
BeanValidator는 바인딩에 실패한 필드는 BeanValidation 적용 x
BeanValidation 메시지 찾는 순서
1. 생성된 메시지 코드 순서대로 messageSource에서 찾기
2. 애노테이션의 messsage 속성 사용
3. 라이브러리가 제공하는 기본 값 사용
ObjectError
@ScriptAssert() 사용
>> 제약이 많고 복잡
>> 오브젝트 오류 관련 부분만 직접 자바 코드로 작성하는 것 권장
한계
수정시 요구사항이 등록시와 다를 수 있음
>> 등록시에는 quantity를 최대 9999, 수정시에는 무제한으로 변경
>> 등록시에는 id에 값이 없어도 되지만 수정시에는 id 값 필수
id : @NotNull 추가
quantity : @Max(9999) 제거
수정은 잘 동작하지만 등록에서 문제
>> 등록시에는 id에 값도 없고 quantity 제한 최대 값이 99999 적용 x
>> @NotNull에 의해 검증에 실패하고 다시 등록 폼 화면으로 넘어옴
>> 등록과 수정의 검증 조건의 충돌!!
groups
동일 모델 객체를 등록할 때, 수정할 때 각각 다르게 검증 방법
1. BeanValidation의 groups 기능 사용
2. Item을 직접 사용하지 않고 ItemSaveForm, ItemUpdateForm 같은 폼 전송을 위한 별도 모델 객체 사용
groups 적용
등록시 검증할 기능과 수정시 검증할 기능을 각 그룹으로 나누어 적용 가능
Form 전송 객체 분리
폼 데이터 전달에 Item 도메인 객체 사용
HTML Form => Item => Controller => Item => Repository
장점 : Item 도메인 객체를 컨트롤러, 리포지토리 까지 직접 전달, 중간에 Item을 만드는 과정이 없어서 간단
단점 : 간단한 경우에만 적용 가능, 수정시 검증이 중복될 수 있고, groups를 사용해야 함
폼 데이터 전달을 위한 별도의 객체 사용
HTML Form => ItemSaveForm => Controller => Item 생성 => Repository
장점 : 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해서 데이터를 전달 받음, 보통 등록과 수정용으로 별도의 폼 객체를 만들기 때문에 검증이 중복 x
단점 : 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가
등록시 실무에서는 Item의 데이터만 넘어오는 것이 아니라 무수한 추가 데이터가 넘어옴
>> 더 나아가 Item을 생성하는데 필요한 추가 데이터를 데이터베이스나 다른 곳에서 찾아와야 할 가능성
등록용 폼, 수정용 폼 분리
폼 객체 바인딩
Item 대신 ItemSaveForm을 전달 받음, @Validated 검증 수행, BindingResult로 검증 결과 받음
>> @ModelAttribute에 item 이름 넣는 것 주의, 넣지 않으면 모델 이름이 itemSaveFrom으로 자동으로 담김
폼 객체를 Item으로 변환
폼 객체의 데이터 기반으로 Item 객체 생성
>> 이렇게 폼 객체처럼 중간에 다른 객체가 추가되면 변환하는 과정 추가
HTTP 메시지 컨버터
@Validated는 HttpMessageConverter(@RequestBody)에도 적용 가능
@ModelAttribute : HTTP 요청 파라미터(URL 쿼리 스트링, POST Form)를 다룰 때 사용
@RequestBody : HTTP Body의 데이터를 객체로 변환할 때 사용, 주로 API JSON 요청을 다룰 때 사용
@ModelAttribute vs @RequestBody
HTTP 요청 파리미터를 처리하는 @ModelAttribute 는 각각의 필드 단위로 세밀하게 적용
>> 특정 필드 에 타입이 맞지 않는 오류가 발생해도 나머지 필드는 정상 처리 가능
HttpMessageConverter 는 각각의 필드 단위로 적용되는 것이 아니라
>> 전체 객체 단위로 적용
>> 메시지 컨버터의 작동이 성공해서 ItemSaveForm 객체를 만들어야 @Validated 가 적용
@ModelAttribute 는 필드 단위로 정교하게 바인딩이 적용
>> 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 사용한 검증도 적용 가능
@RequestBody 는 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면
>> 이후 단계 자체가 진행되지 않고 예외가 발생
>> 컨트롤러도 호출되지 않고, Validator도 적용 x
출처 : 김영한, 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
'Spring' 카테고리의 다른 글
MVC / 로그인 처리 - 필터, 인터셉터 (0) | 2025.04.13 |
---|---|
MVC / 로그인 처리 - 쿠키, 세션 (0) | 2025.04.12 |
MVC / Validation (0) | 2025.04.10 |
MVC / 메시지, 국제화 (0) | 2025.04.09 |
MVC / Thymeleaf - 스프링 통합과 폼 (0) | 2025.04.08 |