Все уже прекрасно понимают, что Amplicode — неотъемлемая часть тулинга для разработки в OpenIDE, IntelliJ IDEA Community Edition и GigaIDE на Spring Boot. Но стоит установить Amplicode в IntelliJ IDEA Ultimate и ваша, казалось бы, идеальная IDE станет ещё мощнее и удобнее.

Пользователи Ultimate выбирают лучшее из лучшего. Если вы работаете в Ultimate, значит, привыкли к топовым инструментам, которые экономят время и делают разработку приятнее. Amplicode органично дополняет этот набор: он добавляет в IDE то, чего всегда не хватало — быструю работу с данными, автоматизацию рутины и готовые решения для Spring-разработки.

Amplicode особенно любим у пользователей Ultimate именно потому, что продолжает эту философию: никаких компромиссов — только максимум возможностей и комфорта. Хотите оставаться среди тех, кто работает с самыми сильными инструментами? Amplicode — ваш must-have.


Статья получилась объёмной, но мы решили не дробить её на части. Потратив 30 минут на чтение, вы сэкономите часы в будущем.

Помните про принцип «малых шагов» — регулярные небольшие улучшения дают большой результат на дистанции. Экономьте по несколько минут каждый день — к концу недели это уже несколько часов.

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

Amplicode – идеальное дополнение к IntelliJ IDEA Ultimate


Создание Spring-приложения

Начнем с базы — создания Spring Boot-проекта. Кажется, как часто разработчики создают проекты с нуля? Но именно это первое, что мы ожидаем от IDE и идем проверять.

В IntelliJ IDEA Ultimate есть функциональность создания проекта, интегрированная со start.spring.io. Давайте воспользуемся ею и создадим проект с типовыми компонентами: Spring Data JPA, Spring Web, Spring Security.

Даже если что-то забыли, не проблема — добавим позже через функцию Add starters....

Добавить Spring-стартер
Добавить Spring-стартер

Что получаем на выходе? Рабочее приложение (нет). Конечно, это только стартовая точка. Впереди — бизнес-логика, работа с данными, REST API, Kafka-очереди или другие механизмы. Но уже сейчас можно нажать Run и увидеть, что приложение запускается. Ну почти...

Ошибка запуска Spring-приложения
Ошибка запуска Spring-приложения

Появится ошибка: не сконфигурирован DataSource. Кажется странным, но вспомните в процессе создания приложения — нас никто не спрашивал о названии базы данных, хосте, логине и пароле. Не беда — давайте доконфигурируем.

Настройка DataSource

Открываем application.properties. Осталось совсем немного: вспомнить названия свойств для настройки DataSource и структуру jdbcUrl. Удобно, что IDE знакома с Spring Properties и подсказывает их, помогая избежать опечаток. Важно не забыть указать правильный драйвер для БД.

Кажется, ничего нового — так мы делали всегда. Но можно ли иначе?

Amplicode предлагает удобную функциональность работы с DataSource. С его помощью можно сконфигурировать как основной, так и дополнительные DataSource.

В результате Amplicode не только добавил свойства для настройки DataSource, но и зависимость на драйвер PostgreSQL (или драйвер для другой СУБД):

spring.datasource.url=jdbc:postgresql://localhost/orders
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=org.postgresql.Driver
runtimeOnly 'org.postgresql:postgresql'

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

Что насчет остальных параметров DataSource? Размер пула подключений, connection timeout? Чтобы это узнать, обычно нужно найти имя свойства и перейти в соответствующий класс Properties прямо из IDE, а затем посмотреть, чему равны значения. Но можно проще.

В Amplicode есть Amplicode Inspector. Достаточно поставить курсор на DataSource и взглянуть на нижнюю часть панели, мы часто называем её Amplicode Inspector — и вы увидите все актуальные свойства, их значения, а также значения по умолчанию, если они не заданы.

Amplicode Designer (нижняя панель aka Inspector)
Amplicode Designer (нижняя панель aka Inspector)

Пробуем запустить приложение снова. На этот раз оно падает по вполне ожидаемой причине: мы настроили DataSource для подключения к локальному PostgreSQL, но окружение не подготовили. Исправляем это — для локального окружения используем Docker Compose.

Docker Compose для локального окружения

Начнем с создания файла. Docker Compose использует формат YAML, значит нам нужен файл с расширением .yml или .yaml. Создать его можно через New...

Но давайте остановимся на секунду. Как часто мы создаем файлы в IDE?

На самом деле — не так часто. Чаще мы создаем классы, интерфейсы, репозитории, сервисы, контроллеры. Для нас это уже рутина. IntelliJ IDEA, как и любой продукт, вынуждена расставлять приоритеты: поддерживать одни технологии в ущерб другим. Amplicode помогает закрыть эти пробелы.

Например, в меню New... вы найдете пункт для создания Docker Compose-файла. Помимо этого, Amplicode позволяет создавать репозитории, сервисы, контроллеры, CRUD-контроллеры, event-листенеры, Helm-чарты и многое другое. Мелочь, а приятно.

Фреймворко-ориентированные действия от Amplicode
Фреймворко-ориентированные действия от Amplicode

Теперь нужно добавить для нашего DataSource сервис PostgreSQL. JetBrains тоже стараются помочь — IntelliJ IDEA предлагает комплишены для YAML, но поскольку общедоступного формата описания опций конфигурации docker-образов не существует (есть только Dockerfile), подсказки носят общий характер.

Этого недостаточно. Чтобы правильно сконфигурировать PostgreSQL, нужно знать:

  • версию образа,

  • имя базы данных, пользователя и пароль,

  • где смонтировать volume,

  • как настроить healthcheck.

Почти все это можно узнать только из документации. Поэтому в Amplicode мы добавили функциональность для работы с сервисами в Docker Compose.

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

Добавляем сервис — в нашем случае PostgreSQL. В открывшемся диалоге можно его доконфигурировать, например выбрать, для какого DataSource мы его создаем.

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

Работа с данными в приложении

Движемся дальше. Сложно представить приложение, которое не работает с данными. Есть мнение, что современный бэкенд-разработчик в основном «гоняет» данные между JSON/Protobuf/... и БД. Поэтому в IntelliJ IDEA есть отличные инструменты для работы с данными.

Начнем с хорошо знакомого DB-клиента. Этот инструмент невероятно мощный: он позволяет работать с очень большими таблицами, размер которых ограничен лишь объемом вашей ОЗУ. Он настолько хорош, что некоторые пользователи покупали Ultimate только ради него. Позже JetBrains вынесли его в отдельный продукт и продолжают активно развивать.

Большинство из нас хорошо с ним знакомо. Вот лишь малая часть возможностей:

  • просмотр структуры БД (таблицы, колонки, индексы, внешние ключи),

  • изменение структуры таблиц и связей,

  • редактирование данных в реляционных, колоночных и NoSQL-базах,

  • копирование, экспорт, выполнение запросов и многое другое.

За полным списком лучше обратиться к документации.

А что с самим приложением? Обычно оно работает с данными через Spring Data JPA/JDBC/MongoDB/Redis и т.д. Давайте разберемся по порядку.

Моделирование сущностей (JPA/JDBC/MongoDB)

Сущность — ключевой термин в Spring Data:

  • в JPA это @Entity,

  • в JDBC — @Table,

  • в MongoDB — @Document.

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

  • В JPA для этого есть аннотации @OneToMany, @ManyToOne, @ManyToMany.

  • В JDBC для описания агрегата используют @MappedCollection, а для связи агрегатов — AggregateReference.

Для начала посмотрим, как создавать сущности.

Например, в JPA это Java/Kotlin-класс с аннотациями @Entity, @Table и обязательным полем с @Id. На многих проектах принято добавлять @Table, хотя по спецификации это не обязательно.

Создаем сущность через New.... Вроде все просто — IDE умеет создавать классы. Но можно лучше. Amplicode позволяет создавать ключевые объекты поддерживаемых фреймворков напрямую: New... → JPA Entity, указываем тип идентификатора — и на выходе готовая сущность.

Amplicode может не только создавать объекты «с нуля», но и использовать готовые. Например, если уже есть БД, можно сгенерировать JPA Entity на основе таблицы — достаточно настроить подключение в IDE.

Если вы используете Spec First-подход, можно создать сущность на основе DTO.

Осталось добавить атрибуты. Тут все по классике: указываем тип, имя поля, при необходимости добавляем @Column. Для простых типов, например String, этого достаточно. Но есть типы, для которых нужно указывать дополнительные параметры.
Например, у BigDecimal важно задать precision и scale, иначе на реальных данных можно получить неприятные баги.

Amplicode помогает с этим:

  • позволяет быстро создавать атрибуты с базовыми типами (String, Integer, Long, BigDecimal),

  • корректно генерирует связи между сущностями (@OneToMany, @ManyToOne, @ManyToMany),

  • предупреждает об особенностях работы коллекций в JPA.

Следуя этим рекомендациям, можно избежать проблем с производительностью и дублированием элементов. Вопросу корректной реализации equals() и hashCode() для JPA-сущностей мы даже посвятили отдельную статью.

Методы Spring Data репозиториев и поддержка кастомных @Query

После создания сущностей нужно реализовать операции над ними: поиск по id, фильтрация по атрибутам, создание, изменение, удаление. В Spring Data это принято делать через репозитории.

Spring Data предоставляет несколько инструментов: derived method, query method, custom repository — обычно именно в таком порядке их и применяют.

Предположим, у нас есть сущность Vet с атрибутами: фамилия, имя, дата рождения и связью один-ко-многим с сущностью Specialty (если вы знакомы с типовым проектом Spring «PetClinic», то модель вам знакома).

Поиск по ID

Начнем с простого — поиска ветеринара по id. Для этого создаем репозиторий, унаследовав его от нужного родителя, например JpaRepository. Amplicode позволяет сделать это быстро — так же, как и с другими объектами. Созданный репозиторий «из коробки» содержит множество полезных методов, включая findById.

Derived-методы

Следующая задача — поиск ветеринара по части фамилии, без учета регистра.

Открываем интерфейс репозитория и начинаем набирать findAllBy.... IDE подсказывает возможные варианты. Нужно вспомнить:

  • какое условие использовать для поля фамилия — до или после имени поля,

  • как задать игнорирование регистра.

После пары попыток метод будет готов.

Но с Amplicode это можно сделать быстрее.

Вызываем контекстное меню Generate или открываем Amplicode DesignerRepository derived method -> Find Collection. В окне выбора указываем атрибут, выбираем условие Contains, ставим галочку IgnoreCase и жмем OK. Amplicode создаст метод в нужном виде. Создавать derived-методы становится действительно удобно, так как нет необходимости держать в голове всю модель данных.

@Query-методы

Так же легко можно создать метод с @Query. В контекстном меню или в Amplicode Designer выбираем Repository Query method, задаем атрибуты и условия, Amplicode сгенерирует метод с JPQL-запросом.

Если нужно, можно доработать запрос вручную — в IntelliJ IDEA Ultimate есть отличная поддержка JPQL.

Кроме того, Derived-метод можно конвертировать в Query-метод. Для этого вызываем действия IDE над методом и выбираем Extract JPQL query. Amplicode добавит аннотацию @Query с запросом и предложит переименовать метод.

Entity Graph

Еще один полезный инструмент — Entity Graph. Он нужен, если требуется загрузить дерево связанных сущностей одним запросом. Например, при поиске ветеринара по id нам нужны не только данные ветеринара, но и его специальности. Создадим метод:

Optional<Vet> findWithSpecialityById(Long id);  

Теперь определим граф для загрузки специальностей. Снова встает вопрос: писать руками или воспользоваться инструментом? Amplicode упрощает задачу.

Ставим курсор на метод → вызываем быстрые действия → Define an entity graph.
Выбираем сущности, указываем тип графа (load/fetch), жмем OK. Amplicode добавит аннотацию:

@EntityGraph(attributePaths = {"specialities"})
Optional<Vet> findWithSpecialityById(Integer id);

Версионирование БД (Liquibase/Flyway)

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

Есть несколько способов:

  • создать таблицы вручную через DB Client в IDE,

  • воспользоваться стратегиями create/create-only/create-drop из Hibernate,

  • использовать инструменты версионирования БД — Liquibase или Flyway.

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

Мы будем использовать Flyway. Конечно, можно просто отредактировать стартеры через IDE, но, как я уже писал в разделе про DataSource, это требует дополнительной настройки. А вот если добавить Flyway-конфигурацию через Amplicode, можно сразу приступить к написанию скриптов.

В Amplicode Explorer вызываем контекстное меню на элементе Configurations → Add Configuration → DB Migration Configuration. В открывшемся окне выбираем Flyway (Amplicode поддерживает и Liquibase), указываем место хранения скриптов и активируем опцию "Create init db scripts". Это удобно, так как на момент подключения механизма версионирования у нас обычно уже есть модель или готовые таблицы. В нашем случае это модель, поэтому выбираем ее и указываем тип БД — PostgreSQL. Жмем OK.

Amplicode добавит зависимости, настройки в application.properties и сгенерирует скрипты инициализации схемы для пустой БД. Остается только сделать ревью сгенерированных скриптов — вы удивитесь, насколько точно Amplicode интерпретирует описание JPA (или JDBC) модели. Теперь при запуске на пустой БД приложение выполнит эти скрипты и создаст все нужные объекты.

Разработка бизнес-логики

После настройки скриптов версионирования можно перейти к написанию бизнес-логики. Решим классическую задачу для ветеринарной клиники — поиск подходящего ветеринара для будущего визита.

Как обычно, начнем с создания сервиса, который будет содержать бизнес-логику.

Мы хотим разделять декларацию и реализацию, поэтому создаем два объекта: интерфейс сервиса и класс реализации. Конечно, можно сделать это вручную в IDE, но проще воспользоваться Amplicode.

В контекстном меню New... выбираем Service/Component. В открывшемся окне ставим галочку Autowire by interface и нажимаем +, чтобы добавить интерфейс с именем VetScheduleService (пусть именно этот сервис отвечает за поиск свободного ветеринара). Amplicode заполнит имя класса реализации автоматически. Если реализация должна работать только в определенном профиле, можно указать его сразу. Жмем OK — Amplicode создаст и интерфейс, и класс реализации.

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

Однако использовать сущность визита в качестве параметра метода пока нельзя — визита еще не существует. Поэтому последним параметром определяем несуществующий класс VisitAppropriateDto. Ничего необычного — приступаем к реализации.

Заготовка метода findAppropriateVet()
Заготовка метода findAppropriateVet()

Создание DTO: генерация и маппинг

Чаще всего мы создаем DTO копированием уже существующего объекта. IDE отлично с этим справляется: удаляет лишнее, добавляет нужное. В качестве элемента от которого можно оттолкнуться обычно используются сущности или другие DTO.

Но у такого подхода есть неудобства:

  • Много ручных действий — особенно если мы хотим превратить mutable-сущность в record.

  • Сам процесс компоновки: приходится искать подходящую DTO с нужными полями и копировать их.

Работа с DTO кажется рутинной и утомительной. Казалось бы, AI должен решать такие задачи, но и ему приходится явно перечислять нужные поля, что порой сложнее, чем ручное копирование.

Что хотелось бы? Возможность быстро выбрать поля для DTO из базы — сущности или другой DTO. И со временем захочется указывать, как именно отображать ссылки и коллекции: flat, nested и т.д. Amplicode как раз это умеет.

Для создания DTO в Amplicode есть несколько вариантов. Можно воспользоваться контекстным меню New..., но мы пойдем другим путем.

В качестве третьего аргумента метода у нас уже указан несуществующий тип VisitAppropriateDto. Вызываем стандартное действие IDE для исправления некорректного кода и выбираем Create DTO... от Amplicode.

Quick-fix для создания DTO
Quick-fix для создания DTO

Откроется окно создания DTO. В качестве Domain entity указываем созданную ранее сущность визита, а тип результата выбираем Java Record. В нижней части окна появится дерево атрибутов. Это именно дерево: выбрав атрибут-ссылку на другую сущность/DTO/класс, можно выбрать поля и способ их отображения.

> Обратите внимание на поле Mapper. Amplicode умеет не только создавать DTO, но и генерировать функции маппинга для их дальнейшего использования — например, в контроллерах, чтобы преобразовать сущность в DTO или наоборот. Поддерживаются: MapStruct, ModelMapper, Custom Mappers.

Для нашей задачи нужны поля date и description. Отмечаем их и нажимаем OK. Amplicode создаст record с выбранными полями.

Если забыли что-то добавить, не проблема: открываем DTO, начинаем вводить название поля — Amplicode предложит недостающие атрибуты, так как знает связь между DTO и исходной сущностью.

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

Начнём набирать название метода для VetRepository и IDE покажет не только уже существующие, но и позволит создать новый метод налету. Тут же можно воспользоваться функцией Amplicode для создания derived-метода (описанной ранее, через удобный UI). Создаем метод поиска всех ветеринаров по списку специальностей.

Осталось определить id специальности, по которому выполняем поиск. Лучше вынести его в application.properties:

petclinic.appropriate.vet.speciality.id=2  

В сервисе добавляем поле с аннотацией @Value. Обычно здесь возникают ошибки в SpEL, даже несмотря на поддержку в IDE. Amplicode решает эту проблему: автоподстановка для Spring Properties работает так же, как для бинов. Начинаем вводить petcli..., выбираем petclinicAppropriateVetSpecialityId из подсказок — Amplicode сделает все остальное.

На этом метод сервиса готов. Пора опубликовать его в REST.

Доступ к приложению через REST

Создание любого API начинается с определения правил, по которым оно будет строиться. В каждой организации, в зависимости от проекта, они могут отличаться. Но обычно внешнее API строят в формате REST over HTTP(S). Давайте реализуем его.

Начнем с ветеринаров. Создадим RestController: в контекстном меню выбираем New → Rest/MVC Controller, указываем название VetRestController и путь /rest/vets, нажимаем OK.

Однако созданный метод не полностью решает задачу: он не возвращает 404, если объект с переданным id не найден. Это легко исправить, достаточно выбрасывать ResponseStatusException с кодом 404. Почему Amplicode не делает это по умолчанию? Потому что делегация — инструмент низкоуровневый, и findById() может использоваться для самых разных целей, не только для REST-контроллеров.

Если же нужны CRUD-методы контроллера, полностью соответствующие REST, в Amplicode есть отдельный инструмент для их генерации.

CRUD REST API: на автопилоте

Сгенерируем еще один метод getOne(), но на этот раз создадим DTO, содержащую информацию не только о ветеринаре, но и о его специальностях.

Открываем VetRestController. Вместо контекстного меню Generate воспользуемся Amplicode Designer — полезный инструмент для знакомства с возможностями Amplicode. Переходим в раздел Request Handling, выбираем метод Get One (by id). В открывшемся окне в качестве репозитория выбираем VetRepository. В поле DTO нажимаем + для создания новой, указываем VetMapper как маппер, а для поля specialities выбираем тип New Nested Class. Нажимаем OK. В поле Proxy service указываем VetService. Еще раз нажимаем OK.

Amplicode сгенерировал связывающий код, добавил методы репозитория, создал DTO и настроил методы маппинга. Учёл, что это именно CRUD REST API: для метода Get One возвращается 404, если объект по id не найден.

Теперь можно легко реализовать остальные CRUD-методы контроллера. Если вам нравится, как Amplicode генерирует код, можно воспользоваться действием по созданию полноценного CRUD Rest Controller (доступно в меню New...). В результате Amplicode создаст контроллер со всеми методами CRUD API, включая работу с коллекциями.

Как видим, запрос вернул 401. Заглянем в раздел Configuration в Amplicode Explorer. В проекте есть конфигурация Security — помните, в самом начале мы добавляли ее при генерации проекта. Даже если мы не определяли SecurityFilterChain, Spring-автоконфигурации сделали это за нас. Но как понять, в каком виде настроена Security? Искать нужную автоконфигурацию, читать документацию?

Достаточно развернуть конфигурацию Spring Security в Amplicode Explorer. В нашем случае автоконфигурация включает Form Login, Basic Auth и CSRF. Реализуем вариант Basic Auth + CSRF.

Spring Security конфигурация в Amplicode Explorer
Spring Security конфигурация в Amplicode Explorer

Сначала получим CSRF-токен. Так как у нас подключен Form Login, токен можно извлечь из страницы ответа — воспользуемся регулярным выражением:

val csrfToken by GET("http://localhost:8080/login") {  
} then {  
    val csrfRegex = """<inputs+name="_csrf"s+type="hidden"s+value="([^"]+)"s*/>""".toRegex()

    csrfRegex.find(body!!.string())?.groupValues?.get(1)
}

Как можно заметить, значение CSRF-токена сохранено в константу (ее можно вычислять лениво — полезно в сценариях с условными блоками).

Возвращаемся к ранее сгенерированному эндпоинту создания ветеринара и добавляем заголовок X-CSRF-TOKEN. Этого недостаточно — нужно еще авторизоваться.

Для Basic Auth в Connekt есть нативная поддержка. Поскольку в основе лежит Kotlin DSL, достаточно вызвать completion, начав набирать basi..., и выбрать basicAuth. Пользователь по умолчанию — user, пароль возьмем из логов приложения.

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

На этот раз сгенерируем запрос через Amplicode Explorer: в контекстном меню на endpoint getOne выбираем Generate request in Connekt (аналогичное действие доступно в любом файле Connekt в меню Generate). В сгенерированном запросе указываем id созданного ветеринара как параметр, добавляем CSRF-токен и авторизацию уже известными способами. Осталось убедиться, что фамилия в ответе совпадает с указанной при создании.

Это можно сделать и глазами, но в Connekt есть функциональность assertion. Начните писать asse..., выберите в completion assertThat, укажите ожидаемое и актуальное значение. Актуальное извлечем через jsonPath. Выполняем запрос:

Запрос выполнился без ошибок — значит, созданный ранее ветеринар действительно имеет фамилию «Ivanov». Конечно, сценарий не идеален: как минимум, пользователя и пароль стоит вынести в переменные окружения. Это всё также можно сделать. Читайте подробнее про возможности Connekt в этой статье.

Connekt — мощный инструмент: с его помощью можно реализовывать самые сложные сценарии. При этом простые вещи делаются просто, а сложные — настолько просто, насколько это возможно.

Теперь повторим сценарий в классическом Spring Boot-тесте. По сути, написанный сценарий уже является тестом: в нем есть assert, а сам сценарий, ничего не меняя, можно запустить на CI.

Spring Boot Web-тесты (MockMvc/@SpringBootTest)

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

В IntelliJ IDEA, помимо множества плагинов в JB Marketplace, есть два предустановленных плагина: AI Assistant и Junie. Оба хорошо справляются с написанием большинства тестов, но не всегда с первого раза результат совпадает с ожиданиями. Возникает выбор: продолжать «промптить» или воспользоваться классическими инструментами. Момент, когда стоит остановиться, каждый определяет сам — но он неизбежно наступит. Разберемся, какие инструменты будут доступны в этот момент.

За основу возьмем endpoint create. Сначала нужен тестовый класс. В Spring есть несколько подходов к тестированию web:

  • Sliced-тесты — контекст включает только компоненты web-слоя. Подробнее читайте в документации.

  • @SpringBootTest + MockMvc — поднимается полный контекст, упрощается работа с инфраструктурой (например, с security).

  • @SpringBootTest + TestRestTemplate — тесты, сопоставимые с вызовами через Connekt.

Выбор зависит от задачи, но чаще всего используют комбинацию @SpringBootTest и MockMvc — золотая середина: основной контекст поднят, ощущение реального приложения есть, при этом не нужно заботиться о web-инфраструктуре и реальном порте. Как создать такой тестовый класс?

Проще всего сгенерировать Spring Web Test от контроллера или его метода. Откройте контроллер (VetRestController), слева от наз��ания класса нажмите на иконку бина и в выпадающем списке выберите Generate Spring Web Tests.... В открывшемся окне напротив Target нажмите + (Create Web Test), укажите имя тестового класса и в качестве контекста выберите Spring Application Context. Ниже в списке методов контроллера отметьте create. Справа видно, что Amplicode корректно распознал конфигурацию Spring Security и CSRF. Снимите галочку Print results и выполните генерацию. Останется поправить body (например, фамилия "Petrov") и добавить утверждения.

Как и в сценарии с Connekt, нужно убедиться, что фамилия действительно совпадает с указанной в запросе на создание. Чтобы извлечь id из ответа, распарсим результат вызова endpoint с помощью ObjectMapper. Поскольку это Spring Boot-тест, нет необходимости делать дополнительный запрос — достаточно заавтовайрить VetRepository и получить ветеринара по id. Затем написать assert.

@Test  
public void create() throws Exception {  
    String vetCreateDto = """  
            {
                "lastName": "Petrov"
            }""";

    MvcResult response = mockMvc.perform(post("/rest/vets")  
                    .with(SecurityMockMvcRequestPostProcessors.csrf())  
                    .with(SecurityMockMvcRequestPostProcessors.user("user"))  
                    .content(vetCreateDto)  
                    .contentType(MediaType.APPLICATION_JSON))  
            .andExpect(status().isOk())  
            .andReturn();

    String responseContent = response.getResponse().getContentAsString();

    // Parse JSON to extract ID using ObjectMapper  
    ObjectMapper objectMapper = new ObjectMapper();  
    JsonNode jsonNode = objectMapper.readTree(responseContent);  
    Long createdVetId = jsonNode.get("id").asLong();

    Vet vet = vetRepository.findById(createdVetId).orElseThrow();

    assertThat(vet.getLastName()).isEqualTo("Petrov");  
}

Как видно, в IDE есть мощные инструменты тестирования — на случай, если тесты все же пришлось писать вручную.

Остается еще одна задача перед деплоем на test/production-контуры: рассказать, как работает наш API. Пора подготовить схему OpenAPI.

Генерация OpenAPI-схемы

Решить эту задачу можно по-разному: аннотировать методы дополнительными аннотациями, подготовить описание вручную или сгенерировать автоматически. И IntelliJ IDEA Ultimate, и Amplicode включают удобные инструменты генерации OpenAPI-схемы на основе описания в RestController. На выходе можно выбрать формат (YAML/JSON) и область, для которой выполнить генерацию.

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

Вызвать генерацию можно так же, как и для тестов — из gutter-иконки. Откройте VetRestController, нажмите на иконку и выберите действие Generate OpenAPI Schema. В открывшемся окне задайте формат, область и место сохранения результата. После нажатия OK схема будет сгенерирована. В нашем случае это первая генерация, поэтому сохраняем результат в файл и публикуем вместе с приложением.

Приложение создано, бизнес-логика реализована, REST готов — самое время заняться публикацией приложения.

Продакшн-деплой

Умение деплоить приложение в production всегда было важным навыком разработчика. Еще 3–5 лет назад часто использовали серверы приложений или UberJar. Сейчас стандартом де-факто стал Kubernetes. Он не единственный, но явно доминирующий.

Кластер Kubernetes можно получить разными способами. Для разработки и тестирования удобно использовать локальные решения — Minikube или Rancher. Production-кластер проще всего заказать у облачного провайдера — это значительно дешевле, чем разворачивать и поддерживать его своими силами (если, конечно, речь не о большой компании, где этим занимается внутренняя команда).

Важно учитывать, что Kubernetes у разных провайдеров может отличаться. Идеальный сценарий выглядит так:

  • подготавливаем конфигурацию локально (быстрый фидбек при изменениях),

  • деплоим приложение в Kubernetes выбранного облака без изменений,

  • при проблемах (цена, стабильность) переносим решение к другому провайдеру.

На практике все не так гладко, но не критично. Часть проблем решается инструментами.

Существует множество решений, упрощающих работу с конфигурациями. Два самых популярных — Helm и Kustomize. Helm, помимо поддержки разных окружений (test, prod, разные облака), является пакетным менеджером. Это упрощает деплой приложения и всей необходимой инфраструктуры. В дальнейшем мы будем использовать именно Helm.

Подключение к Kubernetes-кластерам в IDE

Для тестирования конфигурации нужно подключиться к кластеру Kubernetes. Это можно сделать средствами IDE:

  • в панели Services вызовите контекстное меню элемента Kubernetes (убедитесь, что установлен и включен Kubernetes-плагин),

  • выберите Add Clusters,

  • Если используется локальный кластер, выберите From Default Directory. IDE просканирует доступные Kubernetes, отобразит их в окне — останется выбрать нужный кластер.

После выбора он появится в панели Services. IDEA предоставляет удобные средства анализа кластера: можно просматривать ресурсы, логи, подключаться к контейнерам и многое другое.

Если кластер новый, в нем будут только ресурсы установщика. Самое время заняться деплоем приложения — начать стоит с инфраструктуры.

Инфраструктура: PostgreSQL через Helm

В нашем случае приложению нужна только база данных — PostgreSQL. Развернуть ее в Kubernetes можно с помощью Helm. Есть два варианта: развернуть как сервис или как оператор. Оператор имел бы смысл, если бы мы строили собственное облако.

В репозитории Helm-чартов ArtifactHub доступно множество пакетов PostgreSQL. С одной стороны, это хорошо, с другой — возникает вопрос, какой выбрать. В ArtifactHub нет метки «официальный», как на DockerHub, но указаны вендоры — Bitnami, Celtic и т.д. Долгое время чарт от Bitnami был выбором по умолчанию, но недавно они изменили политику распространения: теперь доступны только latest-версии. Сообщество ждет, кто займет их место, но для нас сейчас это не критично — используем Bitnami.

Поставить PostgreSQL в кластер можно простой командой helm install, указав пакет. Но этот способ ограничен: все параметры конфигурации нужно передавать прямо в командной строке. Удобнее указать PostgreSQL как зависимость в собственном Helm-чарте. Для этого создадим пустой Helm Chart.

В IntelliJ IDEA это делается через контекстное меню New…. Обратите внимание: меню содержит два варианта создания чарта — стандартный и от Amplicode.

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

  • Amplicode позволяет сгенерировать пустой чарт, Spring Boot-чарт и т.д.

Выбираем действие от Amplicode, тип — Empty Helm Chart, имя — postgresql. Далее добавляем зависимость.

Также список доступных для генерации сервисов можно найти в панеле Amplicode Designer:

Amplicode Designer для Helm
Amplicode Designer для Helm

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

Осталось задеплоить конфигурацию.

  • В Amplicode Explorer откройте контекстное меню для postgresql и выберите Run.

  • Укажите namespace (если его нет, он создастся автоматически).

Amplicode запустит Helm с нужными параметрами (Helm должен быть установлен). Проверить успешный запуск можно в панели Services — раздел Workloads.

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

Деплой Spring Boot приложения (Helm, Ingress)

Точно так же, как мы создавали Helm для PostgreSQL, можно создать Helm для нашего Spring Boot-приложения. Отличие лишь в том, что на втором шаге нужно выбрать Spring Boot Application вместо Empty Helm Chart. В открывшемся окне выбираем приложение, проверяем, что Amplicode корректно считал конфигурацию actuator для readiness/liveness-проб, а также порт приложения.

Здесь же можно разрешить внешний доступ к приложению — установите галочку Enable Ingress. Ingress требует DNS-имя и установленный в кластере Ingress-контроллер. Большинство провайдеров Kubernetes предустанавливают контроллер, интегрированный с их инфраструктурой. Локальные инсталляции часто включают Traefik или NGINX. Если контроллер отсутствует, его можно поставить из Helm Chart, как PostgreSQL.

Сгенерированный Helm Chart уже учитывает специфику Spring Boot-приложения, но его нужно доработать. В частности, в values.yaml отсутствуют параметры конфигурации DataSource. Чтобы добавить их, редактируем шаблон deployment.yaml.

Helm-шаблоны используют Go Template, убедитесь, что включен соответствующий плагин. Плагин JetBrains предоставляет автодополнение, навигацию и другие удобства. Amplicode дополняет их и понимает специфику Spring Boot.

Переопределять свойства Spring Boot можно разными способами, самый популярный — через переменные окружения.

В deployment.yaml в секцию env добавляем переменные. Для конкретного свойства можно:

  • воспользоваться действием Amplicode Wrap property value into environment variable,

  • либо использовать стандартное преобразование свойства в переменную окружения.

Выберем второй способ. Автодополнение IDE здесь не помогает, но Amplicode подсказывает доступные опции. Для name выбираем SPRING_DATASOURCE_URL. Значение берем напрямую из values.yaml, выбрав его через completion. После этого задаем базовое значение — Amplicode предложит быстрое исправление. Аналогично добавляем переменные для имени пользователя и пароля.

Запускаем конфигурацию так же, как раньше:

  • в Amplicode Explorer для Helm Chart вызываем действие Run,

  • указываем тот же namespace, куда был задеплоен PostgreSQL.

Ну а как проверить работу приложения мы уже знаем – через Connekt.

Если что-то пошло не так, в панели Services можно посмотреть логи приложения. Если приложение задеплоено, но не отвечает по имени, можно сделать port forwarding для ресурса — действие доступно в контекстном меню.

Можно выдохнуть: мы прошли полный цикл — от создания приложения до деплоя в production.

Поддержка устаревших версий IntelliJ IDEA Ultimate (2022.x)

Несмотря на то, что актуальная версия Amplicode поддерживает только три последних мажорных версии IntelliJ IDEA, можно установить одну из предыдущих версий Amplicode и получить улучшение даже для outdated инструмента.

Важно: все новые фичи, вышедшие после Amplicode 2024.1, в устаревших IDE недоступны. Поэтому мы крайне рекомендуем вам рассмотреть переезд с устаревших версий IDE на актуальную.
Если ваша команда пока не готова обновляться — свяжитесь с нами через Telegram-чат или форму на сайте, и мы поможем вам спланировать переезд.

Установив Amplicode в IntelliJ IDEA Ultimate 2022.x, вы получите не только функции, описанные выше, но и возможности более поздних версий IDE. Иными словами, Amplicode в IntelliJ IDEA Ultimate 2022.x дает часть функционала версии 2025.x. Попробуйте и убедитесь сами.

Заключение

Даже не смотря на то, что эта статья получилась просто огромной, у нас всё равно не получилось перечислить все возможности, которые даёт Amplicode в дополнение к функциональности IntelliJ IDEA Ultimate. Например, мы ничего не рассказали про поддержку Terraform, Kafka, MongoDB, лишь вскользь упомянули поддержку Spring Security, не показали всех возможностей для работы со Spring Web и много чего ещё.

Но всё же лучший способ оценить поддержку именно ваше стека со стороны Amplicode – это попробовать его в действии! Устанавливайте Amplicode абсолютно бесплатно уже сейчас, а чтобы получить от инструмент максимум – активируйте триальную подписку на Amplicode PRO!

Ну и подписывайтесь на наш ТГК, там мы рассказываем про Amplicode, Spring и всё что с ними связано!

Статья также опубликована на нашем сайте.

Комментарии (4)


  1. ant1free2e
    03.10.2025 11:39

    было бы здорово если бы Amplicode Designer или Docker Compose Designer умели строить управляемые диаграммки из ямлов как в n8n или bpmn


  1. akardapolov
    03.10.2025 11:39

    Есть поддержка Spring Data JDBC?


    1. ikuchmin Автор
      03.10.2025 11:39

      да, в текущих релизах поддержка Spring Data JDBC уже имеется, решили не описывать ее в данной статье, поскольку обзор получился и так огромный. Планируем в конце ноября сделать онлайн митап по Spring Data JDBC, где подробнейшим образом расскажем про Amplicode поддержку. Ну и в предверии конечно напишем пару статей описывающих интересные моменты и то как их учитывает Amplicode. Поэтому рекомендую подписаться на канал: https://t.me/amplicode


  1. oldzoomer
    03.10.2025 11:39

    Мне нравится и OpenIDE, и Amplicode, но будет ли нечто вроде Cursor/Roo Code, только под OpenIDE? Просто надо бы уже иметь нормальную агентную систему для JB-based IDE.