해당 예제는 다음과 같은 기술 스택을 사용했습니다.
- JDK 11
- Spring Boot
- ThymeLeaf
1. Bean Validation이란?
Bean Validation은 Java EE 환경에서 표준으로 제공되는 유효성 검증 프레임워크로, JSR-380(Bean Validation 2.0) 표준에 따라 정의된다. 애노테이션 기반으로 도메인 모델의 필드에 유효성 검증 규칙을 선언하여 자동으로 검증을 수행할 수 있게 해준다.
Spring Boot는 기본적으로 Hibernate Validator를 통합하여 Bean Validation을 지원한다. Hibernate Validator는 Bean Validation의 레퍼런스 구현체로, 다양한 유효성 검증 기능을 제공한다.
Bean Validation은 다양한 유효성 검증 애노테이션을 제공한다.
- @NotNull: 값이 null이 아님을 검사.
- @NotEmpty: 문자열, 컬렉션 등이 비어있지 않음을 검사.
- @NotBlank: 문자열이 공백이 아님을 검사.
- @Size: 문자열, 배열, 컬렉션 등의 크기를 검사.
- @Min, @Max: 숫자의 최소값과 최대값을 검사.
- @Email: 이메일 형식을 검사.
- @Pattern: 정규식을 사용하여 값을 검사.
2. 프로젝트 준비
의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-validation'
3. Bean Validation 시작하기
도메인 모델에 검증 애노테이션 적용
Item 클래스를 하나 생성 후 검증 애노테이션을 추가한다.
public class Item {
private Long id;
@NotBlank(message = "상품 이름은 필수입니다.")
private String itemName;
@NotNull(message = "가격은 필수입니다.")
@Range(min = 1000, max = 1000000, message = "가격은 1,000원에서 1,000,000원 사이여야 합니다.")
private Integer price;
@NotNull(message = "수량은 필수입니다.")
@Max(value = 9999, message = "수량은 최대 9,999까지 허용됩니다.")
private Integer quantity;
// getters and setters
}
Bean Validation 테스트 코드 작성
@SpringBootTest
public class BeanValidationTest {
@Test
void beanValidation() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Item item = new Item();
item.setItemName(" "); // 공백 문자열
item.setPrice(0);
item.setQuantity(10000);
Set<ConstraintViolation<Item>> violations = validator.validate(item);
for (ConstraintViolation<Item> violation : violations) {
System.out.println("오류 필드: " + violation.getPropertyPath());
System.out.println("오류 메시지: " + violation.getMessage());
}
}
}
그럼 다음과 같은 값이 콘솔에 나타날 것이다.
4. 스프링과 Bean Validation 통합
컨트롤러에서 검증 적용
Controller의 매개변수에서 @Validated 애노테이션을 사용하여 검증을 활성화한다.
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
return "validation/v3/addForm";
}
// 성공 로직
}
- @Validated: 스프링 프레임워크에서 제공하는 검증 애노테이션
- BindingResult: 검증 오류 정보를 담는 객체 (무조건 바인딩 할 객체 매개변수 뒤에 선언해줘야 함)
5. 에러 메시지 커스터마이징
메시지 소스 설정
messages.properties 또는 errors.properties 파일에 커스텀 에러 메시지를 정의할 수도 있다.
NotBlank.item.itemName=상품 이름은 필수입니다.
Range.item.price=가격은 {2}에서 {1} 사이여야 합니다.
Max.item.quantity=수량은 최대 {1}까지 허용됩니다.
메시지 코드 우선순위
- NotBlank.item.itemName
- NotBlank.itemName
- NotBlank.java.lang.String
- NotBlank
6. 오브젝트 레벨 검증
필드 단위가 아닌 객체 전체에 대한 검증이 필요한 경우, 직접 자바 코드를 통해 검증한다. 예를들어 "아이템의 수량 * 가격이 10000원이하라는 조건"이 생성된다면 어노테이션 선언으로 검증하기가 어려울 것이다. 그래서 직접 자바 코드를 통해 검증하는것이 낫다.
// 검증 예시 코드
if (item.getPrice() != null && item.getQuantity() != null) {
int totalPrice = item.getPrice() * item.getQuantity();
if (totalPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000, totalPrice}, null);
}
}
7. 다른 API (아이템 수정 기능)에도 검증 적용하기
수정 시에도 검증이 필요하므로, 수정용 컨트롤러 메서드에 @Validated를 적용한다.
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute Item item, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "validation/v3/editForm";
}
// 수정 로직
}
저장과 수정 검증 조건이 같다면 상관이 없겠지만 다르다면 하나의 도매인 객체에 모든 검증 로직을 선언하기 어려울 것이다. 예를들자면 저장 할 때의 검증로직과 수정 할 때의 검증 로직이 다를 수 있기 때문이다. 다음 포스팅에서는 이러한 문제점을 해결하기 위한 해결책을 포스팅하겠다.
다음 포스팅:
[Spring] Bean Validation (검증) - 2
Reference
'Spring Framework' 카테고리의 다른 글
[Spring] 예외 처리와 오류 페이지 (0) | 2024.11.12 |
---|---|
[Spring] Bean Validation (검증) - 2 (0) | 2024.11.04 |
[Spring] 스프링 메시지, 국제화 (1) | 2024.10.29 |
[Spring] Argument Resolver 란? (0) | 2024.10.24 |
@Transactional을 선언해도 내부 메서드를 실행 시 ROLLBACK이 되지 않는 문제 (0) | 2024.08.03 |