검증2(Validation)-springboot

Jiwon Park·2023년 5월 16일
0

검증1(validation)-spring <- 클릭

구현

@RequiredArgsConstructor
public class ValidationItemControllerV2 {

    private final ItemValidator itemValidator;

    @InitBinder
    public void initBinder(WebDataBinder dataBinder){
        dataBinder.addValidators(itemValidator);
    }
    
     @PostMapping("/add")
    public String addItemV5(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {

        //검증에 실패하면 다시 입력 폼으로
        if(bindingResult.hasErrors()){
            log.info("errors = {}", bindingResult);
            return "validation/v2/addForm";
        }

        //성공 로직
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v2/items/{itemId}";
    }

@Validated 이 붙으면 WebDataBinder 에 등록한 검증기를 찾아서 실행한다.
여러 검증기를 등록한다면 그 중에 어떤 검증기가 실행되어야 할지 구분이 필요하다.
이때 supports() 가 사용된다.
여기서는 supports(Item.class) 호출되고, 결과가 true 이므로 ItemValidator 의 validate()가 호출된다.

@Component
public class ItemValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return Item.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        Item item = (Item) target;

        //ValidationUtils.rejectIfEmptyOrWhitespace(errors, "itemName", "required");
        //검증 로직
        if(!StringUtils.hasText(item.getItemName())){
            errors.rejectValue("itemName", "required");
        }
        if(item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000){
            errors.rejectValue("price", "range", new Object[]{1000, 1000000}, null);
        }
        if(item.getQuantity() == null || item.getQuantity() >= 9999){
            errors.rejectValue("quantity", "max", new Object[]{9999}, null);
        }
        //특정 필드가 아닌 복합 룰 검증
        if(item.getPrice() != null && item.getQuantity() != null){
            int resultPrice = item.getPrice() * item.getQuantity();
            if(resultPrice<10000){
                errors.reject("totalPriceMin", new Object[]{10000,resultPrice}, null);
            }
        }
    }
}

글로벌 설정

@SpringBootApplication
public class ItemServiceApplication implements WebMvcConfigurer {
   @Override
     public Validator getValidator() {
    	 return new ItemValidator();
   }
}

View

  <form action="item.html" th:action th:object="${item}" method="post">

        <div th:if="${#fields.hasGlobalErrors()}">
            <p class="field-error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">전체 오류 메시지</p>
        </div>

        <div>
            <label for="itemName" th:text="#{label.item.itemName}">상품명</label>
            <input type="text" id="itemName" th:field="*{itemName}" th:errorclass="field-error" class="form-control" placeholder="이름을 입력하세요">
            <div class="field-error" th:errors="*{itemName}">상품명 오류</div>
        </div>

Settings

spring.messages.basename=messages, errors
#==ObjectError==

#Level1
totalPriceMin.item=상품의 가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}

#Level2
totalPriceMin=전체 가격은 {0}원 이상이어야 합니다. 현재 값 = {1}

#==FieldError==

#Level1
required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.

#Level2 - 생략

#Level3
required.java.lang.String = 필수 문자입니다.
required.java.lang.Integer = 필수 숫자입니다.
min.java.lang.String = {0} 이상의 문자를 입력해주세요.
min.java.lang.Integer = {0} 이상의 숫자를 입력해주세요.
range.java.lang.String = {0} ~ {1} 까지의 문자를 입력해주세요.
range.java.lang.Integer = {0} ~ {1} 까지의 숫자를 입력해주세요.
max.java.lang.String = {0} 까지의 문자를 허용합니다.
max.java.lang.Integer = {0} 까지의 숫자를 허용합니다.

#Level4
required = 필수 값 입니다.
min= {0} 이상이어야 합니다.
range= {0} ~ {1} 범위를 허용합니다.
max= {0} 까지 허용합니다.

DefaultMessageCodesResolver의 기본 메시지 생성 규칙

1. FieldError rejectValue("itemName", "required")

errorCode: required
objectName: "item"
field: "itemName"
fieldType: String

다음 4가지 오류 코드를 자동으로 생성

required.item.itemName
required.itemName
required.java.lang.String
required

2. ObjectError reject("totalPriceMin")

errorCode: totalPriceMin
objectName: "item"

다음 2가지 오류 코드를 자동으로 생성

totalPriceMin.item
totalPriceMin


profile
안녕하세요

0개의 댓글