java 스프링부트 ( spring boot ) / 목록 ( 3 ) 검증 방법

김동명·2022년 11월 30일
0

스프링부트

목록 보기
8/19

// 기본내용은 java 스프링부트 ( spring boot ) / 목록 ( 1 ) 와 동일합니다.

프로젝트 설정

  • application.properties
#port
server.port=9090

#thymeleaf cache
spring.thymeleaf.cache=false

#encoding
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
server.servlet.encoding.enabled=true

시작

스프링과 thymeleaf를 이용한 검증방법

1. 기본

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

  • StringUtils.hasText : 값이 있을 경우에는 true, 공백이나 null이 들어올 경우에는 false를 반환하게 된다.
  • FieldError : field 단위의 error를 처리하는 spring에서 제공해주는 객체
  • ItemController.java 수정
...
	@PostMapping("/add")
	public String saveV7( Item item,  BindingResult bindingResult, RedirectAttributes redirectAttributes ) {
		
        if(!StringUtils.hasText(item.getItemName())) {
		bindingResult.addError(new FieldError("item", "itemName", "상품이름은 필수입니다."));
		}
        
		// 검증 실패하면 다시 입력 폼으로
        if(bindingResult.hasErrors()) {
        	System.out.println("errors = " + bindingResult);
        	return "basic/addForm";
        }
        
        if( item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError( new FieldError("item", "price", "가격은 1,000~1,000,000까지만 허용합니다"));
        }
        
		if( item.getQuantity() == null || item.getQuantity() > 10000) {
			bindingResult.addError(new FieldError("item", "quantity", "수량은 최대 9,999 까지 허용합니다."));
		}
        
		Item saveitem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", saveitem.getId());
		redirectAttributes.addAttribute("status", true);
		return "redirect:/basic/items/{itemId}";
	}
...    

  • 타임리프는 스프링의 BindingResult를 활용해서 편리한 오류 표현기능 제공
  • field : BindingResult 가 제공하는 오류에 접근 할 수 있다.
  • th:errorclass : th:field에서 지정한 필드에 오류가 있으면 class를 추가
  • th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if의 편의 기능
  • addForm.html 수정
			<div>
				<label for="itemName">상품명</label>
				<input type="text" id="itemName" th:field="${item.itemName}" th:errorclass="field-error" class="form-control" placeholder="이름을 입력하세요">
				<div class="field-error" th:errors="*{itemName}">상품명 오류</div>
			</div>
			<div>
				<label for="price">가격</label> 
				<input type="text" id="price" th:field="*{price}" th:errorclass="field-error" class="form-control" placeholder="가격을 입력하세요">
				<div class="field-error" th:errors="*{price}">가격 오류</div>
			</div>
			<div>
				<label for="quantity">수량</label> 
				<input type="text" id="quantity" th:field="*{quantity}" th:errorclass="field-error" class="form-control" placeholder="수량을 입력하세요">
				<div class="field-error" th:errors="*{quantity}">수량 오류</div>

  • 출력


2. 정보 유지

	 파라미터에 대한 설명
	   FieldError param
	   	- objectName	: 오류가 발생한 객체 이름
	   	- field			: 오류 필드
	   	- rejectedValue	: 사용자가 입력한 값 ( 거절된 값 )
	 	- bindingFailure: 타입오류와 같은 바인딩 실패인지 구분
	  	- codes			: 메시지 코드
	   	- argumnets		: 메시지에서 사용하는 인자
	   	- defaultMessage: 기본 오류 메세지	

2-1. 기본

  • ItemController.java 수정
...
	@PostMapping("/add")
	public String saveV8( Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes ) {


		if(!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("itme", "itemName", item.getItemName(), false, null, null,  "상품이름은 필수입니다."));
		}

		if( item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError(new FieldError("itme", "price", item.getPrice(), false, null, null,  "가격은 1,000~1,000,000까지만 허용합니다"));
		}

		if( item.getQuantity() == null || item.getQuantity() > 10000) {
			bindingResult.addError(new FieldError("itme", "quantity", item.getQuantity(), false, null, null,  "수량은 최대 9,999 까지 허용합니다."));
		}
		
        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}";
	}
...    


2-2. 파라미터 이용


  • application.properties 추가
...
spring.messages.basename=errors

  • resources > file생성 > errors.proerties 생성
#required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0}~{1}까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
required.default=데이터 오류입니다.

  • ItemController.java 수정
...
	@PostMapping("/add")
	public String saveV9( Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes ) {

		if(!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("itme", "itemName", item.getItemName(), false, new String[] { "required.item.itemName"}, null,  null));

		if( item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
			bindingResult.addError(new FieldError("itme", "price", item.getPrice(), false, new String[] {"range.item.price"} , new Object[] {1000,10000}, null));
		}

		if( item.getQuantity() == null || item.getQuantity() > 10000) {
			bindingResult.addError(new FieldError("itme", "quantity", item.getQuantity(), false, new String[] {"max.item.quantity"}, new Object[] {9999}, null));
		}
...

출력



2-3. 응용 1 - "required.default"를 출력하도록 수정

  • ItemController.java 수정
...
		if(!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("itme", "itemName", item.getItemName(), false, new String[] { "required.item.itemName","required.default"}, null,  null));
		}
...

  • resources > file > errors.proerties 수정
#required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0}~{1}까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
required.default=데이터 오류입니다.

  • 출력



2-4. 응용 2 - "defaultMessage"를 출력하도록 수정

  • ItemController.java 수정
...
		if(!StringUtils.hasText(item.getItemName())) {
			bindingResult.addError(new FieldError("itme", "itemName", item.getItemName(), false, new String[] { "required.item.itemName","required.default"}, null,  "defaultMessage"));
		}
...        

  • resources > file > errors.proerties
#required.item.itemName=상품 이름은 필수입니다.
#required.default=데이터 오류입니다.

  • 출력

2-5. 타입오류 메세지 설정

2-5-1. Integer 타입에 맞지 않을경우 해당 내용 출력

  • resources > file > errors.proerties 수정
...
typeMismatch.java.lang.Integer=숫자를 입력해주세요.
...

  • 출력

2-5-2. type오류 전체를 통틀어서 메세지 설정 가능

  • resources > file > errors.proerties 수정
...
#typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.
...

  • 출력
profile
코딩공부

0개의 댓글