클라이언트로부터 받은 정보를 검증할 때 사용하는 것이
Bean Validation
어노테이션을 이용해서 간단하게 검증할 수 있다
먼저 build.gradle에 의존관계를 추가해야함
implementation 'org.springframework.boot:spring-boot-starter-validation'
검증할 객체에 검증 어노테이션을 삽입한다
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;
}
이외에도 다향한 어노테이션이 있다
@NotNull vs @NotEmpty vs @NotBlack
@NotNull은 null 일때만 에러
@NotEmpty는 @NotNull + "" 일때 에러
@NotBlank는 @NotEmpty + " " 일때 에러
@NotBlank가 가장 강하다
위의 객체를 컨트롤러에 적용하면
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult
bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "validation/v3/addForm";
}
//성공 로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v3/items/{itemId}";
}
Bean Validation을 사용하기 위해
검증할 객체에 @Valited를 붙혀주고, 바로 옆에
BindingResults 객체를 붙혀줘야 한다.
검증순서
1. @ModelAttribute 각가의 필드에 타입 변환 시도
- 성공하면 다음으로
- 실패하면 typeMismatch로 FieldError 추가
- Validator 적용
바인딩에 성공한 필드(타입 변환 성공)만 Bean Validation을 적용한다
그리고 bindingResults.hasErrors() 로 에러가 있는지 체크하고
있다면 이전 폼 주소로 보낸다
에러가 있다면 이를 클라에 전달해 보여줘야 한다.
이를 위해 에러 메시지용 파일을 생성한다.
먼저 application.properties에 해당 파일을 지정해준다
spring.messages.basename=errors
그다음 erros.properties 파일에서 에러 메시지를 설정해준다
(오류코드.객체이름.필드명=에러메시지)
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
// {0], {1] 로 인자값을 출력할 수 있다
// 객체이름과 필드명을 넣지 않아도 알아서 출력됨
// -> 자세한 것이 우선
// 오류코드.타입 가능 -> typeMismatch.java.lang.Integer
typeMismatch=타입이 맞지 않습니다.
// 타입을 잘못 받았을 때 오류 메시지
Bean Validation에서 특정 필드가 아닌 오브젝트 관련 오류가 생길 수 있다
이때는 오브젝트 오류 관련 부분만 자바 코드로 작성하는 것을 권장한다
public String addItem(@Validated @ModelAttribute Item item, BindingResult
bindingResult, RedirectAttributes redirectAttributes) {
//특정 필드 예외가 아닌 전체 예외
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 "validation/v3/addForm";
}
이때 bindingResult.reject() 메서드를 이용해서 오류 메시지를 추가해준다
bindingResult.reject(오류코드, 메시지로 출력할 인자들, 디폴트메시지)
bindingResult.rejectValue(필드명, 오류코드, 메시지로 출력할 인자들, 디폴트메시지)
@Validated는 @RequestBody도(API JSON) 가능하다
하지만 @RequestBody는 @ModelAttribute와 다르게
필드 단위가 아닌 객체 단위로 검증한다.
-> 타입이 맞지 않는다면 객체 자체가 생성이 되지 않는다
-> Validator를 적용할 수 없다