Быстрая разработка и развертывание приложения инвентаризации хранилища медицинских/биологических лабораторий в виде адаптивного одностраничного приложения (SPA).
…используя AngularJS/Restful Services/MongoDB.
Здравствуйте, я опытный инженер-программист/разработчик веб-приложений, который занимается разработкой с использованием устаревших фреймворков, включая JSP, технологии просмотра JSF (недавно Spring Thymeleaf) с Spring MVC, сервисы Rest, реляционные базы данных для сохранения данных и многое другое. В начале года, в прошлом году, я решил, что пришло время немного запачкать руки одним из новых фреймворков javascript (AngularJS), с которым я играл, но никогда не работал над веб-приложением на работе, которая требовала его использование. Я также хотел заново привыкнуть к использованию хранилищ данных NoSQL, а именно Mongodb. Я работал с Mongodb два года назад в инженерной стартап-компании, поэтому знаком с ней. Кроме того, кажется, что это популярный выбор по многим причинам, которые я не буду сейчас углублять в этом блоге.
Итак, вот и начинается мой путь по этой дороге. Ранее в этом году я исследовал инструмент быстрой разработки приложений (RAD), в котором был пример проекта, включающего AngularJS. Я обнаружил, что в среде разработки JBOSS Studio Developer IDE, которой я недавно пользовался, есть инструмент RAD под названием «Forge». Он содержит пример проекта, который обеспечивает мгновенную интеграцию всего вышеперечисленного, за исключением настройки ORM-фреймворка (Hibernate), которую необходимо было сделать. Я также отметил, что Spring Data может обеспечить взаимодействие NoSql с приложением. Увидев примеры их аннотаций «@Document» и «@Collection», используемых в классах Entity, я убедился, что их фреймворки были настроены для взаимодействия с самой природой Mongodb, являющейся хранилищем данных на основе документов. Поэтому я решил попробовать оба подхода. Итак, я поведу вас по этому пути, позволяющему Mongodb хорошо работать с остальной частью приложения, начиная с JBOSS Forge.
Инструменты JBOSS Developer Studio Forge с использованием сервера приложений Wildfly
Сначала я установил Mongodb, что представляет собой простой процесс, и отредактировал файл persistence.xml, включив в него необходимые свойства хранилища данных (имя базы данных, хост, порт, имя пользователя, пароль). После онлайн-исследований следующим шагом было получение зависимостей для HibernateOGM, которые позволяют приложению взаимодействовать с Mongodb и другими хранилищами данных NoSql. Я мог бы упомянуть, что я решил развернуть это приложение в Wildfly, которое является следующей бета-версией платформы корпоративных приложений JBOSS (EAP). Причина в том, что WildFly, основанный на JEE7, демонстрирует передовые характеристики и функции, которые, по-видимому, необходимы для моего проекта.
Итак, моим следующим шагом было создание файла конфигурации с именем « jboss-deployment-structure.xml », который нужно поместить в каталог «WEB-INF» со следующим содержимым:
<boss-deployment-structure> <deployment> <dependencies> <module name=”org.hibernate” slot=”ogm” services=”export” /> <module name=”org.hibernate.ogm.mongodb” slot=”main” services=”export” /> </dependencies> </deployment> </jboss-deployment-structure>
Затем мне нужно было добавить модули Hibernate OGM в правильный каталог сервера приложений. Поэтому я загрузил этот zip-файл и извлек только каталог ogm, который находится вне каталога org.hibernate. Я распаковал в следующий каталог: wildfly-8.2.0.Final\modules\system\layers\base\org\hibernate. Затем я изменил строку в файле persistence.xml:
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
Следующим шагом я использую аннотацию «Entity» Hibernate в классе модели, поэтому необходимо включить ссылку на нее в файл persistence.xml, пример ниже. Также удалите ссылку на источник данных в этом файле:
{removed:] <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> … </properties> <class>package com.xstreamus.model.Labsample</class> </persistence-unit> …
Затем измените спецификацию разрешенных символов в методах Rest Service: (Пример: для моего метода GET…)
@Path(“/{id:[0–9][0–9]*}”) ...becomes: @Path(“/{id:[0–9,a-z][0–9,a-z,\\-]*}”) ...due to the fact that Id is now a string.
Последним шагом было убедиться, что все мои столбцы, определенные в моем классе сущностей, были определены как строки, связанные с соответствующей аннотацией, когда это необходимо, для нестроковых полей (например: @Digits(fraction = 0, integer = 12) to представлять номер телефона). Кроме того, из-за различий между реляционными базами данных и базами данных на основе документов (или типа ключ/значение) поле id было изменено, как показано ниже:
Was: private static final long serialVersionUID = 1L; private Long id; Now: @Id @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") private String id;
Исходя из исключений, возникших в результате запуска приложения на этом этапе, потребовался еще один шаг. Эта стратегия требовала создания нового UUID вручную и… «Эй, это работает!»
В этот момент мое любопытство к решению Spring взяло верх надо мной. Можно ли сделать столько же шагов, чтобы добраться до этой точки с предложениями Spring? Пришло время узнать…
Spring STS с использованием Spring Boot, Spring Data с использованием встроенного сервера Tomcat
Как я упоминал ранее в этом блоге, я использовал Spring Boot в рабочем проекте, который произвел на меня очень сильное впечатление тем, как быстро я смог развернуть веб-приложение с помощью этого инструмента. Я надеялся получить столь же приятный исход этого испытания. Ну, я должен сказать, что у меня было приложение (уже определенное в предыдущем проекте), использующее AngularJS, использующее API Restful Service, работающее в течение 20 минут, при этом все операции CRUD работают с Mongodb. Проблемы с генерацией идентификатора уже учтены Spring Data, я был в пути. Я мог фактически разработать свое приложение со всей инфраструктурой мгновенно. Мы все чувствовали тот прилив волнения, когда мы делаем правильный поворот в поездке после того, как «заблудились», что возвращает нас на правильный путь. Это то чувство, которое я испытал, когда, не веря своим глазам, оно просто заработало без подстройки! Ниже приводится краткий отчет об этом путешествии:
Я создал проект Spring Boot, выбрав все компоненты, которые я искал (интеграция с Mongodb и т. д.). Я установил плагин AngularJS eclipse и портировал свой код AngularJS, репозитории Spring, контроллеры, остальные API из предыдущего проекта. Я использовал те же параметры подключения к базе данных.
Говоря об остальных API, я автоматически использую RestComtrollers и Jackson (поскольку они находятся в пути к классам, Spring выбирает их автоматически), выполняя автоматическое преобразование объектов в JSON с помощью Springl MappingJackson2HttpMessageConverter. Кроме того, поскольку я сохраняю данные в хранилище данных Mongodb, все данные хранятся в формате JSON, представленном как BSON (двоичный). Spring Data делает этот процесс прозрачным.
Затем я добавил еще несколько полей ввода в представление, стараясь указать типы ввода как «даты» для полей даты и «текст» для текстовых полей. Я добавил каждое соответствующее свойство в класс Java модели.
Я включил проверку входных данных для двух полей, одно из которых представляет «описание/примечания», а другое — «название образца». Остальное могу добавить позже. Я изменил входные теги и добавил условное отображение сообщений об ошибках. Они должны отображаться только после того, как с формой взаимодействовали (грязные) и данный ввод в поле недействителен. Фрагмент ниже используется для первого поля, которое является обязательным:
<div class="col-md-12"> <input id="title" name="title" type="text" class="form-control input-text" placeholder="Enter Description/Notes about your sample" ng-model="formData.sampdescription" autofocus required/> </div> <div ng-show="labSampleForm.$dirty && labsampForm.sampdescription.$invalid"> <span style='color:red;text-align:left' ng-show='labsampForm.sampdescription.$error.required'> Enter required field </span> </div>
Ниже заботится о втором поле. Это не только обязательное поле, но и введенный текст проверяется на соответствие правилу шаблона, указанному в ng-контроллере, на которое ссылается ниже «shelfNameFormat»:
<input type="text" class="form-control input-text" id="shelfName" name="shelfName" placeholder="Shelf Id" ng-model="formData.shelfName" required ng-pattern="shelfNameFormat"/> <div ng-show="labsampForm.$dirty && labsampForm.shelfName.$invalid"> <span style="color:red;text-align:left" ng- show='labsampForm.shelfName.$error.required'>Enter required field </span> </div> <div ng-show='labsampForm.$dirty && labsampForm.shelfName.$error.pattern'> <span style="color:red;text-align:left" ng-show='labsampForm.shelfName.$error.pattern'>Enter required format: sh-[alphanumeric chars]-[numerals] </span> </div>
Строка ниже была добавлена в регулярное выражение ng-controller, чтобы гарантировать, что пользователь вводит «sh-», за которым следует любое количество буквенно-цифровых символов. За этим следует тире («-»), затем любое количество цифр:
$scope.shelfNameFormat = /sh+\-[a-zA-Z0-9]+\-[0-9]/;
Я мог бы упомянуть, что при запуске приложения в качестве приложения Spring Boot Spring Data обеспечил автоматическое создание моих объектов mongo в соответствующей коллекции в хранилище данных mongodb. Теперь, когда он запущен и работает, я могу показать ниже изображения проверки в действии. На первом снимке экрана показаны проверки при нажатии кнопки «Добавить» без ввода данных в форму:
На приведенном ниже снимке экрана показано, когда для «sampleName» вводится неправильный «шаблон» данных.
Как видите, в приложение добавлен ряд «записей» или документов. После ввода документы можно удалить или отредактировать, щелкнув значок «X» в кружке или значок карандаша, соответственно, справа от описания/примечаний. Это приводит к раскрывающемуся аккордеону со всеми редактируемыми полями:
Дополнительной функцией является флажок слева от каждого документа. Когда пользователь завершил всю работу с данным образцом, он может отметить это поле. При любом последующем использовании приложения эти проверенные записи будут выделены серым цветом, как напоминание о том, что они завершены. Однако их по-прежнему можно редактировать на случай, если в будущем потребуются обновления.
Мне пришлось изменить теги ввода для полей даты. Ниже приведено соглашение, которое я использовал (пример для ‘finishDate), чтобы получить правильное форматирование для обработки angular:
<input type="date" class="form-control input-date" id="finishdate"value="{{formData.finishDate | date: 'yyyy-MM-dd'}}"placeholder="Test End Date" ng-model="formData.finishDate">
Ниже приведен скриншот добавленной «записи», готовой к редактированию:
Данные сохраняются, как показано в сеансе RoboMongo (инструмент, который я выбрал для взаимодействия с базой данных, это довольно приятно!):
Данные редактируются ниже, будучи одним из полей даты, с выбором даты:
Результирующие изменения теперь отражаются в хранилище данных:
Вот и все! Таким образом, конечный результат — это начало отзывчивого веб-/мобильного приложения с сенсорным экраном, которое относится к хранению образцов медицинских/биологических лабораторий и отслеживанию запасов. Кроме того, приложение с полной возможностью CRUD с хранилищем данных документов, в котором коллекции содержат разные документы, реализовано с хранилищем данных Mongodb.
Пример кода
Исходники рабочего примера этого проекта можно найти на GitHub здесь.
Об авторе:
Опытный инженер-программист, включая разработку веб-приложений с полным стеком, не ограничиваясь технологиями и платформами Java, но с большим опытом. Кроме того, 4 года работы с Интернетом вещей (IoT), в частности, с системами отслеживания активов с RFID-метками с использованием современных антенных систем.
Не стесняйтесь отвечать ниже. Как говорится, обратная связь является ключом к стабильной системе.