본문 바로가기
스프링

검증

by moonstal 2022. 6. 17.

검증-Validation

  • 컨트롤러의 역할: HTTP 요청이 정상인지 검증
  • 정상: PRG

직접 개발

    //Map
    Map<String, String> errors = new HashMap<>(); //<필드명, 에러메시지>
    errors.put("itemName", "상품 이름은 필수입니다.");
    !errors.isEmpty()-> 모델에 담고 다시 입력 폼으로

    th:if="${errors?.containsKey('globalError')}"
    th:text="${errors['globalError']}"

    th:classappend="${errors?.containsKey('itemName')} ? 'field-error' : _"
    th:if="${errors?.containsKey('itemName')}" th:text="${errors['itemName']}"
  • errors?. : null일 때 null반환

BindingResult

    //Map->BindingResult
    bindingResult.addError(new FieldError("item", "itemName", "상품 이름은
    필수입니다."));//@ModelAttribute명, 필드명, 오류메시지
    bindingResult.addError(new ObjectError("item", "가격 * 수량의 합은 10,000원") //글로벌 오류
    bindingResult.hasErrors()->다시 입력 폼으로

    th:if="${#fields.hasGlobalErrors()}"
    th:each="err : ${#fields.globalErrors()}" th:text="${err}"
    th:errorclass="field-error"
    th:errors="*{itemName}"
  • 순서지키기 @ModelAttribute Item item, BindingResult bindingResult
  • 오류가 있는 경우에 태그 출력
  • BindingResult: 데이터 바인딩 오류->BindingResult에 담아 컨트롤러
    정상 호출

FieldError, ObjectError

    public FieldError(String objectName, String field, @Nullable Object 
    rejectedValue, boolean bindingFailure, @Nullable String[] codes, 
    @Nullable Object[] arguments, @Nullable String defaultMessage)
  • th:field="*{price}"는 FieldError에서 보관한 값 출력

오류 코드와 메시지 처리

  • errors.properties
  • application.properties: spring.messages.basename=messages,errors
      max.item.quantity=수량은 최대 {0} 까지 허용합니다.
      new FieldError("item", "quantity",item.getQuantity(), false, 
      new String[]{"max.item.quantity"}, new Object[]{9999}, null)
  • FieldError , ObjectError -> rejectValue() , reject()
      bindingResult.rejectValue("quantity", "max", new Object[]{9999}, null);
      bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
  • MessageCodesResolver: 검증 오류 코드로 메시지 코드 생성
  • resolveMessageCodes("range","item", "price", Integer.class);
  • codes [range.item.price, range.price, range.java.lang.Integer, range]
  • ValidationUtils: Empty , 공백
      ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "itemName",
      "required");

스프링이 직접 만든 오류 메시지

  • 타입 오류: codes [typeMismatch.item.price, typeMismatch.price, typeMismatch.java.lang.Integer, typeMismatch]
  • typeMismatch.java.lang.Integer=숫자를 입력해주세요.

Validator 분리

  • Validator

      Validator
      supports(Class<?> clazz)
      validate(Object target, Errors errors)
    
      //컨트롤러 주입
      private final ItemValidator itemValidator;
      itemValidator.validate(item, bindingResult);
  • WebDataBinder: 검증기 자동 적용
      컨트롤러에 추가
      @InitBinder
      public void init(WebDataBinder dataBinder) {
      dataBinder.addValidators(itemValidator);
      }

검증-Bean Validation

  • 검증 애노테이션과 여러 인터페이스의 모음
  • @NotBlank: 빈값 + 공백체크
  • @NotNull
  • @Range(min = 1000, max = 1000000)
  • @Max(9999)
  • @Validated(스프링 전용)

      addItem(@Validated @ModelAttribute Item item, 
              BindingResult bindingResult, 
              RedirectAttributes redirectAttributes)
  • spring-boot-starter-validation 라이브러리: Bean Validator자동 인지

  • @ModelAttribute 타입변환시도->실패(typeMismatch) FieldError추가

  • @ModelAttribute 타입변환시도->성공 Validator 적용

에러 코드

  • NotBlank.item.itemName, NotBlank.itemName, NotBlank.java.lang.String, NotBlank
  • NotBlank={0} 공백X //{0}은 필드명
  • @NotBlank(message = "공백! {0}")

오브젝트 오류

  • @ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")
  • 자바 코드 작성 권장
      bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);

한계

  • 등록, 수정 요구사항 다름

  • BeanValidation의 groups(@Validated만 가능, @Valid 안됨)

      public interface SaveCheck
      public interface UpdateCheck
    
      //아이템에 적용
      @NotNull(groups = UpdateCheck.class)
      @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    
      //컨트롤러에 적용
      @Validated(SaveCheck.class)//저장로직
      @Validated(UpdateCheck.class)//수정로직
  • 등록시 폼 데이터 도메인 객체와 맞지않음->폼 전송을 위한 별도의 모델 객체

      public class ItemSaveForm
      public class ItemUpdateForm
    
      @Validated @ModelAttribute("item") ItemSaveForm form
      Item item = new Item();
      item.setItemName(form.getItemName());
      itemRepository.save(item);
    
      @Validated @ModelAttribute("item") ItemUpdateForm form
      Item itemParam = new Item();
      itemParam.setItemName(form.getItemName());
      itemRepository.update(itemId, itemParam);
  • @ModelAttribute("item")안적어주면 ItemSaveForm -> itemSaveForm

HTTP 메시지 컨버터

  • HttpMessageConverter(@RequestBody)에도 적용
  • @RequestBody @Validated ItemSaveForm form
  • 성공 < 검증 오류(Validator) < 객체 생성 실패(HttpMessageConverter->ItemSaveForm)
  • @ModelAttribute(필드 단위), @RequestBody(객체를 만들어야 @Valid , @Validate 적용)

링크

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2

'스프링' 카테고리의 다른 글

예외 처리  (0) 2022.06.19
로그인  (0) 2022.06.18
타임리프  (0) 2022.06.16
[스프링] 스프링 MVC  (0) 2022.06.09
[스프링] MVC 프레임워크  (0) 2022.06.09