Быстрая разработка современного приложения: Spring Roo
Все мы, включая программистов, мечтаем о скатерти-самобранке: ей говоришь, что нам надо, а она делает. Скатерть в сказке работает быстро. Это само собой разумеется. И как она это делает, нам знать не нужно.
Если сказку сделать былью в современной разработке, то хотелось бы иметь возможность создавать веб-приложения, даже не зная фронтэнд. И ещё: современное приложение – это мониторинг, безопасность, логирование, полнотекстовой поиск и многое ещё – сто одёжек с застежками и без. А собственно бизнес-логики в приложении зачастую – совсем не много. Львиную долю времени разработчика сжирает всё остальное. И хочется, чтобы и тут нам наша скатерть помогла.
Подобные программы (по-английски – Rapid Application Development) делались, делаются и будут делаться. Не избежал своей попытки и стек Spring. Называется программа – Spring Roo. Появился Spring Roo 10 лет назад и первое время активно развивался. Выходили книги – н-р, «Spring Roo in Action». Но потом разработчики Pivotal решили сконцентрироваться на Spring Boot, который стал сверхуспешным и вдохнул в Spring новую жизнь. А разработку Spring Roo полностью отдали на откуп испанской фирме DISID. С тех пор проект развивается неспешно. Вышла вторая версия, несовместимая с первой. В ней появились Spring Boot и Thymleaf с Freemarker, но и пропали некоторые фишки первой версии вроде возможности автоматического создания классов и их связей по schema.sql.
У Spring Roo на гитхабе – 632 звезды (для сравнения, у идейного наследника Spring Roo – JHipster – 13 494). Примеров его сопряжения с различными иными технологиями не слишком много. Да и вопросов и ответов по Spring Roo не накоплено в достаточном количестве.
С другой стороны, Spring Roo – это по-прежнему очень мощный и полезный инструмент. Особенно для создания CRUD-приложений или CRUD-частей сложных приложений (отдельный user management, например).
Spring Roo создаёт удобный и многофункциональный пользовательский интерфейс с поиском «из коробки». Разработка осуществляется чрезвычайно быстро. И кто знает – возможно, Spring Roo получит новое развитие и популярность. И может быть, этому в будущем поспособствуете именно вы.
Как пользоваться Spring Roo?
А пока давайте рассмотрим, как им пользоваться. В этом нет никакой сложности. Для начала вы скачиваете по адресу https://projects.spring.io/spring-roo/ zip-file (http://spring-roo-repository.springsource.org.s3.amazonaws.com/release/ROO/spring-roo-2.0.0.RELEASE.zip), распаковываете содержимое в произвольный каталог – вот и вся инсталляция.
Остаётся только прописать путь к программе в системной переменной Path. Например: C:\Program Files\spring-roo-2.0.0.RELEASE\bin;
Теперь можно создать папку для будущей программы, которую для нас разработает Spring Roo, и запустить Spring Roo оттуда в командной строке командой roo. На экране мы увидим нечто подобное:
_ ___ _ __ _ __(_)_ __ __ _ _ __ ___ ___ / __| '_ \| '__| | '_ \ / _` | | '__/ _ \ / _ \ \__ \ |_) | | | | | | | (_| | | | | (_) | (_) | |___/ .__/|_| |_|_| |_|\__, | |_| \___/ \___/ |_| |___/ 2.0.0.RC1 Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
Всё. Теперь мы уже внутри Roo и из командной строки может запускать его команды. К примеру, help или hint.
roo> hint Roo requires the installation of a persistence configuration. Type 'jpa setup' and then hit CTRL+SPACE. We suggest you type 'H' then CTRL+SPACE to complete "HIBERNATE". After the --provider, press CTRL+SPACE for database choices. For testing purposes, type (or CTRL+SPACE) HYPERSONIC_IN_MEMORY. If you press CTRL+SPACE again, you'll see there are no more options. As such, you're ready to press ENTER to execute the command. Once JPA is installed, type 'hint' and ENTER for the next suggestion. roo>
Подсказки Roo выдаёт в зависимости от контекста. А ещё, если нажимать клавишу Tab, Roo сам предложит доступную команду, опцию или имя скрипта, а также автоматически дополнит введённое вами.
Особенности работы со Spring Roo
Работа со Spring Roo представляет собой последовательный ввод команд, каждая из которых создаёт проект, классы, связи между полями этих классов, репозитории, сервисы, контроллеры, тесты и так далее и тому подобное.
Вместо того, чтобы по очереди вводить команды, имеет смысл просто записать их все в один текстовый файл, а потом командой script исполнить их все сразу. С учётом того, что все введённые нами команды Roo записывает в log-файл, создание скрипта обычно представляет собой копирование и творческое редактирование этого самого лога.
Соответственно, если вы в какой-то из команд совершили ошибку и хотите исправить получившийся результат, вы можете не только повторно ввести команду с опцией
Вы также можете параллельно с командной строкой открыть генерируемый Roo код в вашей IDE. STS поддерживает Spring Roo с помощью соответствующего плагина, в нём вам не нужен отдельный shell. IDEA поддерживала Roo с версии 11 по 15. Но плагин совершенно не обязателен. Совершённые вами в IDE изменения автоматически подхватятся Roo в shell и отразятся там.
Под капотом у Spring Roo – AspectJ. И значительная часть кода содержится в .ITD-файлах (AspectJ inter-type declaration). С помощью команды
Подробнее о командах и опциях Spring Roo вы можете прочитать здесь.
Создаём онлайн-магазин
Давайте мы уже, наконец, рассмотрим пример. Создадим онлайн-магазин (для создания скрипта под запуск просто уберите из текста ниже все комментарии):
// Create project project setup --topLevelPackage com.disid.restful --projectName restfulshop // Setup JPA jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY // Create entities without relations // Address entity jpa --class ~.model.Address field string --fieldName street field string --fieldName city field number --fieldName streetNumber --type Integer --min 1 // Category entity jpa --class ~.model.Category --entityFormatMessage category_format field string --fieldName name --sizeMin 3 --sizeMax 30 field string --fieldName description // Customer entity jpa --class ~.model.Customer --entityFormatExpression "#{firstName} #{lastName}" field string --fieldName firstName field string --fieldName lastName // Product entity jpa --class ~.model.Product --entityFormatExpression #{name} field string --fieldName name field string --fieldName description // CustomerOrder entity jpa --class ~.model.CustomerOrder --entityFormatExpression #{shipAddress} field date --fieldName orderDate --type java.util.Date --dateTimeFormatPattern "dd/MM/yyyy" field date --fieldName shippedDate --type java.util.Date --dateTimeFormatPattern "dd/MM/yyyy" field string --fieldName shipAddress // OrderDetailPK //embeddable --class ~.model.OrderDetailPK --serializable //field number --fieldName id --type Integer //field number --fieldName customerOrderId --type Long --column customerOrderId // OrderDetail //entity jpa --class ~.model.OrderDetail --identifierType ~.model.OrderDetailPK entity jpa --class ~.model.OrderDetail field number --fieldName quantity --type Integer // Customer relations focus --class ~.model.Customer field reference --fieldName address --type ~.model.Address --aggregation false --joinColumnName my_customer field set --fieldName orders --type ~.model.CustomerOrder --joinTable my_customer_orders --joinColumns my_order --referencedColumns id --inverseJoinColumns my_customer --inverseReferencedColumns id // Category relations focus --class ~.model.Category field set --fieldName products --type ~.model.Product --cardinality MANY_TO_MANY --aggregation --joinTable my_products_categories --joinColumns my_product --referencedColumns id --inverseJoinColumns my_category --inverseReferencedColumns id // CostumerOrder relations focus --class ~.model.CustomerOrder field set --fieldName details --type ~.model.OrderDetail --cardinality ONE_TO_MANY --aggregation false // Product relations focus --class ~.model.Product field set --fieldName orderDetails --type ~.model.OrderDetail // Generate repositories repository jpa --all // Generate service layer service --all // Generate finders dto --class ~.model.CustomerFindByFirstNameAndLastName field string --fieldName firstName field string --fieldName lastName finder add --entity ~.model.Customer --name findByFirstNameAndLastName --formBean ~.model.CustomerFindByFirstNameAndLastName // Generate web layer web mvc setup web mvc language --code es web mvc controller --all web mvc view setup --type THYMELEAF web mvc controller --all --responseType THYMELEAF // Publishing finders in web layer web mvc finder --entity ~.model.Customer web mvc finder --entity ~.model.Customer --responseType THYMELEAF // detail OneToMany aggregation web mvc detail --entity ~.model.Customer --field orders web mvc detail --entity ~.model.Customer --field orders --responseType THYMELEAF --views list,findByFirstNameAndLastName // detail ManyToMany aggregation web mvc detail --entity ~.model.Category --field products web mvc detail --entity ~.model.Category --field products --responseType THYMELEAF // detail OneToMany composition web mvc detail --entity ~.model.CustomerOrder --field details web mvc detail --entity ~.model.CustomerOrder --field details --responseType THYMELEAF // Unit tests test unit --class ~.model.Product test unit --class ~.model.CustomerOrder test unit --class ~.model.Address // Integration tests test integration --class ~.repository.CustomerRepository test integration --class ~.repository.CategoryRepository test integration --class ~.web.CustomerOrdersCollectionThymeleafController test integration --class ~.web.CustomerOrdersCollectionJsonController
После того, как скрипт выше отработал (и Spring Roo создал весь необходимый код), можно выйти из Roo (команда
Остаётся открыть магазин в браузере: http://localhost:8080/
Ниже – несколько скриншотов магазина.
Остаётся пожелать вам успешной работы со Spring Roo. И не забудьте поделиться с другими вашими достижениями на этой ниве!