Итак, построим наши примеры на предыдущей бизнес задаче: создание скидочных купонов. На вход наш контроллер получает данные о купонах, которые нужно сгенерить (DiscountCouponGenerationCommand), в качестве результата возвращает список сгенерированных купонов (CouponJson) либо список ошибок валидации.
Поля нашей команды помечены специальными аннотациями, которые называются Constraint. В примере я использовал несколько стандартных аннотаций @Min, @Digits. Также я использовал свои собвстенные Constraint аннотации: @CouponCode для валидации поля couponCode, @DiscountCoupon для валидации всего бина DiscountCouponGenerationCommand.
Как же работают Constraint аннотации? Давайте заглянем внутрь одной их них:
Прежде всего, обратите внимание на аннотацию @Constraint, которая указывает на то, что @CouponCode является Constraint аннотацией, также она содержит в себе имя валидатора, который будет использоваться для валидации поля, помеченного как @CouponCode. В нашем случае валидирующий класс - это CouponCodeValidator. Из других частей аннотации также следует обратить внимание на параметр message, который содержит сообщение-ошибку, которое будет передано на клиент, в случае если валидация поля прошла не успешно. Также аннотация @Target содержит список элементов Java класса, перед которыми мы сможем использовать @CouponCode.
Следует сказать, что текст ошибок валидации можно указывать явно в классе, либо использовать property файл, что особенно удобно, если необходима локализация сообщений. В этом случае вместо сообщения в параметре message нужно указать ключ окруженный фигурными скобками, а само сообщение поместить в файл ValidationMessages.properties, который обязательно должен находиться в корне classpath:
Рассмотрим теперь сам валидатор CouponCodeValidator.
Как видно из примера, валидатор имплементирует generic интерфейс. Первый generic параметр - это constraint который обрабатывает валидатор, второй - тип поля, на котором предположительно будет использоваться constraint. Итак, наш валидатор проверяет, что поле анотированное @CouponCode не пустое, имеет длину 10 символов и начинается с символов 'CP'.
Теперь перейдем собственно к конроллеру, который будет заниматься обработкой команды, валидацией и генерацией купонов.
Мы помечаем параметр DiscountCouponGenerationCommand аннотацией @Valid, которая и включит механизм валидации перед тем, как будет запущен метод generateDiscountCoupons. Всю работу за нас сделает Spring MVC:
- вначале будет создана команда DiscountCouponGenerationCommand, которая заполнится значениями из POST запроса;
- далее команду просканируют на наличие constraint аннотаций, и для каждой из них запустится соответствующий валидатор;
- если ошибок не будет, то вызовется метод контроллера generateDiscountCoupons.
В последних версиях Spring MVC ввели еще одну возможность обработки ошибок валидации - с помощью обработчиков исключений.
Метод аннотированный @ExceptionHandler аннотацией будет автоматически использоваться для обработки ошибок валидации, если таковые возникнут. Параметр MethodArgumentNotValidException содержит всю необходимую нам информацию об ошибках и месте где они возникли.
Конфигурация Spring контекста для JSR-303 не требует ничего особенного, она содержит 2 строки, которые инициализируют поиск компонент и Spring MVC:
В качестве имплементации JSR-303 я использовал Hibernate Validator, его необходимо поместить в classpath. Так как для сборки я использую Maven, я включил в pom.xml следующие зависимости:
Также хочу сказать, что весь код, использованный в примерах, находится на GitHub: https://github.com/hoaz/spring-validation-example. Вы можете склонировать себе этот репозиторий, собрать и поэксперементировать с примерами.
No comments:
Post a Comment