Skip to content

Files

889 lines (503 loc) · 70.5 KB

existing-spring-boot-app-modification.md

File metadata and controls

889 lines (503 loc) · 70.5 KB

Amplicode для разработки Spring Boot (Security + Web + Data + Flyway + Kafka) приложения

В этом гайде мы расскажем, как сделать существующее приложение (Spring PetClinic) готовым к продакшен, переехав с H2 и инициализировать базу данных посредством стандартного механизма Spring на PostgreSQL и Flyway; как реализовать учет заработных плат сотрудников, расширив существующую модель данных и изменив пользовательский интерфейс; как подготовить приложение к разработке мобильного клиента реализовав REST эндпоинты для получения списка ветеринаров, а также списка ветеринаров с возможностью фильтрации их по специальностям; как реализовать автоматическое назначение ветеринаров новым визитам, а также как настроить оповещение сотрудников о новых визитах через интеграцию с внешним сервисом, используя Kafka.

Для того чтобы следовать лучшим практикам, все сервисы, как и наше Spring Boot приложение, мы опишем в качестве контейнеров в файле Docker Compose.

Смотреть на Youtube

Примерное время прочтения: 30 минут.

Введение

Amplicode - это набор инструментов для максимально эффективной и комфортной разработки сервисов и веб приложений на Spring Boot в IntelliJ IDEA и административного пользовательского интерфейса на React Admin в VSCode.

Amplicode предоставляет мощную поддержку фреймворка Spring для пользователей IntelliJ IDEA, включая популярные модули, такие как Spring Boot, Spring Web, Spring Data, Spring Security и другие. Также Amplicode облегчает использование связанных с экосистемой Spring технологий, таких как Liquibase и Flyway, MapStruct и Model Mapper, Lombok, Kafka и многих других.

Кроме того, Amplicode помогает в написании Docker и Docker Compose файлов, что может значительно облегчить процесс разработки и разворачивания приложения для тестирования или демонстрации. А для разработки frontend доступна поддержка React Admin на TypeScript в VSCode.

К ключевым задачам Amplicode, с которыми он успешно справляется, относятся:

  • Ускорение разработчика на всех этапах с целью повышения его эффективности
  • Снижение порога входа в поддерживаемые технологии для новичков
  • Углубление познаний разработчиков в области corner/edge кейсов
  • Придание уверенности в том, что написанный код следует лучшим практикам
  • Дополнение GitHub Copilot и IntelliJ IDEA AI

Стоит отметить, что за разработкой Amplicode стоит команда с богатым опытом, насчитывающим десятилетия, и успешными продуктами с многомиллионной аудиторией. Также Amplicode гарантирует увеличение скорости создания приложений до 80%, а общей производительности команды разработчиков на 30%.

А теперь давайте посмотрим на Amplicode в действии.

Установка Amplicode

Для того чтобы установить Amplicode:

  • Откройте IntelliJ IDEA
  • Перейдите в секцию Plugins plugins.png
  • Нажмите на иконку шестеренки и выберите пункт Manage Plugin Repositories manage-plugin-repositories.png
  • В открывшемся окне укажите ссылку на репозиторий Amplicode
https://amplicode.ru/jetbrains-marketplace

insert-link.png

  • Находясь на складке Marketplace, впишите в поле ввода Amplicode и нажмите кнопку Install. install-amplicode.png
  • Перезапустите IntelliJ IDEA restart-ide.png

Обзор существующего приложения (через Amplicode Explorer)

Давайте посмотрим, как Amplicode может помочь в разработке уже существующего Spring Boot приложения. В качестве примера возьмем довольно популярный проект Spring PetClinic. Откройте его в IntelliJ IDEA. В момент первого открытия приложения Amplicode необходимо активировать.

activate-amplicode.png

После успешной активации все возможности Amplicode станут доступны. Amplicode предоставляет возможность проанализировать приложение в контексте используемых вреймворков и библиотек с помощью панели Amplicode Explorer.

amplicode-explorer.png

С помощью этой панели можно узнать следующее:

  • Какие модули подключены к проекту
  • Что из себя представляет слой данных

data-layer.png

  • Какие эндпоинты доступны в проекте
  • Какие файлы, необходимые для развертывания приложения, уже есть в проекте

Исходя из знаний Amplicode о нашем проекте, можно сделать следующие выводы:

  1. Для удобной работы с персистентным слоем в приложении используется модуль Spring Data JPA. spring-data-jpa.png
  2. К проекту подключены стартеры Spring Web и Actuator starters.png
  3. В качестве хранилища данных используется встроенная база данных H2 datasource.png
  4. Мы можем более детально ознакомиться с моделью данных нашего приложения, посмотреть, какие основные сущности объявлены в проекте, а также каким образом они связаны друг с другом data-model.png
  5. Все доступные MVC и REST эндпоинты могут быть просмотрены в наиболее удобном для нас виде endpoints.png

Структура проекта стала более понятной. Приступаем к реализации поставленных задач.

H2 -> PostgreSQL

Первым шагом станет замена встроенной базы данных H2 на PostgreSQL. Amplicode старается придерживаться подходов, с которыми многие разработчики уже давно знакомы, как, например, двойной клик, нажатие правой кнопкой мыши или комбинация клавиш для открытия файла. Amplicode с очень высокой вероятностью поймет любое из этих действий на большинстве визуальных элементов.

Нас интересует источник данных. Чтобы обратиться к этому элементу в дереве, выполните двойной клик на dataSource.

database-type.png

В открывшемся окне необходимо выполнить следующие действия:

  • Изменить тип базы данных
  • Указать необходимые параметры, такие как хост, порт, название базы данных, имя пользователя и пароль.
  • Нажать ОК

edit-data-source.png

Важно отметить, что Amplicode не только обновил значения свойств в файле application.properties, но также добавил необходимую зависимость для взаимодействия с базой данных PostgreSQL из нашего приложения.

postgres-properties.png

postgres-dependency.png

Благодаря панели Amplicode Designer, появляется возможность определить, какие еще свойства, помимо уже объявленных, могут быть использованы в приложении. Например, можно обратить внимание, что для группы Spring JPA доступно такое свойство как Auto DDL.

auto-ddl.png

Благодаря использованию этого свойства со значением validate, можно убедиться в том, что JPA модель полностью соответствует схеме, заданной в базе данных.

auto-ddl-validate.png

Также мы можем обратить внимание, что нам доступно свойство Show SQL. Установите это свойство в true для удобства отслеживания того, какие именно запросы отправляются в базу данных.

shoq-sql.png

Осталось только изменить тип базы данных в свойстве database на postgres.

database-postgres.png

Использовать локально поднятые сервисы в современных реалиях является дурным тоном. Из-за использования локальных сервисов возникают проблемы с переносимостью и настройкой окружения каждым из разработчиков на проекте. Намного лучше описать все необходимые сервисы в файле Docker Compose. Используя такой подход, нам достаточно иметь установленный локально Docker либо его аналог. За все остальное можно будет не переживать.

Amplicode содержит узел Docker в панели Amplicode Explorer. docker-in-panel.png

С его помощью вы можете создать файл Docker Compose. Для этого нажмите правую кнопку мыши на узле Docker.

create-docker-compose.png

В открывшемся файле добавьте необходимый нам сервис из числа доступных, воспользовавшись панелью Amplicode Designer, Editor Toolbar или же действием Generate от IntelliJ IDEA.

use-generate-in-docker-compose.png

Amplicode воспользовался уже существующим подключением к базе данных и подставил все необходимые значения в обязательные поля.

postgres-parameters-for-docker.png

Любой из параметров можно менять в случае необходимости, но на текущем этапе вам этого делать не нужно. Достаточно просто нажать ОК. Сервис готов.

docker-service-ready.png

Запустите базу данных, а затем и приложение, чтобы убедиться, что все работает, как и прежде.

Для запуска базы данных нажмите на значок двойной стрелочки в файле docker-compose.yaml.

run-database.png

Первый шаг - переезд на PostgreSQL - успешно осуществлен.

Подключение Flyway. Генерация скрипта инициализации БД

Следующий шаг - добавление инструментов версионирования баз данных. Помимо исследования доступных свойств с помощью Amplicode Designer, мы можем настроить свойства, которые на данном этапе нам пока недоступны ввиду отсутствия необходимых зависимостей. Например, в секции DB Migration можно обнаружить необходимый для дальнейшей работы Flyway.

db-migration-flyway.png

Стоит отметить, что, помимо Flyway, Amplicode может облегчить нам работу и с Liquibase. Все возможности, описанные в этом разделе, доступны также и для тех, кто предпочитает использовать Liquibase.

Для подключения и настройки Flyway необходимо выполнить описанные ниже действия.

  • Оставьте значение префикса-сепаратора и расположение директории, которая будет содержать сгенерированные скрипты, по умолчанию.

db-migration-settings-by-default.png

  • Поскольку мы больше не будем использовать встроенные возможности Spring для создания таблиц, нам потребуется скрипт инициализации базы данных.

script-init-db.png

  • В качестве источника данных следует выбрать базу данных, так как она была успешно проинициализирована и заполнена необходимыми данными на предыдущем шаге.

choose-database.png

  • Для того чтобы Amplicode смог прочитать структуру базы данных и сгенерировать скрипт инициализации, необходимо создать новое подключение либо выбрать уже существующее.

existing-connection.png

  • Нажмите ОК.

  • Amplicode сгенерирует скрипты инициализации базы данных. Прежде чем сохранить их, следует убедиться, что они соответствуют нашим ожиданиям.

verifying-initialization-scripts.png

Скрипт инициализации базы данных готов. Ранее существовавшие скрипты инициализации базы данных при наполнении ее данными больше не понадобятся, поэтому необходимо удалить те свойства, которые на них ссылаются.

properties-to-delete.png

На этом настройка Flyway успешно завершена. Модно переходить к следующему шагу.

Изменение модели: добавление базового атрибута

Следующей задачей является реализация учета заработных плат сотрудников. Для этого прежде всего необходимо расширить существующую модель данных, а именно добавить поле, содержащее информацию о зарплате, в сущность Vet.

Воспользуйтесь панелью Amplicode Designer (Attributes -> Basic Type) либо панелью Generate от IntelliJ IDEA, в которой необходимо выбрать пункт Entity Attribute.

add-attribute-to-vet-entity.png

В открывшемся окне можно полностью настроить атрибут. Прежде всего, необходимо правильно выбрать тип для нового аттрибута. Хорошей практикой при работе с денежными типами данных в Java является использование BigDecimal.

attribute-setup-window.png

В зависимости от выбранного типа, Amplicode предоставляет дополнительные параметры настройки атрибута. В данном случае это Precision и Scale.

attribute-setup-window.png

Оставьте их значения как предложено по умолчанию и нажмите OK. Атрибут готов.

Если обратить внимание на панель Amplicode Designer, то можем увидеть, что нам доступна секция Validation, так как в приложении используется одноименный стартер.

validation-for-attribute.png

Amplicode знает об этом и позволяет нам выбрать нужные валидации из множества доступных для конкретного атрибута, не обращаясь к поиску в интернете или чтению документации.

Логичной валидацией в данном случае будет @PositiveOrZero. Выберите ее, и Amplicode добавит соответствующую аннотацию.

positive-or-zero.png

Теперь необходимо внести соответствующие изменения в пользовательский интерфейс, добавив новое поле.

change-user-interface.png

Половина из всех поставленных задач выполнена. Запустите приложение, чтобы убедиться, что все работает должным образом. Приложение не запустилось и выдало ошибку, но почему?

error-message-from-app.png

Причина заключается в том, что мы добавили новое поле на уровне JPA, но забыли написать соответствующий скрипт для добавления этой колонки в базу данных. Благодаря свойству Hibernate ddl-auto со значением validate мы обнаружили это несоответствие сразу при запуске приложения.

Amplicode позволяет вызвать действие по синхронизации модели с базой данных прямо из stacktrace. Для этого нажмите на помеченную на рисунке ниже ссылку:

link-in-stacktrace.png

Появится следующее всплывающее окно:

popup-window-from-stacktrace.png

Проверьте, что выбраны корректный persistence unit и подключение к базе данных и нажмите ОК.

Среди всех скриптов, которые мы видим в окне предпросмотра, можно найти тот самый скрипт, который мы забыли написать для новой колонки. Однако, помимо этого скрипта есть еще более 10 скриптов, которые мы не ожидали увидеть. Давайте разберемся, в чем же дело.

script-preview-window.png

Ранее мы использовали скрипты, в которых не указывали длину для колонок с текстом. Однако, в JPA, когда мы используем аннотацию @Column, по умолчанию будет выставлена длина 255. Amplicode об этом знает и предлагает модифицировать длину существующих колонок. Так как подобное изменение может привести к потере данных, то есть, те данные, которые выходят за границу 255 символов, будут удалены, Amplicode подсвечивает нам все эти скрипты красным цветом, так как к ним требуется особое внимание со стороны разработчика.

red-scripts.png

Если говорить о цветовой раскраске, то бывают еще скрипты, которые Amplicode отмечает желтым и зеленым цветами. По аналогии с красными скриптами, желтые могут быть потенциально опасны, а вот зеленые абсолютно безопасны и не смогут привести к потере данных.

yellow-and-green-scripts.png

Остальные изменения, которые мы видим, точно так же появились здесь ввиду различий между JPA моделью и базой данных, которые, видимо, накопились за долгое время существования проекта.

Эти изменения выходят за рамки текущих задач, поэтому перенесите их в секцию Ignored. Для этого:

  • Пометьте все переносимые скрипты
  • Нажмите правую клавишу мыши
  • Во всплывающем меню выберите Remove and Ignore

remove-and-ignore.png

Amplicode запомнит все эти изменения и не будет предлагать их при последующих генерациях скриптов.

Наконец, можно заметить, что в этой секции уже были некоторые скрипты. Например, скрипт по удалению индекса из базы данных. Amplicode заранее разместил эти скрипты в секцию Ignored.

ignored-by-default.png

Такой подход выглядит довольно логичным, так как создание индекса может быть довольно дорогостоящей операцией, а его объявление на уровне модели JPA не является довольно распространенным. Поэтому удалять его мы вряд ли захотим.

Теперь скрипт нас полностью устраивает. Назовите его V1__add_salary и перезапустите приложение. У ранее созданных ветеринаров отсутствует значение для поля зарплаты. Для проверки корректности реализованной функциональности необходимо проинициализировать поля рандомными значениями. Это можно сделать из вкладки local как показано на рисунке ниже:

initialize-salaries.png

Теперь все должно работать, корректно.

vets-with-salaries.png

Подключение и настройка Spring Security

Давайте проанализируем, что мы уже сделали. Решив предыдущую задачу, мы столкнулись с небольшой проблемой безопасности. Теперь абсолютно все, даже неаутентифицированные пользователи, могут просматривать информацию о зарплатах сотрудников. Давайте сделаем так, чтобы эту информацию могли видеть только аутентифицированные пользователи. Для этого добавим Spring Security и настроим доступ к эндпоинту.

Amplicode позволяет добавить и настроить Spring Security через панель Amplicode Explorer. Для этого неоьходимо выбрать Add Configuration -> Spring Security Configuration.

add-spring-security-configuration.png

Интуитивно понятные диалоговые окна позволяют настроить один из множества наиболее популярных способов аутентификации и дополнительные параметры, специфичные для каждого из типов.

authentication-methods.png

В данном случае подойдет базовый механизм Spring Security HTTP session authentication. Поэтому:

  • Отметьте соответствующий радио баттон и нажмите Next

authentication-method-step-1.png

  • Оставьте все параметры по умолчанию (в дальнейшем их можно будет изменить, если потребуется); нажмите Next

authentication-method-step-2.png

  • Убедитесь в правильности настроек и нажмите Next

authentication-method-step-3.png

  • На последнем шаге можно увидеть, какие новые зависимости будут добавлены к проекту, затем необходимо нажать Create

authentication-method-step-4.png

Конфигурационный класс для Spring Security готов. Перезапустите приложение, чтобы убедиться в том, что теперь информацию о ветеринарах смогут видеть только аутентифицированные пользователи.

Модификация существующего REST эндпоинта

Помимо MVC эндпоинтов в нашем приложении также существует один REST эндпоинт, который могут использовать наши внешние клиенты для получения информации о ветеринарах (класс Vets, исходный код приведен ниже).

@XmlRootElement
public class Vets {

	private List<Vet> vets;

	@XmlElement
	public List<Vet> getVetList() {
		if (vets == null) {
			vets = new ArrayList<>();
		}
		return vets;
	}

}

В качестве возвращаемого значения здесь используется список сущностей. Как следствие, каждое изменение в модели, такое как добавление зарплаты или любого другого поля, будет отражаться и на клиентах. И этого мы, конечно же, не хотим.

Наиболее распространенным решением этой проблемы является использование DTO в качестве возвращаемого типа. Давайте просто изменим возвращаемый тип на не существующий пока что VetWithoutSalaryDto.

@XmlRootElement
public class Vets {

	private List<VetWithoutSalaryDto> vets;

	@XmlElement
	public List<VetWithoutSalaryDto> getVetList() {
		if (vets == null) {
			vets = new ArrayList<>();
		}
		return vets;
	}

}

Amplicode понял, что мы хотим сделать, и позволяет нам вызвать диалог создания DTO прямо отсюда (нажмите Alt+Enter для Windows/Linux или ⌥+Enter для macOS).

create-dto-popup-menu.png

Далее:

  • Выберите сущность для DTO

select-entity-for-dto.png

  • Создайте абстрактный интерфейс, нажав на ссылку Add MapStruct DTO mapper dependency to project:

add-mapstruct-link.png

  • Сделайте DTO мутабельным и выберите все поля, кроме зарплаты

make-dto-mutable.png

Для ассоциативного поля специальностей Amplicode также предлагает создать DTO. Поэтому:

  • Создайте DTO для специальностей прямо в текущем объекте, выбрав тип New Nested Class.

dto-for-association.png

  • Нажмите OK

DTO и MapStruct интерфейс готовы к использованию. Исходный код MapStruct интерфейса приведен ниже:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING)
public interface VetMapper {
	Vet toEntity(VetWithoutSalaryDto vetWithoutSalaryDto);

	VetWithoutSalaryDto toDto(Vet vet);

	@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
	Vet partialUpdate(VetWithoutSalaryDto vetWithoutSalaryDto,
					  @MappingTarget Vet vet);
}

Теперь нам осталось только преобразовать список возвращаемых сущностей в список DTO в классе VetController. Благодаря Java Stream API мы можем это сделать довольно элегантно, а благодаря IntelliJ IDEA мы можем сразу начать писать необходимый оператор вместо предварительного преобразования списка в поток. IDE выведет список подсказок для нашего удобства.

conversion.png

Помимо встроенных вариантов от IntelliJ IDEA, мы можем также сразу заметить новую опцию mapToVetWithoutSalaryDto от Amplicode, которая выглядит как именно то, что мы и хотим сделать. Выберите этот вариант. Помимо того генерации кода для преобразования сущности в DTO, мы также получим корректно заинжектированный Bean маппера в наш контроллер.

generation-and-bean.png

Последнее, что осталось сделать - предоставить доступ к нашему эндпоинту всем без исключения. Amplicode позволяет нам сделать это прямо из исходного кода контроллера. В IntelliJ IDEA практически все визуальные элементы являются кликабельными. Иконки, предоставляемые Amplicode, не являются исключением.

click-on-the-lock.png

Кликните на иконку замочка, нажмите на Add Authorize Rule и добавьте правило авторизации. Нажмите OK.

add-authorization-rule.png

Amplicode внесет изменения в существующие параметры доступа к эндпоинту.

		http.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
			.requestMatchers(HttpMethod.GET, "/vets").permitAll()
			.anyRequest().authenticated());

Перезапустите приложение и убедимся в том, что все работает корректно. Теперь все приложение доступно только аутентифицированным пользователям, а наш единственный REST эндпоинт - всем без исключения.

rest-endpoint.png

Создание REST-контроллера с нуля

Как мы уже успели заметить ранее, в нашем приложении большинство эндпоинтов реализовано по принципу MVC, и только один из них - REST эндпоинт, объявленный прямо в контроллере MVC.

mvc-and-rest-endpoints.png

На самом деле, это не лучшая практика. Поэтому наша следующая задача - подготовить приложение к интеграции с мобильным клиентом, создав отдельный REST контроллер для REST эндпоинтов.

Для этого:

  • Прямо в дереве проекта вызовите действие REST Controller от Amplicode нажатием правой кнопки мыши

rest-controller-action.png

  • В открывшемся окне укажите название контроллера, пакет, в котором он будет создан, и путь, по которому он будет доступен

rest-controller-parameters.png

  • Нажмите OK

По сути, эндпоинты, которые мы хотим реализовать, являются делегацией методов из репозитория. Amplicode предоставляет специальный диалог для делегирования любых методов из любых Bean'ов, существующих в проекте.

delegate-from.png

Amplicode автоматически выбрал интерфейс VetRepository в качестве источника для делегирования. Это как раз то, что нам нужно.

delegation-source.png

Начнем с настройки метода, отвечающего за делегирование метода findAll. Его название, путь и тип запроса выбраны автоматически именно такие, которые нам и нужны.

name-and-path.png

Единственное, что нам нужно изменить - это возвращаемый тип. Как мы уже говорили ранее, возвращать сущность - не лучшая идея. Можно создать новую DTO и маппер к ней прямо отсюда либо воспользоваться уже существующей DTO. Используйте вторую опцию, так как у нас уже есть класс VetWithoutSalaryDto.

return-type-dto.png

Перед закрытием диалога можно предварительно посмотреть код, который будет сгенерирован, чтобы убедиться, что все сделано верно. Помимо самого метода, Amplicode также инжектирует необходимые Bean'ы в контроллер.

code-preview.png

Нажмите OK.

Второй метод, который необходимо реализовать - это метод для получения ветеринаров только определенной специальности. Для этого понадобится добавить новый метод в репозиторий.

Перейдите к классу VetRepository и создайте метод поиска коллекции сущностей, используя панель Generate от intelliJ IDEA.

generate-repository-method.png

method-find-collection.png

В качестве параметра запроса укажите специальности, а в качестве оператора поиска - условие in. Нажмите OK.

create-collection-window.png

Метод готов, и теперь следует делегировать его прямо в контроллер, воспользовавшись опцией Delegate to из панели Editor Toolbar.

delegete-to.png

В открывшемся окне выберите тот контроллер, в который мы хотим делегировать данный метод.

select-controller.png

Следующее, что нужно сделать - настроить параметры метода контроллера. Мы реализовали метод по поиску ветеринаров, принадлежащих к определенной специальности.

method-implementation.png

Подобная реализация крайне понятна в использовании, а также более поддерживаема в дальнейшем ввиду наличия типизации. Но, реализуя REST эндпоинт, нам бы хотелось получать всех ветеринаров, принадлежащих к определенным специальностям, указывая только их идентификатор. Amplicode прекрасно понимает, что такое требование является довольно распространенным, и предоставляет удобный способ его реализации.

В выпадающем списке для параметров метода Specialties выберите метод уже существующего репозитория SpecialtyRepository, который обернет полученный из запроса идентификатор в прокси-объект без дополнительных запросов в базу данных.

select-existing-method.png

Аналогично ранее созданному эндпоинту, измените возвращаемый тип на DTO и нажмите OK.

change-type-to-dto.png

Укажите путь к эндпоинту, воспользовавшись панелью Amplicode Designer.

specify-path.png

Отлично! Все, что нам осталось сделать - настроить Spring Security, сделав все REST эндпоинты общедоступными. Для этого воспользуйтесь замочком над классом и выберите в качестве правил доступа значение Permit all.

permit-all.png

Тестирование эндпоинта

Есть довольно много способов протестировать работоспособность нашего кода. Можно было бы обратиться к эндпоинтам через стороннего HTTP клиента вроде Postman, через браузер, как мы это делали ранее или через curl команды прямо из терминала. Но с Amplicode для нас открывается еще одна возможность реализовать проверку, пожалуй, еще более быстрым способом и еще более полезным в дальнейшем. А именно, используя @WebMvcTest.

На самом деле, тема тестирования довольно обширная и выходит за рамки наших сегодняшних целей. Более подробно мы расскажем о том, как Amplicode может помочь вам в тестировании Spring Boot приложения, в одном из следующих видео. А сегодня давайте сгенерируем тесты, которые позволят нам убедиться в том, что наши REST эндпоинты возвращают нужный статус.

  • Откройте меню Generate от IntelliJ IDEA
  • Создайте новый тестовый класс

create-new-test-class.png

  • В качестве тестового контекста выберите Spring Boot Application.

select-context.png

  • Пометьте оба метода как тестируемые
  • Отключите CSRF

both-methods.png

  • Настройте входные параметры для метода поиска по специальности как показано на рисунке.

search-by-speciality-parameters.png

  • Нажмите OK.

Чтобы запустить тесты, воспользуйтесь специальной иконкой в исходном коде тестового класса:

run-the-tests.png

Если тесты прогнались удачно, вы должны увидеть примерно следующую картину:

test-no-errors.png

Изменение модели: добавление ассоциативной связи

Следующей задачей, которую предстоит решить, является реализация логики по автоматическому назначению ветеринара новому визиту. Для того чтобы реализовать подобную функциональность, сначала нужно вновь расширить существующую модель, добавив ассоциативную связь "Многие к одному" от визита к ветеринару. Воспользуйтесь уже знакомым нам действием по добавлению нового атрибута. В качестве типа атрибута укажем ветеринара.

add-attribute-vet.png

Все параметры в данном случае нас полностью устраивают. Стоит отметить, что Amplicode позволяет создавать любой тип ассоциативной связи; более того, он всегда сможет подсказать вам, какая из реализаций будет дучше в плане производительности, благодаря умным подсказкам.

Пример: smart-prompt.png

Однако, в данном случае вам надлежит оставить все параметры без изменений и просто нажать OK.

Атрибут готов. Не забудьте внести изменения на UI, а также сгенерировать скрипт миграции.

Написание бизнес логики

Бизнес логику в Spring приложениях принято реализовывать в классах, помеченных аннотацией @Service. Давайте создадим такой класс. Помимо обычного класса, среди доступных опций можем обратить внимание на отдельно стоящий элемент Spring Service от Amplicode. Давайте им и воспользуемся. Нажмите на Spring Service в меню New, как показано на рисунке.

new-spring-service.png

В появившемся окне введите имя класса и нажмите OK.

enter-class-name.png

Amplicode создаст пустой класс под реализацию бизнес логики.

Логика нахождения подходящего ветеринара будет довольно простой. В случае, если у питомца уже были визиты в клинику, то выберем последнего ветеринара, работавшего с питомцем. В случае же, если визитов ранее не было, будем назначать любого из ветеринаров с профессией хирурга.

Давайте приступим к реализации. Сначала надо получить список визитов переданного питомца. Если список пуст, то нам нужно найти любого из ветеринаров с идентификатором специальности, равным идентификатору специальности "Хирург". Для этого обратимся к интерфейсу VetRepository и попробуем найти подходящий метод. Вместе с Amplicode нам не нужно думать о том, какие Bean'ы уже заинжектированы в текущий сервис, а какие нет. Мы можем начать писать имя нужного нам Bean, выбрать его из списка, а Amplicode сделает все необходимое для того, чтобы мы смогли им воспользоваться.

auto-assignment-code.png

Среди существующих методов репозитория нам ни один не подходит. Однако есть возможность создать новый метод прямо отсюда благодаря действию find с многоточием.

find-with-three-dots.png

В качестве типа репозитория выберите тип поиска коллекции сущности.

search-for-entity-collection.png

Amplicode откроет диалог создания нового метода в уже существующем репозитории. Для этого даже не требуется покидать текущий редактор кода. Нажмите на ссылку Add query condition.

create-new-method-dialog.png

Чтобы реализовать поиск ветеринара по id специальности:

  • Нажмите на икону с тремя точками в колонке Attribute в таблице

click-three-dots.png

  • Выберите поле id из списка

choose-attribute-window.png

  • Выберите условие in из списка в колонке Condition

choose-condition.png

  • Нажмите OK

Метод в репозитории создан, и его вызов сгенерирован в нашем сервисе. Осталось только реализовать логику нахождения ветеринара, работавшего последним с нашим питомцем. Финальный код метода будет иметь следующий вид:

@Service
public class VetAutoAssignmentService {

	public static final int SURGERY_ID = 2;
	private final VetRepository vetRepository;

	public VetAutoAssignmentService(VetRepository vetRepository) {
		this.vetRepository = vetRepository;
	}

	public Vet findAppropriateVet(Pet pet) {
		List<Visit> visits = pet.getVisits()
			.stream()
			.toList();
		if (visits.isEmpty() || visits.stream()
			.noneMatch(v -> v.getVet() != null)) {
			return vetRepository.findBySpecialties_IdIn(Collections.singleton(SURGERY_ID))
				.stream()
				.findAny()
				.orElseThrow();
		}
		return visits.stream()
			.filter(v -> v.getVet() != null)
			.max(Comparator.comparing(Visit::getDate))
			.orElseThrow()
			.getVet();
	}
}

Сервис готов к использованию. Давайте воспользуемся Amplicode Explorer, чтобы быстро найти эндпоинт для создания нового визита. Скорее всего, в пути к подобному эндпоинту должны содержаться слова visit и new. Действительно, подобный POST эндпоинт существует в проекте.

visit-new-endpoint.png

Первым делом обратимся к нашему сервису по имени vetAutoAssignmentService`

vetAutoAssignmentService.findAppropriateVet(pet);

В текущем эндпоинте у нас еще нет объекта pet, есть только его идентификатор. Давайте аналогичным образом заинжектируем репозиторий для сущности Pet и обратимся к методу getReferenceById, чтобы обернуть идентификатор в объект.

Начните писать petRepository. Оказывается, у нас в проекте еще не было репозитория для сущности Pet. Несмотря на это, Amplicode понял, что именно мы хотим сделать, и вывел всплывающее окно, позволяющее совместить сразу несколько действий в одно: создание нового репозитория, его инжекция и генерация обращений к нему.

popup-prompt.png

Выберите petRepository. Появится следующее выплывающее окно:

create-pet-repository.png

Нажмите OK. Недостающий класс будет создан в проекте.

Amplicode настолько хорошо понимает наш проект, что предлагает заинжектировать даже еще не существующие Bean'ы.

Обратимся к методу getReferenceById, чтобы получить объект. Передадим его в метод сервиса и наконец установим объекту visit выбранного ветеринара.

		Pet pet = petRepository.getReferenceById(petId);
		Vet vet = vetAutoAssignmentService.findAppropriateVet(pet);
		visit.setVet(vet);

Запустите приложение и попробуйте создать новый визит.

create-new-visit.png

Если все сделано правильно, ветеринар будет успешно назначен автоматически.

vet-automatically-assigned.png

Еще одна задача решена. Можно двигаться дальше.

Подключение и настройка Kafka

Следующей задачей для нас будет настройка отправки сообщений в Kafka и их получение из нее. Для этого нам сначала нужно подключить саму Kafka к проекту. Давайте воспользуемся Amplicode Explorer, чтобы создать новую Kafka конфигурацию. Для этого:

  • Нажмите правой клавишей мыши на пункте Configurations
  • Выберите Add Configuration и затем Kafka Configuration.

kafka-configuration.png

Создадим новый конфигурационный класс для настроек, связанных с Kafka, воспользовавшись для этого появившимся всплывающим окном. Для этого нажмите на иконку плюса рядом с полем Configuration class и затем в новом маленьком окошке нажмите OK.

kafka-configuration-class.png

Далее, в качестве значения для идентификатора группы потребителей укажите visit, а все остальные параметры оставьте по умолчанию и нажмите OK.

specify-group-id.png

Amplicode добавит необходимую зависимость, настроит значения в файле свойств и создаст все необходимые компоненты для новой конфигурации. Кроме того, Amplicode сразу же предложит нам добавить Kafka в качестве сервиса в Docker Compose.

docker-compose-suggestion.png

Воспользуйтесь этим предложением, нажав на соответствующую ссылку. Оставьте все настройки по умолчанию и нажмите OK.

Запустите Kafka, чтобы убедиться, что все работает корректно. Для этого в файле docker-compose.yaml нажмите соответствующую иконку стрелочки.

run-kafka.png

Отправка сообщений в Kafka

Теперь нам нужно настроить отправку сообщений в очередь после добавления, удаления и изменения визитов в базе данных. Для этого будет удобно воспользоваться Hibernate Event Listener, чтобы отслеживать изменения с помощью механизма, представленного Hibernate.

Откройте меню создания новых элементов в дереве проекта и в разделе Other найдите Hibernate Event Listener.

hibernate-event-listener.png

Далее:

  • Переименуйте класс в VisitHibernateEventListener

rename-listener.png

  • Выберите типы событий, на которые будет реагировать наш слушатель

choose-events.png

  • Укажите сущность

specify-entity.png

  • Нажмите OK

listener-basis.png

Класс-основа для слушателя будет сгенерирован.

Теперь осталось только реализовать логику отправки сообщений в очередь.

Измените возвращаемое значение в методе requiresPostCommitHandling с false на true, чтобы разрешить Hibernate выполнять всю описанную выше логику после коммита.

false-to-true.png

Снова придерживаясь уже известного правила о том, что лучше отправлять DTO, а не сущность, воспользуйтесь постфиксом mapTo для преобразования сущности в DTO.

use-mapto.png

В качестве типа для DTO выберите Java Record, отметьте все базовые поля, а для ветеринара - только идентификатор, как показано на рисунке.

create-dto-for-kafka.png

Также, необходимо создать новый MapStruct интерфейс.

new-mapstruct-interface.png

Далее, нажмите OK, чтобы завершить генерацию кода для DTO.

Теперь необходимо воспользоваться еще одним постфиксом send, чтобы настроить отправку сообщений в очередь.

postfix-send.png

После нажатия на send появится следующее диалоговое окно:

kafka-template-dialog.png

Нажмите Next.

Сериализаторы для ключа и значения выбраны правильно.

serializers.png

Нажмите Next.

Надо изменить только конфигурационный класс, в котором будет зарегистрирован новый Kafka template.

kafka-template-configuration-class.png

Выберите KafkaConfiguration из выпадающего списка и нажмите Create.

click-create.png

Kafka template с нужными типами создан и уже внедрен в класс.

kafka-template-in-code.png

Осталось только указать название очереди, в нашем случае, visit.

specify-visit.png

При желании можете скопировать следующий код напрямую из текста гайда:

kafkaTemplate.send("visit", visitMapper.toDto(visit));

Теперь скопируйте получившуюся строку в остальные обработчики событий.

copy-to-all-handlers.png

Отправка сообщений в очередь полностью настроена.

Получение сообщений из Kafka

Чтобы убедиться в том, что все работает, реализуем получение сообщений из брокера. Для того чтобы настроить получение сообщений из Kafka в Spring, необходимо создать новый сервис. Воспользуйтесь меню New и выберите Spring Service.

new-spring-service-for-receiving-messages.png

Появится диалоговое окно. Назовите новый класс KafkaVisitService и нажмите OK.

kafka-visit-service.png

Новый класс будет сгенерирован и открыт в редакторе IDE.

Механизм получения сообщения Spring для Kafka реализуется через слушатель. Amplicode позволяет нам создать их с помощью Amplicode Designer.

amplicode-designer-for-kafka.png

Нажмите на @KafkaListener и из выпадающего списка выберите New Container.

new-container.png

В открывшемся окне выберите тип ключа (String) и тип значения (VisitDto), затем нажмите Next.

key-type-value-type.png

На данный момент оставьте без изменения сериализаторы, которые предлагает Amplicode, и в случае необходимости вы всегда сможете изменить их значения потом. Нажмите Next.

Выберите конфигурационный класс, в котором будет создан необходимый компонент. Для этого, аналогично тому, как это было сделано в предыдущем разделе, выберите KafkaConfiguration из выпадающего списка и нажмите Create.

Kafka слушатель готов. Для демонстрации достаточно просто залоггиовать то, что приходит из очереди с названием visit. Запустите приложение и создайте новый визит.

Если все работает корректно, новый визит должен отобразиться в логах.

new-visit-in-logs.png

Контейнеризация Spring Boot приложения

В качестве финального шага реализуем возможность запуска приложения также из Docker Compose. С Amplicode весь процесс не займет более двух минут.

  • В Amplicode Designer, Editor Toolbar или Generate menu выберите Spring Boot приложение.

select-spring-boot-three-ways.png

  • Образ будет создаваться из Dockerfile, который нам также предварительно потребуется создать, для чего воспользуйтесь иконкой "плюс" рядом с полем Dockerfile:

create-dockerfile.png

  • Пометьте чекбокс Include application build stage, чтобы включить стадию сборки нашего приложения, а настройки Gradle оставьте по умолчанию

  • Нажмите OK

  • В качестве зависимых сервисов выберите Postgres

depends-on-postgres.png

  • Нажмите OK еще раз

Теперь нужно изменить значения свойств в application.properties. Так как Kafka и Postgres больше не будут располагаться на localhost, для образа, поднятого в Docker, добавьте переменные окружения, чтобы указать валидные пути к сервисам. Для этого необходимо открыть файл application.properties и воспользоваться контекстным действием от Amplicode (нажмите Alt+Enter для Windows/Linux или ⌥+Enter для macOS).

context-action.png

Пользуясь пунктом меню Wrap property value with environment variable, укажите значения, которые будут использоваться при запуске в Docker Compose.

environment-variables.png

Запустите приложение и проверьте, все ли работает, как прежде. Теперь, используя Docker Compose, вам не составит никакого труда задеплоить приложение для тестирования или демонстрации.

Заключение

Давайте вспомним еще раз, какие задачи были поставлены перед нами в этом гайде.

  • Сделать приложение production-ready, а именно переехать с H2 и инициализировать базу данных посредством стандартного механизма Spring на PostgreSQL и Flyway в качестве системы версионирования базы данных
  • Реализовать учет заработных плат сотрудников, расширив существующую модель данных и изменив пользовательский интерфейс (При этом важно будет сохранить обратную совместимость с имеющимся API, а также подключить и настроить Spring Security таким образом, чтобы информацию о зарплатах не могли получить все желающие)
  • Подготовить приложение к разработке мобильного клиента, а именно, реализовать REST эндпоинты для получения списка ветеринаров, а также списка ветеринаров с возможностью фильтрации их по специальностям
  • Реализовать автоматическое назначение ветеринаров новым визитам
  • Настроить оповещение сотрудников о новых визитах через интеграцию с внешним сервисом, используя Kafka
  • Описать все сервисы, как и Spring Boot приложение, в качестве контейнеров в файле Docker Compose

Мы реализовали все поставленные перед нами задачи менее чем за 30 минут. На самом деле, Amplicode содержит еще множество фич, которые просто не уместились в данный гайд. Если говорить о Spring Boot, то не были показаны, но также заслуживают внимания следующие возможности Amplicode:

  • Поддержка Spring Data MongoDB
  • Поддержка Spring Data JDBC
  • Возможность создания JPA сущностей из таблиц базы данных
  • Поддержка Spring Events и Spring Cloud
  • И многое другое

Кроме помощи в написании backend, Amplicode также помогает и при разработке frontend, предоставляя:

  • Создание React Admin модуля
  • Генерацию типовых экранов для CRUD
  • Помощь в разработке экранов на React Admin

Кроме того, мы также частично продемонстрировали поддержку деплоймента в данном видео. Но на самом деле она еще более обширная и включает в себя:

  • Помощь при написании GitLab/GitHub CI actions
  • Поддержку при разработке Kubernetes/Helm
  • А также развертывание в облаке

В ближайшем будущем мы постараемся раскрыть озвученные ранее возможности в наиболее полном объеме в отдельных видео. А если вы заинтересовались Amplicode и хотите самостоятельно изучить его возможности, то присоединяйтесь к нашему Telegram каналу. Там вы найдете все необходимое для того, чтобы начать получать максимальное удовольствие от разработки вместе с Amplicode.