Чтение требований для еще одного веб-проекта для внутреннего корпоративного использования, который вы (по крайней мере, я) обычно видите довольно общий набор: четко определенная структура хранения данных (или иногда это существующая устаревшая БД), множество форм для ввода данных, довольно сложный бизнес логика, отчетность и интеграция с множеством существующих корпоративных систем от учета до управления поставками, тысячи одновременных пользователей. Каковы ваши первые мысли?
«Хорошо, я возьму хорошо известную RDBMS, Hibernate / JPA + Spring Boot, добавлю REST API и использую мою любимую / новейшую среду JS для реализации UI».
«Ах. И мне нужно настроить Spring Security. И, возможно, добавить собственный код для защиты данных на уровне строк. Как я буду это реализовывать? Вероятно, представления базы данных или виртуальная частная база данных ».
«И все эти DAO — они похожи и скучны, но я должен их реализовать».
«И используйте что-то вроде ModelMapper для преобразования сущностей JPA в DTO для REST».
«И не забудьте рассказать Джону — нашему новому стажеру — о ленивой загрузке и присоединении JPA».
«О, боже, могу ли я избавиться от всех этих рутинных вещей и сосредоточиться на критической части реализации бизнес-логики вместо реализации еще одной формы входа и преобразования Entity-to-DTO?»
Эта статья предназначена для разработчиков, которые реализовали хотя бы пару проектов с нуля, используя среду Spring (включая Spring Boot), и теперь думают об увеличении своей производительности. В этой статье я покажу вам, как избавиться от очень распространенных рутинных задач убийства времени с помощью платформы CUBA.
Опять еще один фреймворк?
Вопрос номер один от разработчиков, когда они слышат о новой платформе: «Зачем мне это нужно, когда я могу взять Spring Boot и реализовать все с нуля, как раньше?». Что ж, достаточно справедливо — новая платформа требует изучения новых принципов и работы с новыми ограничениями, оставляя позади все годы вашего опыта. Даже если ваша текущая структура не блестящая, вы знаете все это, вы знаете все подводные камни и обходные пути для них.
Но что, если я скажу вам, что CUBA не требует разворота (или даже поворота на прямой угол) от традиционного Spring-пути развития, а лишь небольшого шага в сторону, который позволяет устранить шаблонный шум в виде сотен линий DTO и утилиты преобразования, реализация компонентов разбивки на страницы или фильтрации данных, создание файлов конфигурации для Spring Security (JPA, Cache, … вы называете это).
Мы начнем с самого начала, а затем покажем, что разработка приложений CUBA следует модели, которая используется практически для всех приложений на основе Spring, позволит вам использовать все свои навыки Spring кунг-фу, которые вы приобрели в карьере разработчика, и получить больше на конец. Статья посвящена внутреннему коду, чтобы сделать нашу историю меньше и более краткой.
Spring Application Architecture
Типичная архитектура приложения Spring может быть легко найдена, и в 90% случаев она может быть представлена как трехслойное приложение с несколькими сквозными областями. Давайте посмотрим на «классическое» приложение Spring.
Модель предметной области — обычно создается вручную. Однако есть несколько инструментов для создания модели предметной области на основе структуры хранилища данных.
Repository Layer — классы, которые работают с хранилищем данных. Также известный как «DAO», «Хранилища» и т. Д. Вот где правят все эти структуры ORM (и их братья и сестры). Обычно он содержит классы, которые выполняют операции CRUD, используя только один класс сущностей из модели предметной области.
Сервисный уровень — иногда разработчики создают дополнительный уровень для разделения бизнес-логики и операций CRUD с данными. Этот уровень полезен, если у вас сложная бизнес-логика, включающая разные типы источников данных, интеграцию внешних служб и т. Д.
Web / Controllers Layer (REST / MVC) — набор классов, которые работают либо с REST API (которые будут использоваться браузерными приложениями), либо с представлениями, реализованными с использованием JSP, шаблонных структур (thymeleaf, speed) или JVM-структур (GWT, Ваадин, Калитка и др.). Обычно контроллеры манипулируют DTO, а не объектными объектами, из-за структуры API или представления в представлениях. Поэтому разработчикам часто приходится реализовывать двунаправленное преобразование между моделью сущностей и моделью DTO.
Справочное приложение — Pet Clinic
Они говорят: «Слова дешевы, покажи мне свой код». Spring имеет свое известное «эталонное» приложение — Pet Clinic, которое доступно на GitHub . Ниже мы покажем, как ваши навыки Spring Developer могут быть использованы при разработке бэкенда для нового форка Pet Clinic — теперь с CUBA. Здесь очень хорошее и подробное описание эталонной заявки от Антуана Рей; мы повторим некоторые части в этой статье.
Модель данных
ER схема базы данных показана на схеме. Фактическая модель предметной области в коде приложения немного сложнее и включает в себя некоторое наследование, вы можете найти UML в презентации, упомянутой выше.
Уровень хранилища
Существует четыре репозитория для работы с основными объектами: Владелец, Домашнее животное, Визит и Ветеринар. Эти репозитории основаны на среде Spring JPA и почти не содержат кода благодаря Spring JPA, но вы можете найти пользовательский запрос в репозитории Owner, чтобы выбрать владельцев и их питомцев в одном запросе.
Экраны пользовательского интерфейса
Приложение состоит из девяти экранов, которые позволяют нам просматривать все данные и редактировать некоторые из них: владельцы домашних животных, домашние животные и посещения. Мы не будем сейчас о них говорить, но я должен отметить, что эти экраны — это просто простые формы CRUD, которые довольно распространены для большинства приложений, ориентированных на данные.
Дополнительные возможности
Помимо простой функциональности CRUD, приложение предоставляет некоторые (не столь очевидные) функциональные возможности, которые демонстрируют всю мощь Spring Framework:
- Кэширование — список ветеринаров кэшируется, поэтому нет никаких запросов к БД при обновлении списка ветеринаров.
- Валидатор — проверяет, все ли поля заполнены при создании новой записи о питомце.
- Форматтер — для правильного отображения типа питомца.
- i18n — приложение доступно на английском и немецком языках.
- Управление транзакциями — некоторые запросы к базе данных делаются только для чтения.
Примечание стороны
Мне очень нравится эта картина, так как она отражает мои чувства со 100% точностью. Чтобы эффективно использовать любой фреймворк, нужно понимать, как он работает внутри. Например, Spring Boot скрывает от вас многое, и вы удивитесь, сколько классов находится за одной простой инициализацией интерфейса JPA. Некоторые заметки о «магии», происходящей в приложении Spring Boot Pet Clinic:
- Не существует кода конфигурации кэша, кроме аннотации @ Caсheable, но каким-то образом Spring Boot «знает», как настроить реализацию кэша (в нашем случае EhCache).
- Репозитории не помечены как @Transactional (как и их родительский класс org.springframework.data.repository.Repository), но там все методы save () работают нормально.
Но, несмотря на все эти последствия, Spring Boot — очень популярная платформа, потому что она прозрачна и предсказуема. Он имеет очень подробную документацию и открытый исходный код, поэтому вы можете прочитать, как все работает, изучить любой метод и посмотреть, что там происходит. Я предполагаю, что всем нравятся прозрачные и управляемые фреймворки — их использование делает ваше приложение легко обслуживаемым.
Pet Clinic с CUBA
Итак, давайте посмотрим на реализацию Pet Clinic с платформой CUBA, попробуем взглянуть на нее с точки зрения наших знаний о Spring и выяснить, где мы можем сэкономить некоторые усилия.
Исходный код для реализации Pet Clinic можно найти на GitHub . Кроме того, у CUBA Platform есть очень хорошая документация, и вы можете найти там почти все (большинство случаев проиллюстрировано примерами и фрагментами кода на GitHub ). В этой статье мы будем ссылаться на документацию довольно часто, чтобы избежать объяснений дважды.
Архитектура приложений CUBA
Приложение CUBA состоит из следующих модулей (см. Схему).
Глобальный — содержит объекты, сопоставленные с базой данных, представлениями CUBA и сервисными интерфейсами, которые можно использовать в других модулях.
Ядро — здесь должны быть размещены все реализации служб, которые работают с базой данных приложения и реализуют бизнес-логику. Обратите внимание, что классы Core недоступны в других модулях, это было сделано специально для обеспечения отдельного развертывания модулей Core и GUI на разных серверах для лучшей масштабируемости. Чтобы внедрить сервисы из модуля Core в другие модули, вы должны использовать интерфейсы, объявленные в модуле Global.
GUI, Web, Desktop, Portal — эти модули содержат связанные с GUI классы (контроллеры, слушатели и т. Д.), Отвечающие за обработку событий пользовательского интерфейса. Вы можете создать свои собственные контроллеры REST здесь, чтобы дополнить готовый API REST, который CUBA генерирует для вас.
Для лучшей производительности разработчика CUBA имеет Studio — симпатичный небольшой графический интерфейс для создания и регистрации сущностей, который изменит все настройки для вас, поможет с созданием заглушек кода для сервисов и имеет WYSIWYG-редактор для форм GUI.
Таким образом, приложение, основанное на платформе CUBA, состоит из двух (или более) отдельных модулей — ядра и графического интерфейса (ов), которые можно развертывать отдельно, и сквозного глобального модуля. Давайте посмотрим на модули CUBA Global и Core и их содержимое в деталях.
Глобальный модуль
Модель сущности
Модель сущностей в приложении CUBA должна быть знакома любому разработчику, который работал с JPA-совместимой платформой ORM и Spring. Это просто классы, аннотированные @Table, @Entity и т. Д. И зарегистрированные в файле persistence.xml.
В модели лица для приложения Pet Clinic вы можете повторно использовать код из версии Spring, но вам нужно помнить несколько вещей:
- CUBA вводит «пространство имен» для каждого компонента приложения, созданного на этой платформе, чтобы предотвратить конфликт имен между различными компонентами. Вот почему для каждого имени сущности есть префикс «petclinic $».
- Рекомендуется использовать аннотацию @NamePattern для сущностей, чтобы получить содержательное представление экземпляра в пользовательском интерфейсе.
Вопрос в том, что дает нам CUBA, кроме префиксов и декларируемой сущности «строкового» представления? Дополнительные функции включают в себя:
- Базовые классы, которые поддерживают функциональность генерации идентификаторов: от целочисленных идентификаторов до UUID.
- Набор полезных (но необязательных) интерфейсов:
- Versioned — для поддержки версий сущностей.
- SoftDelete — для поддержки «мягкого», то есть «логического» удаления объекта.
- Updatable — добавляет поля для регистрации обновлений объекта.
- Creatable — добавляет поля для регистрации создания сущностей.
Вы можете прочитать больше об этих интерфейсах в документации .
- Сценарии создания и обновления схемы базы данных могут быть сгенерированы CUBA Studio автоматически.
Во время разработки приложения я просто скопировал существующие модели сущностей из версии Spring и добавил упомянутые выше специфичные для CUBA функции, удалив класс BaseEntity из эталонной версии приложения.
Просмотры
Концепция «Взглядов» CUBA может сбивать с толку, но ее довольно легко объяснить. Представление — это декларативный способ указать, какие данные (атрибуты и вложенные экземпляры / коллекции) следует извлечь.
Предположим, вам нужно выбрать владельцев и их питомцев или ветеринаров с их специальностями — для отображения зависимых объектов вместе с «родительскими» данными на одном экране пользовательского интерфейса. В случае чистой реализации Spring вам нужно определить соединения JPA…
1
2
|
@Query ( "SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id" ) public Owner findById( @Param ( "id" ) int id); |
… Или определить надлежащие типы выборки EAGER / LAZY, чтобы получить зависимые коллекции для сущности в контексте транзакции.
1
2
3
4
|
@ManyToMany (fetch = FetchType.EAGER) @JoinTable (name = "vet_specialties" , joinColumns = @JoinColumn (name = "vet_id" ), inverseJoinColumns = @JoinColumn (name = "specialty_id" )) private Set specialties; |
В версии CUBA вы можете использовать EntityManager и JPQL или представления и DataManager:
1. Определите представление, которое указывает, что мы хотим извлечь:
1
2
3
4
5
6
7
|
<view class = "com.haulmont.petclinic.entity.Vet" extends = "_minimal" name= "vet-specialities-view" > <property name= "specialities" view= "_minimal" > </property> </view> |
2. Используйте компонент DataManager для получения этих данных
1
2
3
4
5
6
|
public Collection findAll() { return dataManager.load(Vet. class ) .query( "select v from cubapetclinic$Vet v" ) .view( "vet-specialities-view" ) .list(); } |
Вы можете создавать различные представления для разных задач, выбирая, какие атрибуты вы хотите получить, выбирать или не собирать коллекции и определять, насколько глубокой будет ваше дерево объектов. В блоге Марио Дэвида есть отличный пост о взглядах.
В приложении Pet Clinic мы определили шесть видов для разных случаев. Эти представления используются в основном в формах пользовательского интерфейса, и одно из них — для извлечения данных в сервисе, фрагмент кода показан выше.
Сервисные интерфейсы
Поскольку глобальный модуль является сквозным модулем приложения на основе CUBA, вы должны определить в нем интерфейсы служб, чтобы иметь возможность использовать службы в других модулях с помощью инъекций Spring. Все, что вам нужно сделать, это зарегистрировать сервисы в файле «web-spring.xml» в веб-модуле. Платформа CUBA создает прокси в модулях приложения для сериализации и десериализации прозрачных объектов с использованием этого XML-файла конфигурации Spring. Эта функция позволяет нам вызывать службы, реализованные в Core, из других модулей даже в случае распределенного развертывания с минимумом дополнительных усилий.
Таким образом, с точки зрения разработки модели Entity с помощью CUBA это все то же самое, что и в чистом Spring, но вам не нужно заботиться о генерации идентификатора и получении идентификатора объекта после вставки и не нужно создавать дополнительный код для управления версиями объекта, мягкого удаления и журнал изменений сущностей. Также вы можете сэкономить время на создании представлений вместо соединений JPA.
Основной модуль
Базовый модуль содержит реализации служб для интерфейсов, объявленных в глобальном модуле. Каждый сервис в приложении CUBA обычно аннотируется @Service, но вы можете использовать все доступные аннотации Spring для работы с bean-компонентами. Есть несколько ограничений из-за архитектуры CUBA:
- Вам нужно аннотировать свой сервис с помощью @Service, если вы хотите, чтобы он отображался в веб-модуле.
- Рекомендуется дать название вашей службе, чтобы избежать столкновения компонентов из разных надстроек.
Помимо этого, ваша кодовая база модуля Core является «чистым» Spring-приложением. Вы можете извлекать данные из хранилищ данных, вызывать сторонние веб-службы и т. Д. Так же, как раньше. Единственным существенным отличием является взаимодействие с базой данных.
Entity Manager и DataManager
Платформа использует свой собственный EntityManager, который делегирует часть своей функциональности фактическому экземпляру javax.persistence.EntityManager. EntityManager CUBA обеспечивает в основном операции с объектами низкого уровня и не поддерживает функции безопасности. В большинстве случаев рекомендуется использовать DataManager, который дает дополнительную функциональность:
- Поддержка безопасности на уровне строк и на уровне атрибутов.
- Субъект CUBA просматривает использование для извлечения данных.
- Динамические атрибуты .
Подробнее о DataManager и EntityManager вы можете найти в
документация Обратите внимание, что вам не нужно использовать эти бины непосредственно в графическом интерфейсе — есть
Источники данных для этого.
Говоря о PetClinic — я (почти) не написал много кода в модуле Core, поскольку там не было сложной бизнес-логики.
Особенности от Spring Pet Clinic на КУБЕ
В предыдущем разделе был список дополнительных функций в приложении Spring Clinic Pet Clinic, те же функции доступны в CUBA.
Кэширование
CUBA предоставляет кэши сущностей и запросов в качестве встроенных функций. Эти кэши подробно описаны в документации и должны рассматриваться в первую очередь, поскольку они поддерживают все функции платформы, такие как распределенное развертывание. В дополнение к этому вы можете включить кэширование с помощью SpringC @able и включить кэширование, как описано в документации Spring.
Validator
CUBA использует BeanValidation в качестве стандартного механизма проверки. Если встроенной проверки недостаточно, вы можете определить пользовательский код проверки . И всегда есть возможность проверить данные в пользовательском интерфейсе, определив класс Validator, как описано здесь .
Formatter
Платформа CUBA предоставляет несколько форматеров для компонентов графического интерфейса, но вы можете определить свой собственный форматер помимо стандартных форматеров. Для представления сущности по умолчанию используется аннотация @NamePattern.
I18n
Платформа CUBA поддерживает интернационализацию так же, как и другие Java-приложения: с помощью файлов message.properties, поэтому здесь нет ничего нового.
Управление транзакциями
Платформа CUBA обеспечивает следующее
варианты управления транзакциями:
- @Transactional аннотация знакомого Spring
- Постоянный интерфейс CUBA, если вам нужно детализированное управление транзакциями в некоторых сложных случаях.
Когда я разрабатывал Pet Clinic, я думал об операциях только один раз — во время разработки формы, которая позволяла редактировать владельцев, домашних животных и добавлять посещения на одном экране. Мне нужно было понять, когда совершать транзакции и обновлять пользовательский интерфейс для последовательного отображения данных.
Pet Clinic через несколько часов. В самом деле
Мне удалось создать приложение с той же функциональностью, что и в Spring Pet Pet Clinic, со «стандартным» пользовательским интерфейсом CUBA менее чем за день. Я бы не сказал, что я эксперт в CUBA (прошло всего несколько недель с тех пор, как я начал), но у меня долгая история использования Spring. Давайте посмотрим на приложение на основе CUBA с учетом архитектуры Spring:
Доменная модель — сущности в глобальном модуле. Создание модели сущности было общеизвестной рутиной. Слава классу BaseIntegerIdEntity для экономии времени на генерацию идентификатора.
Слой репозитория — мне не нужны репозитории. Даже не интерфейс. Я только что создал некоторые виды, используя графический интерфейс CUBA Studio. С этим инструментом мне не нужно было писать XML в конфигах.
Уровень сервиса — в нашем приложении у нас есть только два сервиса для экспорта ветеринаров в формате JSON и XML с кешируемым результатом. Я поставил интерфейсы для Global и реализации для Core согласно документации. Тогда это была просто «нормальная» разработка, за исключением чтения о DataManager, чтобы немного ознакомиться с его API.
Уровень контроллеров — CUBA Pet Clinic содержит только один пользовательский контроллер REST для JSON и XML-подачи в веб- модуле. Здесь нет ничего удивительного, это был просто контроллер Spring со знакомыми аннотациями.
Графический интерфейс приложения — создание «стандартных» форм CRUD с помощью CUBA Studio было простым делом.
Я не думал о передаче сущностей в веб-интерфейс и отправке форм — никаких контроллеров и репозиториев. CUBA предоставил мне подходящую сетку и компонент для фильтрации данных, поэтому больше не нужно разбирать строки запросов и суетиться с Pageable. Я потратил большую часть времени на реализацию правильного потока пользовательского интерфейса, рендеринга и применения стилей.
Мой личный опыт показан в таблице:
Легко понять и развить | Нужно читать документацию | |
юридические лица | Моделирование сущностей Сценарии создания БД Стандартные базовые классы |
Дополнительные функции для мягкого удаления и т. Д. |
Хранилища | EntityManager Просмотры |
Менеджер данных |
Сервисы | Управление бобами Управление транзакциями Безопасность и управление пользователями |
Постоянный интерфейс |
Контроллеры | Пользовательские контроллеры REST Запросить сопоставление URL |
Сервисные методы публикации |
UI | Стандартные формы | Настройка пользовательского интерфейса |
Очевидно, что приложение Pet Clinic не использует все функции CUBA, полный список можно найти на сайте, где вы увидите другие общие задачи, которые могут быть решены платформой.
Мое личное мнение — CUBA упрощает внутреннюю реализацию и отлично работает, если вы используете ее «стандартный» графический интерфейс. Даже если вам нужен модный пользовательский интерфейс, CUBA наверняка сэкономит ваше время на серверной разработке.
Так много плюсов! Как насчет минусов?
Ну, есть некоторые вещи, которые я хотел бы упомянуть в этом разделе. Эти вещи не меняют игру, однако я нашел их совершенно нежелательными на первых этапах знакомства с CUBA.
- Во вводном разделе было сказано, что платформа CUBA поставляется с собственной IDE, которая упрощает создание проектов и управление ими. Иногда переключение между Studio и вашей IDE может быть немного раздражающим, но мы сейчас перерабатываем его, поэтому Studio скоро превратится в плагин IDEA.
- В CUBA мы используем немного больше XML-файлов конфигурации, чем в типичном приложении Spring Boot, из-за большего количества сервисов, предоставляемых платформой.
- Для каждой формы пользовательского интерфейса приложения пока нет «дружественных» URL. Вы можете получить доступ к экранам напрямую с помощью экранных ссылок , но они не очень «читабельны».
- Вы должны иметь дело с DataManager CUBA и EntityManager и изучить их API, а не Spring JPA или JDBC (но все равно можете использовать их при необходимости).
- Вы достигнете наилучшей производительности при разработке с CUBA при использовании реляционных баз данных. Что касается NoSQL — CUBA работает так же, как Spring, это тот же объем работы по кодированию.
Вывод
Если у вас есть задача по внедрению приложения для внутренней сети, ориентированного на данные, которое использует СУБД в качестве хранилища данных, вы можете использовать платформу CUBA в качестве основы, потому что:
- КУБА прозрачная. Исходный код доступен, и вы можете отлаживать все.
- CUBA является гибким (до некоторого предела). Вы можете наследовать и внедрять свои собственные bean-компоненты вместо стандартных bean-компонентов CUBA, публиковать пользовательский REST API и использовать свою собственную структуру пользовательского интерфейса для взаимодействия с пользователем.
- КУБА это весна. 80% вашего внутреннего кода будет чисто Spring-приложением.
- Вы можете начать быстро. Приложение готово к использованию сразу после создания первого объекта и экрана интерфейса пользователя.
- Много рутинной работы сделано для вас.
Таким образом, используя CUBA, вы сэкономите время на рутинных задачах, чтобы по-настоящему развлечься сложными алгоритмами, связанными с бизнесом, и нетривиальными интеграциями с другими приложениями.
Опубликовано на Java Code Geeks с разрешения Андрея Беляева, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Разработка с CUBA — большой переход от Spring?
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |