[Spring_Boot] 유효성 검사, 오류 메세지

최현석·2022년 11월 30일
0

Spring_Boot

목록 보기
12/31

🧩 thymeleaf 오류기능

  • 타임리프는 스프링의 BindingResult를 활용해서 편리한 오류 표현기능 제공
  • field : BindingResult가 제공하는 오류에 접근 할 수 있다.
  • th:errorclass : th:field에서 지정한 필드에 오류가 있으면 class를 추가
  • th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if의 편의 기능

BindingResult

  • Item 객체에 값이 잘 담기지 않을때 BindingResult 객체에 값이 담긴다.
  • 스프링이 제공하는 검증 오류를 보관하는 객체, 검증 오류가 발생하면 여기에 보관
  • 주의) BindingResult는 검증할 대상 바로 다음에 와야한다. 순서가 중요!
  • BindingResult는 Model에 자동으로 포함된다.

🧩 에러 설정 파일

errors.properties

required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
required.default=데이터 오류입니다.
typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.

application.properties

  • 스프링 부트 메세지 설정 추가
  • 새로만든 에러파일 빈으로 등록
spring.messages.basename=errors

스프링에서 제공하는 기본 오류 메세지

  • 타입 정보 불일치 메세지

  • 스프링에서 직접 검증 오류에 추가를 한 것으로 BindingResultFieldError가 다음과 같은 메세지코드가 생성되어 추가되었기 때문이다.

  • 스프링은 타입 오류가 발생하면 자동으로 위 오류 코드들을 담게되는데 errors.properties에는 해당 내용으로 정의한 메세지가 없기 때문에 스프링에서 정의한 기본 메세지가 출력되는 것이다.

  • errors.properties에 다음과 같이 메세지를 선언해주면 된다.

typeMismatch.java.lang.Integer=숫자를 입력해주세요. 
typeMismatch=타입 오류입니다.
  • 정상적으로 나오게 된다.



🧩 addForm

  • th:errorclass="field-error" , <div class="field-error" th:errors="*{price}"></div> 입력해준다.
<div>
	<label for="price">가격</label> 
	<input type="text" th:field="*{price}" th:errorclass="field-error"
			class="form-control" placeholder="가격을 입력하세요">
	<div class="field-error" th:errors="*{price}">가격 오류</div>
</div>

🧩 ItemController

StringUtils.hasText

  • 값이 있을 경우에는 true, 공백이나 null 들어올 경우에는 false를 반환
  • 스프링프레임워크에서 제공

FieldError

  • field 단위의 error를 처리하는 spring에서 제공해주는 객체

FieldError param

  • objectName : 오류가 발생한 객체이름
  • field : 오류 필드
  • rejectedValue : 사용자가 입력한 값(거절된 값)
  • bindingFailure: 타입오류와 같은 바인딩 실패인지, 구분
  • codes : 메시지 코드
  • arguments : 메시지에서 사용하는 인자
  • defaultMessage : 기본 오류 메시지

// validation check
//	@PostMapping("/add")
	public String saveV7(Item item,  BindingResult bindingResult,
			RedirectAttributes redirectAttributes){

		if (!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다."));
		}
        
		if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError(new FieldError("item", "price", "가격은 1000 ~ 1000000까지 입니다."));
		}
		if (item.getQuantity() == null || item.getQuantity() >= 9999) {
			bindingResult.addError(new FieldError("item", "quantity", "수량은 최대 9999까지 입니다."));
		}
		
		// 검증에 실파하면 다시 입력 폼으로
		if(bindingResult.hasErrors()) {
			System.out.println("errors = " + bindingResult);
			return "basic/addForm";
		}
		
		Item saveItem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", saveItem.getId());
		redirectAttributes.addAttribute("status", true);
		
		return "redirect:/basic/items/{itemId}";
	}
	
//	@PostMapping("/add")
	public String saveV8(Item item,  BindingResult bindingResult,
			RedirectAttributes redirectAttributes){

		if (!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("item", "itemName", item.getItemName(),
					false, null, null, "상품 이름은 필수입니다."));
		}
		if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError(new FieldError("item", "price", item.getPrice(),
					false, null, null, "가격은 1000 ~ 1000000까지 입니다."));		
		}
		if (item.getQuantity() == null || item.getQuantity() >= 9999) {
			bindingResult.addError(new FieldError("item", "quantity", item.getQuantity(),
					false, null, null, "수량은 최대 9999까지 입니다."));		
		}
		
		if(bindingResult.hasErrors()) {
			System.out.println("errors = " + bindingResult);
			return "basic/addForm";
		}
		
		Item saveItem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", saveItem.getId());
		redirectAttributes.addAttribute("status", true);
		
		return "redirect:/basic/items/{itemId}";
	}
	
	
	@PostMapping("/add")
	public String saveV9(Item item,  BindingResult bindingResult,
			RedirectAttributes redirectAttributes){
		// 상품명
		if (!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("item", "itemName", item.getItemName(),
					false, new String[] {"required.item.itemName","required.default"},
					null, "defaultMessage"));
		}
		// 가격
		if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError(new FieldError("item", "price", item.getPrice(),
					false, new String[] {"range.item.price"}, new Object[] {1000,10000}, null));		
		}
		// 수량
		if (item.getQuantity() == null || item.getQuantity() >= 9999) {
			bindingResult.addError(new FieldError("item", "quantity", item.getQuantity(),
					false, new String[] {"max.item.quantity"}, new Object[] {9999}, null));		
		}
		
		// 판매 여부
		if (item.getOpen() == false) {
			bindingResult.addError(new FieldError("item", "open", item.getOpen(),
					false, null, null, "체크여부 확인해주세요"));		
		}
		
		// 등록 지역
		if (item.getRegions().size() == 0) {
			bindingResult.addError(new FieldError("item", "regions", "1개 이상 선택해주세요."));
		}
		
		// 상품 종류
		if (item.getItemType() == null) {
			bindingResult.addError(new FieldError("item", "itemType", "1개 이상 선택해주세요."));
		}
		
		// 배송 방식
		if (item.getDeliveryCode()== "") {
			bindingResult.addError(new FieldError("item", "deliveryCode", "1개 이상 선택해주세요."));
		}
		

		
		if(bindingResult.hasErrors()) {
			System.out.println("errors = " + bindingResult);
			return "basic/addForm";
		}
		
		Item saveItem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", saveItem.getId());
		redirectAttributes.addAttribute("status", true);
		
		return "redirect:/basic/items/{itemId}";
	}

🧩 유효성 결과

출처

https://catsbi.oopy.io/f6bc86a1-d19d-4647-bd12-b2d1d7db1b4b

0개의 댓글