본문 바로가기

Spring 정리ver2/Framework

[Spring Framework core] 3. Validation, Data Binding, and Type Conversion (1)

728x90

 

3.1. Validation by Using Spring’s Validator Interface ~ 3.2. Resolving Codes to Error Messages

 

 

 

Validation, Data Binding, and Type Conversion

 

Validation을 business Logic으로 간주하면 장단점이 있고, Spring은 유효성 검사 및 데이터 바인딩을 위한 디자인을 제공하고 있다.

Validation은 Web Layer에 연결되지않아야하고 localizer가 쉬워야하며 사용 가능한 모든 available validator 와 연결이 되어야한다.

Spring은 Validator 애플리케이션의 모든 layer에서 기본적이고 쉽게 사용할 수 있는 contract를 제공한다.

 

데이터 바인딩은 사용자 입력이 응용 프로그램의 도메인 모델(또는 입력을 처리할 때 사용하는 개체)에 동적으로 binding하는 데 유용하다.

Spring은 정확히 이를 수행하기 위해 적절한 이름의 DataBinder를 제공한다.

Validator와 DataBinder는 주로 웹 레이어에서 사용되지만 이에 국한되지 않는 유효성 검사 패키지를 구성한다.

BeanWrapper는 Spring Framework의 기본 개념이며 많은 곳에서 사용된다. BeanWrapper를 직접 사용할 필요는 없다.

참조용으로 이 장에서 BeanWrapper에 대해 설명한다. BeanWrapper를 사용하려는 경우 데이터를 객체에 바인딩하려고 할 때 그렇게 할 가능성이 높기 때문이다.  

 

Spring의 DataBinder와 하위 수준의 BeanWrapper는 모두 PropertyEditorSupport 구현을 사용하여 속성 값을 구문 분석하고 형식을 지정한다. PropertyEditor 및 PropertyEditorSupport 유형은 JavaBeans 사양의 일부이며 이 장에서도 설명된다.

Spring의 core.convert 패키지는 일반 유형 변환 기능과 UI 필드 값을 형식화하기 위한 상위 레벨 형식 패키지를 제공한다. 이러한 패키지를 PropertyEditorSupport 구현에 대한 간단한 대안으로 사용할 수 있다.

 

Spring은 설정 인프라와 Spring의 자체 유효성 검사기 계약에 대한 어댑터를 통해 Java Bean 유효성 검사를 지원해준다. 응용 프로그램은 Java Bean 유효성 검사에 설명된 대로 전역적으로 한 번 Bean 유효성 검사를 활성화하고 모든 유효성 검사 요구에 대해 독점적으로 사용할 수 있다. 웹 레이어에서 애플리케이션은 DataBinder 구성에 설명된 대로 DataBinder별로 컨트롤러-로컬 Spring Validator 인스턴스를 추가로 등록할 수 있다. 이는 사용자 지정 유효성 검사 논리를 연결하는 데 유용할 수 있다.

 

 

 

 

 

3.1. Validation by Using Spring’s Validator Interface

Spring은 객체의 유효성을 검사할 때 사용할 수 있는 Validator 인터페이스를 제공한다. 이는 Errors object 를 사용하여 작동하므로 유효성검사를 할 동안 유효성 검사기가 Eoors 개체에 유효성 검사 실패를 보고 할 수 있다.

 

public class Person {

    private String name;
    private int age;

    // the usual getters and setters...
}

 

 

 

org.springframework.validation.Validator 인터페이스의 다음 두 메서드를 구현하여 Person 클래스에 대한 유효성 검사 동작을 시행한다.

 

support(Class): 이 유효성 검사기는 제공된 클래스의 인스턴스를 검증할 수 있는지 확인한다

validate(Object, org.springframework.validation.Errors): 주어진 객체를 검증하고 검증 오류의 경우 Errors 객체에 등록한다.  특히 Spring 프레임워크도 제공하는 ValidationUtils 헬퍼 클래스를 알고 있는 경우 Validator를 구현하는 것이 간단하다. 다음 예제는 Person 인스턴스에 대한 Validator를 구현한다.

 

 

public class PersonValidator implements Validator {

    /**
     * This Validator validates only Person instances
     */
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz);
    }

    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
        Person p = (Person) obj;
        if (p.getAge() < 0) {
            e.rejectValue("age", "negativevalue");
        } else if (p.getAge() > 110) {
            e.rejectValue("age", "too.darn.old");
        }
    }
}

ValidationUtils 클래스의 rejectIfEmpty(..) 메서드는 null 또는 빈 문자열인 경우 이름 속성을 거부하는 데 사용한다.

ValidationUtils javadoc을 살펴보고 이전에 표시된 예제 외에 어떤 기능을 제공하는지 확인 해볼 것.  https://docs.spring.io/spring-framework/docs/6.0.7/javadoc-api/org/springframework/validation/ValidationUtils.html

 

ValidationUtils (Spring Framework 6.0.7 API)

Reject the given field with the given error code, error arguments and default message if the value is empty or just contains whitespace. An 'empty' value in this context means either null, the empty string "", or consisting wholly of whitespace. The object

docs.spring.io

 단일 유효성 검사기 클래스를 구현하여 풍부한 개체의 중첩된 개체 각각의 유효성을 검사하는 것이 가능하지만 자체의 유효성 검사기 구현에서 개체의 각 중첩된 개체 클래스에 대한 유효성 검사 논리를 캡슐화하는 것이 더 나은 경우가 있다. "rich"한 개체의 간단한 예는 두 개의 문자열 속성(첫 번째 및 두 번째 이름)과 복잡한 주소 개체로 구성된 경우이다.

주소 개체는 고객 개체와 독립적으로 사용할 수 있으므로 별도의 AddressValidator가 구현되어있다.

CustomerValidator가 복사하여 붙여넣기를 사용하지 않고 AddressValidator 클래스에 포함된 논리를 재사용하도록 하려면 다음과 같이 CustomerValidator 내에서 AddressValidator를 종속성 주입하거나 인스턴스화할 수 있다.

public class CustomerValidator implements Validator {

    private final Validator addressValidator;

    public CustomerValidator(Validator addressValidator) {
        if (addressValidator == null) {
            throw new IllegalArgumentException("The supplied [Validator] is " +
                "required and must not be null.");
        }
        if (!addressValidator.supports(Address.class)) {
            throw new IllegalArgumentException("The supplied [Validator] must " +
                "support the validation of [Address] instances.");
        }
        this.addressValidator = addressValidator;
    }

    /**
     * This Validator validates Customer instances, and any subclasses of Customer too
     */
    public boolean supports(Class clazz) {
        return Customer.class.isAssignableFrom(clazz);
    }

    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
        Customer customer = (Customer) target;
        try {
            errors.pushNestedPath("address");
            ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
        } finally {
            errors.popNestedPath();
        }
    }
}

Errors 유효성 검사 오류는 유효성 검사기에 전달된 개체 에 보고된다. 

Spring Web MVC의 경우 <spring:bind/>태그를 사용하여 오류 메시지를 검사할 수 있지만 Errors개체를 ​​직접 검사할 수도 있다. 

 

 

 

3.2. Resolving Codes to Error Messages

 이 섹션에서는 유효성 검사 오류에 해당하는 메시지 출력에 대한 것이다. 이전 섹션에 표시된 예에서는 이름 및 연령 필드를 rejected했다. MessageSource를 사용하여 오류 메시지를 출력하려면 필드를 거부할 때 제공하는 오류 코드(이 경우 'name' 및 'age')를 사용하여 출력할 수 있다. Errors 인터페이스에서 rejectValue 또는 다른 거부 메서드 중 하나를 호출하면(직간접적으로, 예를 들어 ValidationUtils 클래스를 사용하여) 기본 구현은 전달한 코드를 등록할 뿐만 아니라 여러 추가 오류 코드인 MessageCodesResolver는 Errors 인터페이스가 등록하는 오류 코드를 결정한다. 기본적으로 DefaultMessageCodesResolver가 사용되는데, 예를 들어 이 함수는 사용자가 제공한 코드로 메시지를 등록할 뿐만 아니라 거부 메소드에 전달한 필드 이름을 포함하는 메시지도 등록한다.

따라서 too.darn.old 코드와 별도로 rejectValue("age", "too.darn.old")를 사용하여 필드를 거부하면 Spring은 too.darn.old.age 및 too.darn.old도 등록해준다. .age.int(첫 번째는 필드 이름을 포함하고 두 번째는 필드 유형을 포함함). 이는 오류 메시지를 대상으로 지정할 때 개발자를 돕기 위한 편의를 위해 수행한다.  MessageCodesResolver 및 기본 전략에 대한 자세한 내용은 각각 MessageCodesResolver 및 DefaultMessageCodesResolver의 javadoc에서 찾으면 된다.

 

 

 

728x90