// 기본내용은 java 스프링부트 ( spring boot ) / 목록 ( 1 ) 와 동일합니다.
프로젝트 설정
#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를 이용한 검증방법
- 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>
파라미터에 대한 설명 FieldError param - objectName : 오류가 발생한 객체 이름 - field : 오류 필드 - rejectedValue : 사용자가 입력한 값 ( 거절된 값 ) - bindingFailure: 타입오류와 같은 바인딩 실패인지 구분 - codes : 메시지 코드 - argumnets : 메시지에서 사용하는 인자 - defaultMessage: 기본 오류 메세지
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}";
}
...
application.properties
추가...
spring.messages.basename=errors
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));
}
...
출력
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));
}
...
errors.proerties
수정#required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0}~{1}까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
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, "defaultMessage"));
}
...
errors.proerties
#required.item.itemName=상품 이름은 필수입니다.
#required.default=데이터 오류입니다.
errors.proerties
수정...
typeMismatch.java.lang.Integer=숫자를 입력해주세요.
...
errors.proerties
수정...
#typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.
...