2 октября 2025 г.

Amplicode – идеальное дополнение к IntelliJ IDEA Ultimate. Огромный гайд для Spring-разработчика

Все уже прекрасно понимают, что 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 минут на чтение, вы сэкономите часы в будущем.

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

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


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

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

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

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

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

Появится ошибка: не сконфигурирован 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 — и вы увидите все актуальные свойства, их значения, а также значения по умолчанию, если они не заданы.

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

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

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

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

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

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

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

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

  • версию образа,
  • имя базы данных, пользователя и пароль,
  • где смонтировать volume,
  • как настроить healthcheck.

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

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

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

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

Теперь можно запустить сервис. Сначала запускаем Docker Compose через Run... в IDE (кстати, в IntelliJ IDEA отличный Docker-клиент), затем запускаем приложение тем же способом.

Обзор и навигация по проекту

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

Смотрим структуру файлов, проверяем зависимости в build.gradle или pom.xml , вспоминаем сущности, REST-эндпоинты, подключенные Kafka-топики. После этого запускаем Docker Compose и приложение.

А теперь оглянемся: сколько файлов пришлось открыть, чтобы «вспомнить всё»? Не один десяток. И это не разовая история — каждый день, по нескольку раз, мы задаем себе вопросы:

  • как связаны сущности?
  • есть ли нужный эндпоинт?
  • в каком он контроллере?

Каждый раз это поиск и переход в конкретный файл.

Зачем вообще нужны файлы в IntelliJ IDEA Ultimate, если список endpoints есть в панели Endpoints, а сущности — в панели Persistence?

Все верно, но проблема в другом: Spring Boot-приложение — это система связанных компонентов. Их нужно воспринимать именно так, а не как набор отдельных файлов. Тем более, что приложение на Spring Data JPA + Spring MVC отличается от приложения на Spring Data JDBC или MyBatis.

Именно здесь помогает Amplicode Explorer. В любой момент вы можете открыть его и быстро восстановить недостающий контекст.

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

Движемся дальше. Сложно представить приложение, которое не работает с данными. Есть мнение, что современный бэкенд-разработчик в основном «гоняет» данные между 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 Designer Repository 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 . Ничего необычного — приступаем к реализации.

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

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

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

  • Много ручных действий — особенно если мы хотим превратить mutable-сущность в record.
  • Сам процесс компоновки: приходится искать подходящую DTO с нужными полями и копировать их.

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

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

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

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

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

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

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

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

Умная инжекция во время набора кода

После описания метода в интерфейсе осталось написать реализацию. В современных условиях в качестве реализации такого метода было бы интересно вызвать AI, передав ему информацию о ветеринарах, их расписаниях и описании визита, чтобы он подобрал подходящего кандидата. Конечно, при этом нужно было бы добавить формальные проверки: наличие нужной специальности, свободного времени и т.д. Но такой сценарий тянет на отдельную статью. Мы реализуем более простую логику: будем искать ветеринара с заранее известной специальностью, например «Хирургия».

Для этого нужно заавтовайрить репозиторий ветеринаров в сервис. Сделать это можно вручную: описать поле и добавить его в конструктор (или воспользоваться Lombok). Но с Amplicode есть ещё один более удобный способ – умная инжекция во время набора кода.

Это очень удобно:

  • не нужно переходить в начало файла и прописывать поле вручную;
  • если репозиторий еще не создан, IDE предложит его сгенерировать;
  • при выборе подсказки IDE сразу выполнит автовайринг, учитывая, используется ли Lombok.

В теле метода начинаем вводить vetRep... IDE предложит создать VetRepository , а затем сразу добавить его в сервис.

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

Начнём набирать название метода для 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.

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

CRUD REST API: пошаговая реализация

Определим список методов для CRUD API:

  • getOne(id) — получить ветеринара по идентификатору
  • getList(filter) — получить список ветеринаров с фильтрацией
  • create(prototype) — создать ветеринара
  • update(id, new state) — обновить информацию о ветеринаре
  • patch(id, diff) — частично обновить информацию о ветеринаре
  • delete(id) — удалить ветеринара

Эти операции соответствуют методам нашего JPA-репозитория и представляют собой делегацию вызова из контроллера в репозиторий (или сервис) с маппингом DTO ↔ сущность. Рассмотрим подробнее операцию create , так как она требует маппинга и аргумента, и результата.

Метод create в контроллере будет вызывать save в репозитории. save принимает сущность и возвращает обновленную сущность. В контроллере нужно смапить аргумент на сущность, а результат — обратно на DTO.

В главе про DTO мы упоминали, что Amplicode умеет генерировать методы маппинга — самое время их использовать. Нужно создать две DTO: одну для аргумента, другую — для результата. Через New → DTO выбираем Vet как Domain entity, отмечаем все поля, кроме id . В поле Mapper нажимаем + , выбираем MapStruct. Если нужной библиотеки нет в проекте, Amplicode добавит ее автоматически. После OK будут созданы DTO и интерфейс MapStruct. Аналогично создаем DTO для результата.

Метод контроллера создаем через live template post : начните печатать post или @post , выберите подсказку, IDE сгенерирует шаблон POST-запроса. В пути оставляем базовый, в качестве реквеста и респонса указываем созданные DTO. Не забудьте про @RequestBody для аргумента.

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

Спойлер: полезные приемы IDE и Amplicode:

  • Напишите имя аргумента, поставьте точку, начните набирать ...mapTo , выберите .mapToEntity . Amplicode преобразует вызов в VetMapper и заинжектирует его.
  • Наберите .var , выберите подсказку — IDE создаст переменную и выведет тип.
  • Вызовите .save на entity — Amplicode преобразует выражение в вызов save и заинжектирует репозиторий.
  • Сохраните результат в переменную и вызовите .mapToVetCreatedDto .
  • Наберите .return , чтобы автоматически добавить return .

Даже не смотря на то, что мы оперировали высокоуровневыми объектами, сразу создавая не просто классы, а DTOшки, мапперы, контроллеры и т.д., мы потратили довольно много времени.

В Amplicode есть функциональность, которая позволяет сделать все это еще проще.

Кастомный API и делегация между бинами

Реализуем следующий метод из нашего списка — getOne(id) . На этот раз воспользуемся функциональностью делегирования в Amplicode. Делегирование доступно из любого Spring Bean в другой. Amplicode учитывает специфику бинов, предлагая дополнительные возможности при делегировании, например, из репозитория или в контроллер.

Нам нужно делегировать метод VetRepository#findById в VetRestController , используя в качестве промежуточного сервиса (будем называть его прокси-сервисом) VetService. Для этого открываем VetRestController, вызываем контекстное меню Generate и выбираем действие Delegate from. Если открыть сервис или компонент, будет доступно также Delegate to.

В открывшемся окне выбираем бин, методы которого хотим делегировать, — в нашем случае VetRepository . Ставим галочку Use proxy service, в качестве сервиса указываем VetService . Выбираем метод findById() , настраиваем делегацию: в Return type выбираем ранее созданное DTO (или создаем новое с маппингом) и отмечаем Unwrap Optional. Нажимаем OK. Amplicode сгенерирует весь необходимый код во всех компонентах в том же виде, как мы делали вручную в предыдущей главе.

Однако созданный метод не полностью решает задачу: он не возвращает 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, включая работу с коллекциями.

Приступим к проверке того, что накодили. Для этого есть несколько способов, рассмотрим два самых популярных:

  • Вызов API любым клиентом (Postman/cURL/Connekt).
  • Написание Spring Boot тестов.

HTTP-клиент в IDE – лучше, чем Postman

Для начала попробуем вызвать наш API с помощью внешнего HTTP-клиента. В IntelliJ IDEA есть встроенный HTTP-клиент. Его важная особенность — описание запроса максимально близко по структуре к протоколу. Это значит, что для большинства запросов, которые корректно отрабатывают в IDE, можно воспользоваться консольной утилитой telnet : скопировать запрос из IDE и получить результат. Это было преимуществом, когда клиент только добавили в IDE. Но время шло, аппетиты пользователей росли, и нужно было искать решение, как их удовлетворить. Чего хотели пользователи:

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

Пользователям нужен был не просто клиент для отдельных запросов, а программируемый клиент. В результате в HTTP-клиенте появились возможности программирования на JS. В итоге мы получили мощный инструмент: зная JS и API, можно реализовать самые сложные сценарии. Однако смешение текстового протокола и программирования на JS стало частым источником сложностей.

### Request with Loop Support, variables from environment file
POST https://examples.http-client.intellij.net/post

Content-Type: application/json
{
  "clientId": ,
  "firstName": ""
}
> {%
  let clientId = request.templateValue(0)
  client.log(`Client id: ${clientId}`)
  let firstName = request.templateValue(1)
  client.log(`First name is: ${firstName}`)
  client.test(`Client ${clientId} has initial firstName ${firstName}`, () => {
    let currentFirstName = jsonPath(response.body, "$.json.firstName")
    client.assert(firstName == currentFirstName)
  })
%}

Казалось бы, проще было бы изначально описывать запросы DSL поверх известного языка программирования. Примут ли его? Какой язык выбрать — Groovy, JS? На первый вопрос ответит время, а на второй сейчас ответ очевиден: таким языком должен быть Kotlin. Но HTTP-клиента на Kotlin DSL, интегрированного в IDE до некоторых пор не было. Но не так давно именно такой клиент появился в Amplicode! Open-source клиент Connekt. Давайте воспользуемся им.

Начнем с генерации запроса от существующего эндпоинта — метода создания ветеринара. Найдя соответствующий метод в контроллере, кликните по gutter-иконке напротив него и в выпадающем списке выберите действие Generate request in Connekt. В результате Amplicode сгенерирует Connekt-описание, включая шаблон body , в scratch-файле, по аналогии со стандартным клиентом. Напротив каждого Connekt-запроса в IDE доступна иконка запуска — воспользуемся ей.

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

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

Сначала получим 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:

После генерации видно, что зависимость добавлена точно так же, как если бы мы делали это вручную, а в 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 и всё что с ними связано!