В статье Использование IndexedDB в веб-браузере - все на Java г-жа Гвитани и доктор Джекл рассказали нам, как мы можем использовать Java с Elemental2 для создания простого прототип на основе WebAPI для IndexedDB. На этот раз они покажут нам, как создать уже показанный код, чтобы его можно было тестировать и поддерживать со всеми шаблонами дизайна, которые мы уже знаем из наших серверный опыт работы с Java.
В мире серверной Java мы все время используем следующие шаблоны, поэтому мы хотим использовать их и в приложениях веб-браузера:
- Внедрение зависимостей: мы внедряем зависимый объект в основной объект, чтобы мы могли легко смоделировать внедренный объект, чтобы иметь возможность протестировать основной объект в простом модульном тесте. Это очень полезно, особенно если зависимый объект использует, например, база данных, которая не может быть загружена очень быстро.
- Шаблон службы и репозитория: мы создаем службы, и эти службы обращаются к репозиториям данных, чтобы иметь возможность вызывать операции с базой данных.
- Расширенная модель домена: мы не хотим строить анемичную модель предметной области, содержащую только данные, вместо этого мы также хотим иметь некоторую логику в ней, которая называется моделью богатой предметной области.
- Шаблон Строителя: мы строим наш объект шаг за шагом, используя правильную последовательность действий, чтобы иметь возможность управлять созданием этого объекта.
- Мок-тест: как упоминалось ранее, очень важно иметь возможность имитировать поведение зависимых объектов, чтобы вам не нужно было использовать настоящую базу данных для своего модульного теста.
Урок 1: чтобы создать поддерживаемое и расширяемое приложение веб-браузера, вам необходимо использовать известные шаблоны проектирования, которые вы уже узнали из серверной Java.
Чтобы показать, как мы можем использовать шаблоны, миссис Гвитани создала небольшой пример indexeddb-element2-dagger2-example на основе IndexedDB, который мы видели в прошлой статье. . В примере используются следующие библиотеки и фреймворки:
- Внедрение зависимостей: Dagger2 разработан, чтобы быть гибким и использует полностью статический генератор времени компиляции для Java, Kotlin и Android.
- Шаблон службы и репозитория: нет специальной структуры для службы, а для шаблона репозитория мы используем общий шаблон репозитория, который разработан на основе этого класса: Repository.java
- Модель Rich Domain: никакой специальной структуры, у нас просто есть вычисляемое свойство getCalculatedPriceWithAmount в нашем классе Product.java
- Builder Pattern: некоторые возможности используются с использованием фреймворков Project Lombok, AutoValue и Immutables. На этот раз мы просто создаем шаблон Builder вручную, но в следующий раз мы попробуем использовать неизменяемые элементы для этого шаблона.
- Mock Test: для этого мы используем JUnit 5 и Mockito (см. pom.xml)
Итак, давайте углубимся в пример проекта!
Структура проекта Maven
Прежде чем мы подробно рассмотрим проект, давайте посмотрим на структуру проекта Maven на Eclipse STS 4 ниже.
В проекте, основанном на Maven и Mrs. Gwitany, используется GWT Boot для упрощения pom.xml. Зависимости GWT Boot Starter - это, по сути, простая коллекция зависимостей Starter для GWT, как и зависимости Spring Boot Starter. Идея взята из Spring Boot Starters. Вот важная часть pom.xml, которая основана на зависимостях GWT Boot Starter:
Миссис Гвитани использует две зависимости Starter:
- gwt-boot-starter-dagger2: зависимости от Dagger2. Все зависимости GWT включены как транзитивные зависимости.
- gwt-boot-starter-elemento-core: зависимости от Elemento. Эта библиотека значительно упрощает работу с Elemental2.
Другие зависимости, такие как element2-indexeddb, могут быть добавлены независимо. Также не забудьте добавить необходимые модули в определение модуля GWT: module.gwt.xml.
GWT Boot использует GWT Maven Plugin, и его нужно настроить, как показано ниже:
С этим pom.xml вы готовы к работе. Дополнительную информацию о том, как настроить проект Maven с загрузкой GWT, см. В разделе Примеры загрузки GWT.
Урок 2: используйте модули GWT Boot Starter, чтобы упростить управление вашим pom.xml. Нет необходимости копировать и вставлять зависимости с соответствующими версиями.
Основной метод == Точка входа
В GWT ваше приложение начинается с загрузки кода в Entry Point. Таким образом, это сопоставимо с основным методом Java. В этой точке входа мы просто инициализируем структуру Dagger2 с помощью корневого представления / компонента пользовательского интерфейса ProductComposite.
Какая точка входа должна быть вызвана, должна быть определена в файле определения модуля GWT: module.gwt.xml.
DI: Dagger2
Если вы знаете Spring Boot с его аннотациями Dependency Injection (DI), то использовать Dagger2 несложно. В приведенной ниже таблице показано сходство между аннотациями Spring Boot и Dagger2 DI.
Следующие модули и компоненты должны быть реализованы пользователем Dagger2:
- AppModule: в этом модуле мы не определяем создание каких-либо объектов, потому что мы используем @Singleton для каждого класса, которым управляет Dagger2.
- AppComponent: в этом компоненте мы определяем точку входа для класса ProductComposite. Класс ProductComposite является представлением корневого компонента / пользовательским интерфейсом домена Product.
После запуска mvn compile Dagger2 сгенерирует несколько файлов Java для управления внедрением зависимостей за вас. Dagger2 использует генератор кода для создания фабрик, и это также большая разница с Spring Boot, который в основном использует динамические прокси и отражения. В мире JavaScript у нас нет Reflection API, поэтому генератор кода - вот решение.
Как мы могли бы потом использовать структуру DI? Так же просто, как этот пример ниже. Класс ProductService использует внедрение конструктора для внедрения двух других классов ProductIdbRepository и ProductRandomCreator, которые могут будет использоваться позже в методе createProduct.
Шаблон службы и репозитория
Для шаблона репозитория мы могли бы определить общий интерфейс, например Репозиторий.
ProductIdbRepository реализует интерфейс для операций IndexedDB, который состоит из сущности Product. Реализация IndexedDB довольно проста. В этом примере миссис Гвитани реализовала только метод persist. Остальное вы можете реализовать. ProductRandomCreator - это класс, в котором мы создаем некоторые продукты, поскольку у нас нет возможности создавать продукты из пользовательского интерфейса.
Оба класса будут внедрены в ProductService в его конструкторе, как мы видели выше.
На следующей диаграмме классов показана структура модели предметной области.
- ProductService ‹‹Service››: служит для создания продуктов и будет использоваться непосредственно из пользовательского интерфейса ProductComposite.
- ProductRandomCreator ‹‹Service››: создает некоторые продукты случайным образом.
- ProductIdbRepository ‹‹Repository››: предлагает операции CRUD (создание, чтение, обновление, удаление) для базы данных веб-браузера IndexedDB.
- Продукт ‹‹Entity››: это объект, который должен создаваться и управляться репозиторием.
Сущность: богатая и анемичная модель домена и шаблон построителя
Как мы видели выше, Продукт - это сущность в модели предметной области. Миссис Гвитани сделала сущность Product многофункциональной, поскольку она также вычисляет цену с заданной суммой в методе под названием getCalculatedPriceWithAmount . Она также создает Builder Pattern, чтобы иметь возможность красиво создать экземпляр продукта. Итак, вот как мы могли бы создать сущность Product с помощью паттерна Builder:
Product product = new Product.Builder(key, "Lofi " + key).setType(type).setAmount(10) .setPrice(price) .build();
Ниже приведен код сущности Продукт, в которой также реализован шаблон Builder.
Урок 3: Внедрение зависимостей, Сервис, Репозиторий, Сущность и Строитель можно также использовать в веб-браузере с Java и GWT / J2CL. Помните, что у нас есть шаблоны дизайна, потому что мы узнали, что они помогают нам структурировать наше приложение, чтобы его было легче поддерживать и расширять.
Пользовательский интерфейс Composite
После того, как у нас есть модель предметной области, нам просто понадобится представление / пользовательский интерфейс. Для этого миссис Гвитани создала класс ProductComposite. Ему требуется ProductService, поэтому он вводится в ProductComposite. Метод renderView строит дерево HTML DOM с помощью библиотеки Elemento. Пользовательский интерфейс очень прост, поэтому мы можем сосредоточиться на основах. Обработчик события onProductCreated будет вызываться каждый раз, когда пользователь нажимает кнопку. У него есть некоторая логика представления, которая управляет созданием поля ввода или простым входом в консоль.
Миссис Гвитани и доктор Джекл подробно займутся разработкой пользовательского интерфейса позже в другой статье, потому что GWT / J2CL предлагает множество инфраструктур пользовательского интерфейса, по количеству почти сопоставимых с JavaScript и старым миром Java.
Пробный тест
И последнее, но не менее важное: на самом деле это очень важная часть, о которой мне рассказали миссис Гвитани и доктор Джекл. В Java вы можете использовать свои хорошо известные тестовые среды, такие как JUnit и Mockito. В этих двух классах модульных тестов вы можете найти несколько интересных тестов:
- ProductCompositeTest: этот класс тестирует класс пользовательского интерфейса ProductComposite. Он использует Mockito и проверяет поведение обработчика событий onProductCreated, который показан ниже. Чтобы иметь возможность протестировать логику представления, вам необходимо отделить метод отрисовки от логики, чтобы вы могли частично смоделировать класс с помощью spy.
- ProductServiceTest: этот класс проверяет бизнес-логику класса обслуживания.
Результат
Как выглядит веб-приложение? Просто перейдите в каталог проекта Maven indexeddb-element2-dagger2-example и выполните следующую команду:
mvn gwt:generate-module gwt:devmode
Вы увидите следующее приложение Swing, и вы можете скопировать и вставить адрес веб-браузера или просто нажать кнопку, чтобы запустить браузер по умолчанию в вашей системе.
Следующее веб-приложение может быть протестировано впоследствии. Вы также можете взглянуть на средство просмотра IndexDB на вкладке Приложение в Google Chrome.
Примечание 1. приложение для веб-браузера протестировано только с Chrome и Firefox. В Firefox вы не могли использовать частный режим для запуска IndexedDB.
Примечание 2: приложение работает с Java 8 или Java 11, поскольку GWT 2.9 поддерживает Java 11, но не забывайте, что результатом вашего приложения всегда будет JavaScript приложение.
Эпилог
В этой статье миссис Гвитани и доктор Джекл показали нам, как создать тестируемое и поддерживаемое приложение веб-браузера на основе Java . Вы можете использовать все шаблоны проектирования, которые вы узнали из серверной Java, в своем клиентском веб-браузере в Java-приложении. В эпоху облачных вычислений это того стоит проявить смелость, чтобы перенести логику вашего бизнеса с серверной на клиентскую. Благодаря загрузке на стороне клиента вы сэкономите на вычислительных затратах вашего поставщика облачных вычислений. PWA (прогрессивные веб-приложения) и приложения для веб-браузера с Java просты и благодаря GWT и J2CL (транспилятору Java2JavaScript) управляемы и расширяемы, как и их аналог на стороне сервера. Сегодня они готовы к производству.
В следующей статье миссис Гвитани и доктор Джекл покажут нам, как использовать некоторые красивые фреймворки пользовательского интерфейса со всеми этими причудливыми дизайнами, такими как Material Design и Bootstrap . Также как получить доступ к API REST Spring Boot на стороне сервера, чтобы показать, как повторно использовать коды для клиента и сервера. А пока наслаждайтесь чтением и не забудьте поиграть с GWT и J2CL!
Все примеры можно найти по адресу:
https://github.com/lofidewanto/jsinterop-simple-jsframework-example/tree/master/indexeddb-elemental2-dagger2-example
Padlet для современного программирования GWT / J2CL:
https://bit.ly/GWTIntroPadlet