728x90
Bean Validation 수정 적용
EditController 수정
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute Item item, BindingResult bindingResult) {
//특정 필드가 아닌 복합 룰 검증
if (item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
}
}
if(bindingResult.hasErrors()){
log.info("errors={}",bindingResult);
return "validation/v3/editForm";
}
itemRepository.update(itemId, item);
return "redirect:/validation/v3/items/{itemId}";
}
EditForm 수정
<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="id" th:text="#{label.item.id}">상품 ID</label>
<input type="text" id="id" th:field="*{id}" class="form-control" readonly>
</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" >
<div class="field-error" th:errors="*{itemName}">
상품명 오류
</div>
</div>
<div>
<label for="price" th:text="#{label.item.price}">가격</label>
<input type="text" id="price" th:errorclass="field-error" th:field="*{price}" class="form-control">
<div class="field-error" th:errors="*{price}">
가격 오류
</div>
</div>
<div>
<label for="quantity" th:text="#{label.item.quantity}">수량</label>
<input type="text" id="quantity" th:errorclass="field-error" th:field="*{quantity}" class="form-control">
<div class="field-error" th:errors="*{quantity}">
수량 오류
</div>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit" th:text="#{button.save}">저장</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='item.html'"
th:onclick="|location.href='@{/validation/v3/items/{itemId}(itemId=${item.id})}'|"
type="button" th:text="#{button.cancel}">취소</button>
</div>
</div>
</form>
Bean Vlidation의 한계
- 수정 요구사항과, 등록 요구사항이 다를 때가 있다
- 수정 시에는 quantity에 제한이 없고 ID가 필수이다.
@Data
public class Item {
@NotNull //수정 요구사항을 추가한 것이다.
private Long id;
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000) //하이버 네이트 구현체에서만 동작한다
private Integer price;
@NotNull
//@Max(9999) //수정요구사항 추가
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
- 수정 시 요구사항을 적용하였더니 등록에서 수량을 MAX 검증이 되지 않고, ID 값이 없어 검증 실패가 된다.
- 참고
- 현재 구조에서는 수정시 item의 id 값은 항상 들어있도록 로직이 구성되어 있다. 그래서 검증하지 않아도 된다고 생각할 수 있다. 그런데 HTTP 요청은 언제든지 악의적으로 변경해서 요청할 수 있으므로 서버에서 항상 검증해야 한다. 예를 들어서 HTTP 요청을 변경해서 item의 id 값을 삭제하고 요청할 수도 있다. 따라서 최종 검증은 서버에서 진행하는 것이 안전한다
- 결과적으로 item 은 등록과 수정에서 검증 조건의 충돌이 발생하고, 등록과 수정은 같은 BeanValidation 을 적용할 수 없다. 이 문제를 어떻게 해결할 수 있을까? 다음 장에서 해결 방법을 알아보자
728x90
'스프링 MVC 2편(백엔드 웹 개발 활용 기술)' 카테고리의 다른 글
| Ch05. 검증(Bean Validation) - Form 전송 객체 분리 (0) | 2022.03.16 |
|---|---|
| Ch05. 검증(Bean Validation) - Bean Validation(groups) (0) | 2022.03.16 |
| Ch05. 검증(Bean Validation) - Bean Validation(오브젝트 오류) (0) | 2022.03.16 |
| Ch05. 검증(Bean Validation) - Bean Validation(에러 코드) (0) | 2022.03.16 |
| Ch05. 검증(Bean Validation) - Bean Validation(스프링 적용) (0) | 2022.03.16 |