SPRING

Bean Validation - 3

devstep88 2023. 12. 20. 15:24

Bean Validation - 오브젝트 오류

Bean Validation에서 특정필드(FieldError)가 아닌 해당 오브젝트 관련 오류(ObjectError)는 어떻게 처리할 수 있는가?

@ScriptAssert() 사용하면 된다.

@Data
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")
public class Item {
 //...
}

 

메시지 코드

  • ScriptAssert.item
  • ScriptAssert

그러나 사용해 보면 제약이 많고 복잡하다. 검증 기능이 해당 객체의 범위를 넘는 경우가 있는데 그럴 경우 대응이 어렵다.

따라서 오브젝트 오류(글로벌 오류)의 경우 @ScriptAssert를 억지로 사용하는 것보다는 오브젝트 오류 관련 부분만 자바 코드로 작성하는 것을 권장한다고 한다.

 

@ScriptAssert 제거 후 검증 로직 자바코드로 직접 추가

		// 특정 필드가 아닌 복합 룰 검증
        if (item.getPrice() != null && item.getQuantity() != null){
            int resultPrice = item.getPrice() * item.getQuantity();
            if (resultPrice < 10000){
                bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
            }
        }

 

수정 에 추가

  • .field-error css 추가
  • 글로벌 오류 메시지
  • 상품명, 가격, 수량 필드에 검증 기능 추가
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
 	<meta charset="utf-8">
 	<link th:href="@{/css/bootstrap.min.css}"
 			 href="../css/bootstrap.min.css" rel="stylesheet">
 	<style>
 		.container {
 			max-width: 560px;
 		}
 		.field-error {
 			border-color: #dc3545;
 			color: #dc3545;
 		}
 	</style>
</head>
<body>
	<div class="container">
 	<div class="py-5 text-center">
 		<h2 th:text="#{page.updateItem}">상품 수정</h2>
 	</div>
 		<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"
				   placeholder="이름을 입력하세요">
 			<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:field="*{price}" th:errorclass="field-error" class="form-control" placeholder="가격을 입력하세요">
 			<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:field="*{quantity}" th:errorclass="field-error" class="form-control" placeholder="수량을 입력하세요">
 			<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>
</div> <!-- /container -->
</body>
</html>