Loading...
Spring Framework Reference Documentation 7.0.2의 Validation Using Spring’s Validator Interface의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
Spring은 객체를 검증하기 위해 사용할 수 있는 Validator 인터페이스를 제공합니다.
Validator 인터페이스는 Errors 객체를 사용하여 동작하므로, 검증을 수행하는 동안 validator는 검증 실패를 Errors 객체에 보고할 수 있습니다.
다음은 작은 data 객체의 예시입니다:
1public class Person { 2 3 private String name; 4 private int age; 5 6 // the usual getters and setters... 7}
1class Person(val name: String, val age: Int)
다음 예시는 org.springframework.validation.Validator 인터페이스의 다음 두 메서드를 구현하여 Person 클래스에 대한 validation 동작을 제공합니다:
supports(Class): 이 Validator가 제공된 Class의 인스턴스를 검증할 수 있는가?validate(Object, org.springframework.validation.Errors): 주어진 객체를 검증하고, 검증 error가 있는 경우, 이를 제공된 Errors 객체에 등록합니다.Validator를 구현하는 것은 상당히 간단하며, 특히 Spring Framework가 제공하는 ValidationUtils helper 클래스를 알고 있다면 더 그렇습니다.
다음 예시는 Person 인스턴스에 대한 Validator를 구현한 것입니다:
1public class PersonValidator implements Validator { 2 3 /** 4 * This Validator validates only Person instances 5 */ 6 public boolean supports(Class clazz) { 7 return Person.class.equals(clazz); 8 } 9 10 public void validate(Object obj, Errors e) { 11 ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); 12 Person p = (Person) obj; 13 if (p.getAge() < 0) { 14 e.rejectValue("age", "negativevalue"); 15 } else if (p.getAge() > 110) { 16 e.rejectValue("age", "too.darn.old"); 17 } 18 } 19}
1class PersonValidator : Validator { 2 3 /** 4 * This Validator validates only Person instances 5 */ 6 override fun supports(clazz: Class<*>): Boolean { 7 return Person::class.java == clazz 8 } 9 10 override fun validate(obj: Any, e: Errors) { 11 ValidationUtils.rejectIfEmpty(e, "name", "name.empty") 12 val p = obj as Person 13 if (p.age < 0) { 14 e.rejectValue("age", "negativevalue") 15 } else if (p.age > 110) { 16 e.rejectValue("age", "too.darn.old") 17 } 18 } 19}
ValidationUtils 클래스의 static rejectIfEmpty(..) 메서드는 name 프로퍼티가 null이거나 빈 string인 경우 이를 거부하는 데 사용됩니다.
앞서 보인 예시 외에 어떤 기능을 제공하는지 확인하려면 ValidationUtils javadoc을 참조하십시오.
풍부한 객체 내의 각 nested 객체를 검증하기 위해 하나의 Validator 클래스를 구현하는 것도 물론 가능하지만, 각 nested 클래스의 객체에 대한 validation 로직을 자체 Validator 구현에 캡슐화하는 것이 더 나을 수 있습니다.
“rich” 객체의 간단한 예는 두 개의 String 프로퍼티(이름과 성)와 복잡한 Address 객체로 구성된 Customer입니다. Address 객체는 Customer 객체와 독립적으로 사용될 수 있으므로, 별도의 AddressValidator가 구현되었습니다. CustomerValidator에서 AddressValidator 클래스에 포함된 로직을 copy-and-paste하지 않고 재사용하려면, 다음 예시에서 보듯이 CustomerValidator 내에 AddressValidator를 dependency-inject하거나 생성하면 됩니다:
1public class CustomerValidator implements Validator { 2 3 private final Validator addressValidator; 4 5 public CustomerValidator(Validator addressValidator) { 6 if (addressValidator == null) { 7 throw new IllegalArgumentException("The supplied [Validator] is " + 8 "required and must not be null."); 9 } 10 if (!addressValidator.supports(Address.class)) { 11 throw new IllegalArgumentException("The supplied [Validator] must " + 12 "support the validation of [Address] instances."); 13 } 14 this.addressValidator = addressValidator; 15 } 16 17 /** 18 * This Validator validates Customer instances, and any subclasses of Customer too 19 */ 20 public boolean supports(Class clazz) { 21 return Customer.class.isAssignableFrom(clazz); 22 } 23 24 public void validate(Object target, Errors errors) { 25 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required"); 26 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required"); 27 Customer customer = (Customer) target; 28 try { 29 errors.pushNestedPath("address"); 30 ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors); 31 } finally { 32 errors.popNestedPath(); 33 } 34 } 35}
1class CustomerValidator(private val addressValidator: Validator) : Validator { 2 3 init { 4 if (addressValidator == null) { 5 throw IllegalArgumentException("The supplied [Validator] is required and must not be null.") 6 } 7 if (!addressValidator.supports(Address::class.java)) { 8 throw IllegalArgumentException("The supplied [Validator] must support the validation of [Address] instances.") 9 } 10 } 11 12 /* 13 * This Validator validates Customer instances, and any subclasses of Customer too 14 */ 15 override fun supports(clazz: Class<*>): Boolean { 16 return Customer::class.java.isAssignableFrom(clazz) 17 } 18 19 override fun validate(target: Any, errors: Errors) { 20 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required") 21 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required") 22 val customer = target as Customer 23 try { 24 errors.pushNestedPath("address") 25 ValidationUtils.invokeValidator(this.addressValidator, customer.address, errors) 26 } finally { 27 errors.popNestedPath() 28 } 29 } 30}
Validation error는 validator에 전달된 Errors 객체에 보고됩니다.
Spring Web MVC의 경우 <spring:bind/> 태그를 사용하여 error message를 확인할 수 있지만, 직접 Errors 객체를 검사할 수도 있습니다. 제공되는 메서드에 대한 더 많은 정보는 javadoc에서 찾을 수 있습니다.
Validator는 binding process를 수반하지 않고 주어진 객체에 대한 즉각적인 validation을 위해 local하게 호출될 수도 있습니다.
6.1부터는 새로운 Validator.validateObject(Object) 메서드를 통해 이 작업이 단순화되었으며, 이제 기본적으로 사용 가능합니다. 이 메서드는 검사할 수 있는 단순한 Errors 표현을 반환합니다. 일반적으로 hasErrors()를 호출하거나, error summary message를 예외로 변환하기 위한 새로운 failOnError 메서드를 호출합니다(예: validator.validateObject(myObject).failOnError(IllegalArgumentException::new)).
Validation, Data Binding, and Type Conversion
Data Binding