본 게시물은 스스로의 공부를 위한 글입니다.
틀린 내용이 있을 수 있습니다.
스프링에서 유효성 검증 로직을 구현하기 위한 사실상 표준
검사 대상 클래스에 어노테이션 기반 제약 조건을 선언하여 간결하게 유효성 검사가 가능하다.
Bean Validation을 사용하려면 validation
의존 관계를 추가해야 한다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
@NotBlank
: 빈값 + 공백만 있는 경우를 허용하지 않는다.@NotNull
: null 을 허용하지 않는다.@Range(min = 1000, max = 1000000)
: 범위 안의 값이어야 한다.@Max(9999)
: 최대 9999까지만 허용한다.@Min(10)
: 최소 10까지만 허용한다.@Size(min=0, max=10)
: 문자열 길이, 컬렉션 사이즈의 제한 범위를 지정@AssertTrue
: 값이 true인 것을 검증@AssertFalse
: 값이 false인 것을 검증@Pattern(regexp="[a-zA-z0-9]*")
: 지정한 정규 표현과 일치하는 것을 검증(예시는 영숫자 검증)@DecimalMax("100.0")
: 소수점 이하를 포함해서 검증할 때는 Max가 아닌, DecimalMax 사용@DecimalMin("10.0")
: 소수점 이하를 포함해서 검증할 때는 Min가 아닌, DecimalMin 사용@Digits(integer=1, fraction=3)
: 정수부와 소수부의 자릿수 검증. String 타입도 검증할 수 있다.@Future
: 미래 날짜인 것을 검증 (Date 타입 등)@Past
: 과거 날짜인 것을 검증 (Date 타입 등)@Valid
: 중첨된 Form을 검증 (클래스 타입)@Length(min-0, max=5)
: 문자열 길이 지정(문자열 전용 Size)@Email
: 문자열이 이메일 주소 형식인지 검증@CreditCardNumber
: 문자열이 신용카드 번호 형식인지 검증@URL
: 문자열이 URL 형식인지 검증cf) @NotNull
, @NotEmpty
, @NotBlank
의 차이점
@NotNull
: null만 허용하지 않는다. 공백문자("")나 스페이스, 탭은 허용한다.@NotEmpty
: null 과 공백문자("")를 둘 다 허용하지 않는다. 스페이스, 탭은 허용한다.@NotBlank
: null 과 공백문자(""), 스페이스, 탭을 모두 허용하지 않는다.@NotEmpty
나 @NotBlank
는 컬렉션, 문자열, 배열용이다. 정수(Integer)에 사용하면 에러 발생한다. 따라서 Integer 타입에는 @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;
}
@ModelAttribute
각각의 필드에 타입 변환 시도
성공하면 다음으로
실패하면 errorCode=typeMismatch
로 FieldError
추가
Validator
적용
MessageCodesResolver
를 통해 메시지 코드가 순서대로 생성된다.애노테이션.오브젝트.필드
애노테이션.필드
애노테이션.타입
애노테이션
ex
@NotBlank
@Range
#errors.properties 추가
NotBlank={0} 공백X
Range={0}, {2} ~ {1} 허용
Max={0}, 최대 {1}
1. 생성된 메시지 코드 순서대로 `messageSource` 에서 메시지 찾기
2. 애노테이션의 message 속성 사용 `@Range(min=1, max=10, message = "{min}~{max} 범위의 숫자를 입력하세요")`
3. 라이브러리가 제공하는 기본 값 사용
@ScriptAssert()
를 사용하면 된다.@ScriptAssert()
보다는 자바 코드에서 bindingResult.reject
를 사용하는것을 추천한다.@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
//특정 필드 예외가 아닌 전체 예외(Global Error)
if (item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
}
}
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "/add";
}
//성공 로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/items/{itemId}";
}
등록과 수정이 같은 도메인을 사용하지만, 비지니스 요구사항이 다를때가 있다.
예를 들면 다음과 같은 경우이다.
공통 도메인을 직접 사용하지 않고, ItemSaveForm
, ItemUpdateForm
같은 폼 전송을 위한 별도의 모델 객체를 만들어서 사용한다.
예를 들면 다음과 같은 로직을 돈다.
@ModelAttribute ItemSaveForm
로 입력값 받기Item
생성 및 세팅Repository
로 Item
저장인프런의 '스프링 MVC 2편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요