Кратко о Bean Validation
Spring Framework обеспечивает поддержку API-интерфейса Java Bean Validation
Bean Validation обеспечивает общий способ проверки достоверности с помощью объявления ограничений и метаданных для Java-приложений. Чтобы использовать его, вы аннотируете свойства модели предметной области декларативными ограничениями проверки достоверности, которые затем применяются средой выполнения. Существуют встроенные ограничения, но вы также можете определить свои собственные ограничения.
Рассмотрим следующий пример, в котором показана простая модель PersonForm
с двумя свойствами:
public class PersonForm {
private String name;
private int age;
}
class PersonForm(
private val name: String,
private val age: Int
)
Bean Validation позволяет объявлять ограничения, как показано в следующем примере:
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
class PersonForm(
@get:NotNull @get:Size(max=64)
private val name: String,
@get:Min(0)
private val age: Int
)
Затем валидатор Bean Validation проверяет экземпляры этого класса, основываясь на объявленных ограничениях. Общую информацию о данном API-интерфейсе см. в разделе "Bean Validation". Конкретные ограничения см. в документации по Hibernate Validator. Чтобы узнать, как настроить поставщика проверки достоверности бинов в качестве бина Spring, продолжайте читать.
Конфигурирование поставщика Bean Validation
Spring обеспечивает полную поддержку API-интерфейса Bean Validation, включая начальную загрузку поставщика Bean Validation в качестве бина Spring. Это позволяет внедрять javax.validation.ValidatorFactory
или javax.validation.Validator
всюду, где требуется проверка достоверности в приложении.
Вы можете использовать LocalValidatorFactoryBean
для настройки валидатора по умолчанию в качестве бина Spring, как показано в следующем примере:
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Базовая конфигурация в предыдущем примере вызывает инициализацию проверки достоверности бинов, используя механизм загрузки по умолчанию. Поставщик Bean Validation, такой как Hibernate Validator, должен находиться в пути классов и определяться автоматически.
Внедрение валидатора
LocalValidatorFactoryBean
реализует как javax.validation.ValidatorFactory
и javax.validation.Validator
, так и org.springframework.validation.Validator
из Spring. Вы можете внедрить ссылку на любой из этих интерфейсов в бины, которые должны вызывать логику проверки достоверности.
Можно внедрить ссылку на javax.validation.Validator
, если предпочтение отдается прямой работе с API-интерфейсом Bean Validation, как показано в следующем примере:
import javax.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
import javax.validation.Validator;
@Service
class MyService(@Autowired private val validator: Validator)
Можно внедрить ссылку на org.springframework.validation.Validator
, если бин требует API-интерфейс Spring Validation, как показано в следующем примере:
import org.springframework.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
import org.springframework.validation.Validator
@Service
class MyService(@Autowired private val validator: Validator)
Настройка специальных ограничений
Каждое ограничение проверки достоверности бинов состоит из двух частей:
-
Аннотации
@Constraint
, которая объявляет ограничение и его настраиваемые свойства. -
Реализации интерфейса
javax.validation.ConstraintValidator
, который реализует логику работы ограничения.
Чтобы связать объявление с реализацией, каждая аннотация @Constraint
ссылается на соответствующий класс реализации ConstraintValidator
. Во время выполнения ConstraintValidatorFactory
создает экземпляр реализации, на которую ссылаются, если аннотация ограничения встречается в вашей модели предметной области.
По умолчанию LocalValidatorFactoryBean
конфигурирует SpringConstraintValidatorFactory
, которая использует Spring для создания экземпляров ConstraintValidator
. Это позволяет специальным ConstraintValidators
пользоваться внедрением зависимостей, как и любым другим бином Spring.
В следующем примере показано специальное объявление @Constraint
, за которым следует связанная реализация ConstraintValidator
, использующая Spring для внедрения зависимостей:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator::class)
annotation class MyConstraint
import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired;
private Foo aDependency;
// ...
}
import javax.validation.ConstraintValidator
class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {
// ...
}
Как следует из предыдущего примера, реализация ConstraintValidator
может иметь свои зависимости, помеченные аннотацией @Autowired
, как и любой другой бин Spring.
Проверка достоверности методов, управляемая Spring
Вы можете внедрить функцию проверки методов, поддерживаемую Bean Validation 1.1 (и, в качестве специального расширения, также Hibernate Validator 4.3), в контекст Spring через определение бина MethodValidationPostProcessor
:
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
Чтобы осуществлять проверку достоверности методов, управляемую Spring, все целевые классы должны быть аннотированы аннотацией @Validated
из Spring, в которой по желанию можно также объявить группы поверки достоверности для использования. См. MethodValidationPostProcessor
для получения более подробной информации о настройке с использованием поставщиков Hibernate Validator и Bean Validation 1.1.
Проверка достоверности методов использует АОП-прокси в обход целевых классов, либо динамические прокси из JDK для методов на интерфейсах, либо прокси из CGLIB. Существуют определенные ограничения при использовании прокси. Кроме того, помните, что для проксированных классов всегда нужно использовать методы и акцессоры; прямой доступ к полям работать не будет.
Дополнительные параметры конфигурации
Конфигурация LocalValidatorFactoryBean
по умолчанию достаточна для большинства случаев. Существует ряд опций конфигурации для различных конструкций Bean Validation, от интерполяции сообщений до разрешения обхода. См. javadoc по LocalValidatorFactoryBean
для получения дополнительной информации об этих опциях.
Конфигурирование DataBinder
Начиная со Spring 3, вы можете конфигурировать экземпляр DataBinder
с помощью Validator
. После конфигурирования можно вызывать Validator
, обратившись к binder.validate()
. Любые Errors
проверки достоверности автоматически добавляются к привязке BindingResult
.
В следующем примере показано, как программно использовать DataBinder
для вызова логики проверки достоверности после привязывания к целевому объекту:
Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());
// привязываем к целевому объекту
binder.bind(propertyValues);
// валидируем целевой объект
binder.validate();
// получаем результат BindingResult, включающий все ошибки валидации
BindingResult results = binder.getBindingResult();
val target = Foo()
val binder = DataBinder(target)
binder.validator = FooValidator()
// привязываем к целевому объекту
binder.bind(propertyValues)
// валидируем целевой объект
binder.validate()
// получаем результат BindingResult, включающий все ошибки валидации
val results = binder.bindingResult
Также можно настроить DataBinder
с использованием нескольких экземпляров Validator
через dataBinder.addValidators
и dataBinder.replaceValidators
. Это имеет смысл при комбинировании глобально сконфигурированной валидации бинов с использованием Validator
из Spring, настроенного локально для экземпляра DataBinder.