Сегодня мы публикуем статью Олега Артемова. Нашего старого боевого товарища и знатока Spring.
Добрый день всем !!
Данная статья является лишь первой моей статьей об использовании Spring, поэтому не стоит судить строго. :). На её написание меня натолкнуло постоянное количество одного и того же кода в нашем WEB - приложении, поэтому в один прекрасный момент я решил сделать что-нить более элегантное( благо у Spring возможностей хоть отбавляй).
Итак, начнем с преамбулы.
Как мы видим, это код в обычном Spring контроллере, который возвращает JSON. Обычно наш код выглядит именно так. Т.е мы видим, что приходит команда (набор параметров с UI), которые ввел пользователь и объект BindingResult (Spring сам его формирует и передает как параметр в метод) . Дальше проводится валидация команды, если она не прошла – возвращаем перечень ошибок, в противном случае выполняем какую-то логику и возвращаем статус ОК. Таких методов в разных контроллерах у нас довольно много и как любому программисту мне не хочется дублировать код. Поэтому я поставил перед собой 2 задачи:
- Как сделать, чтобы когда я ставлю @Valid на команде (а это стандартные возможности Spring), то вызывался нужный мне валидатор (который я зарегистрирую в контексте, а не стандартный JSR валидатор – у меня в валидаторах часто кастомная логика).
- Как сделать, чтобы в контроллер приходила команда только в том случае, если валидация полностью прошла. Этим я избавлюсь от ненужных инжектов валидаторов в контроллер и их постоянного вызова.
- Есть стандартная Spring – аннотация для метода InitBinder, которая позволяет регистрировать валидаторы для разных команд. Но тогда бы мне в каждом контроллере пришлось бы писать метод с этой аннотацией для каждой команды, которую обрабатывает контроллер (не очень хочется).
- Зарегистрировать глобальный валидатор, который централизованно будет управлять валидацией.
Как мы видим из кода, композитный валидатор ищет нужный валидатор для данной команды. Если не нашел, то используется стандартный JSR валидатор (для этого я использую hibernate-validators). Таким образом, теперь мой код сокращается и порядок действий выглядит так:
1. Ставлю аннотацию @Valid на команду.
2. Спринг вызовет композитный валидатор, а тот в свою очередь найдет нужный валидатор для данной команды и провалидирует её.
Итак, с первой задачей разобрались. Вторая поинтереснее. Для её решения был выбран Spring AOP. Напомню, что с помощью аспекта можно изменить поведение метода (более детально читайте главу по АОП в Спринг референс). Итак, решение такое:
Постараюсь объяснить. Аспект перехватывает все методы контроллеров (а есть разные виды аспектов – этот вид, лишь один из множества), которые помечены аннотацией ValidOnlyForJSON. Если команда была провалидирована успешно, то вызовется оригинальный метод контроллера, в противном случае – вернется перечень ошибок для клиента (то что мы делали в каждом методе).
Для имплементации был подключен AspectJ. Итак посмотрим, как теперь выглядит наш код:
По-моему, выглядит очень прилично. Таким образом, мы получили элегантное и готовое для переиспользования (а это самое главное) решение.
Оригинал статьи тут.
Интересная статья!Очень познавательно.
ReplyDelete