1.19.2015

14. Hibernate bean validation.



На заре возникновения языка Java,  не было стандартов для валидации данных - проверки на правильность заполнения данных в моделях сущности и разработчики писали свои валидаторы, что было не совсем удобно для сопровождения крупных проектов, страдала переносимость кода. С некоторых пор появился стандарт JSR 303: Bean Validation,  hibernate и некоторые другие вендоры решили реализовать его, мы получили стандарт, которого стоит придерживаться при проверке данных.  Для работы нам нужно подключить библиотеку hibernate-validator все это я делаю через  maven зависимости:

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.0.Final</version>
        </dependency>

Валидацию в hibernate можно провести двумя способами. Первый способ,  представляет из себя  простую последовательность действий, для этого нужно. Первое описать поля сущностей специальными  аннотациями,  которые будут накладывать на поля определенные ограничения.  Второе запросить валидатор, у фабрики классов.  Третье заполнить сущность данными. В четвертых вызвать у валидатора метод .validate() передав в качестве параметра нашу сущность.   Метод проверит  ограничения, которые были наложены на поля сущностей  аннотациями и если были нарушены какие либо правила, будет возвращен объект Set  типа <ConstraintViolation>,  в котором будут содержаться  “ошибки” валидации.

Стоит упомянуть, что ограничения накладываемые  аннотациями, не имеют ни чего общего с ограничениями баз данных,  т. е. ограничения валидации не переносятся в схему базы данных, если параметр hibernate.validator.apply_to_ddl  выставлен в false, если выставить параметр в true,  то все возможные ограничения перенесутся в схему базы данных:

<property name="hibernate.validator.apply_to_ddl">false</property>


Аннотация
Проверяемые типы данных
Применение
Метаданные переносятся ли в базу данных.
@AssertFalse
Boolean, boolean
Проверяет, имеет ли элемент значение false.
Нет.
@AssertTrue
Boolean, boolean
Проверяет, имеет ли элемент значение true.
Нет.
@DecimalMax(value=, inclusive=)
BigDecimal, BigInteger, CharSequence, byte, short, int, long и их примитивные типы.
Проверяет, имеет ли элемент значение большее чем  value, а если параметр inclusive=true, больше или равно чем value.
Нет.
@DecimalMin(value=, inclusive=)
BigDecimal, BigInteger, CharSequence, byte, short, int, long и их примитивные типы.
Проверяет, имеет ли элемент значение меньше чем  value, а если параметр inclusive=true, меньше или равно чем value.
Нет.
@Digits(integer=, fraction=)
BigDecimal, BigInteger, CharSequence, byte, short, int, long и их примитивные типы.
Проверяет, имеет ли число количество знаков до запятой меньше или равно integer, и кол-во знаков после запятой fraction
Создается  число с точностью до запятой integer и после запятой   fraction.
@Future
java.util.Date, java.util.Calendar;
Проверяет, имеет ли дата значение большее, чем  текущая дата (системная).
Нет.
@Max(value=)
BigDecimal, BigInteger, CharSequence, byte, short, int, long и их примитивные типы.
Проверяет, имеет ли элемент значение меньше или равно чем value.
Создает ограничение на поле таблицы.
@Min(value=)
BigDecimal, BigInteger, CharSequence, byte, short, int, long и их примитивные типы.
Проверяет, имеет ли элемент значение больше или равно чем  value.
Создает ограничение на поле таблицы.
@NotNull
Применим к любым типам данных
Проверяет, имеет ли элемент значение not null.
Создает ограничение на поле таблицы not null.
@Null
Применим к любым типам данных
Проверяет, имеет ли элемент значение  null.
Нет.
@Past
java.util.Date, java.util.Calendar;
Проверяет, имеет ли дата значение меньше чем  текущая дата (системная).
Нет.
@Pattern(regex=, flag=)
CharSequence – Строки.
Проверяет, строку на совпадение с регулярным выражением regex.
Нет.
@Size(min=, max=)
CharSequence, Collection, Map и arrays
Проверяет размерность элемента, т. е.  количество элементов должно быть в пределах минимума min и максимума max включительно.
Создается ограничение,
@Valid
Любой не примитивный тип.
Используется для проверки ассоциированных объектов, коллекций, массивов данных. 
Нет.

Рассмотрим пример, создадим класс Per, с двумя полями пометим их аннотациями:

public class Per implements Serializable{
    @NotNull
    private Long idP;
    @Size(min = 3, message="Длина фамилии должна быть больше трех")
    private String name;
}

Создадим две заведомо ошибочные ситуации в программе,  и отловим наши ошибки:

public class Test_Validation {

    public Test_Validation() {
        ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
        Validator validator = vf.getValidator();
        Per p = new Per();
        p.setName("Vi");
            Set<ConstraintViolation<Per>> constraintViolations = validator.validate(p);
            for (ConstraintViolation<Per> cv : constraintViolations) {
                System.out.format("Error property: [%s], value: [%s], message: [%s]\n",
                        cv.getPropertyPath(), cv.getInvalidValue(), cv.getMessage());
            }
    }

    public static void main(String[] args) {
        new Test_Validation();
    }

}

Отловим две ошибки допущенные нами:

Error property: [idP], value: [null], message: [may not be null]
Error property: [name], value: [Vi], message: [Длина фамилии должна быть больше трех]

И так перейдем ко второму способу,  второй способ, включает валидацию на уровне hibernate,  для этого нужно в файле настроек  hibernate.cfg.xml  добавить 3 слушателя (Listener). Эти слушатели будут перехватывать, и проверять правильность ввода данных, перед вставкой (Insert), перед изменениями (Update) и перед  удалением  (Delete).

        <event type="pre-update">
            <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
        </event>
        <event type="pre-insert">
            <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
        </event>
        <event type="pre-delete">
            <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
        </event>

Применяем аннотации к сущности, в случае нарушения ограничения, какого либо поля будет вызываться исключительная ситуация javax.validation.ValidationException, которое вы всегда можете отловить и обработать.

Комментариев нет:

Отправить комментарий