Разработка корпоративных решений и интранет-порталов на базе Liferay требует управления сложной экосистемой, включая инициализацию серверов приложений, сборку различных модулей, работу с базой данных и REST-эндпоинтами. Чтобы ускорить разработку, Liferay предоставляет специализированный инструментарий в форме плагинов для популярных систем сборки, таких как Gradle и Maven. В этой заметке мы представим краткий обзор некоторых таких плагинов, которые позволяют автоматизировать рутинные операции и сделать процесс разработки эффективнее. Сегодня в нашей подборке 4 плагина
1. com.liferay.portal.tools.bundle.support
Представляет собой плагин для инфраструктуры, управления окружением и CI/CD. Реализует парадигму «Инфраструктура как код», позволяя избавиться от ручного скачивания архивов портала, распаковки и самостоятельного копирования конфигураций. Этот плагин берет под свой контроль весь жизненный цикл Liferay бандла. На основе указанного URL или версии плагин скачивает сборку сервера (например, Tomcat bundle) и кэширует архив в локальной файловой системе сборщика. Также плагин полностью очищает целевую директорию и разворачивает чистый инстанс Liferay, убирая все временные файлы, которые могут помешать деплою, исключая тем самым появление мусорных артефактов и кэша от старых запусков. Плагин также может накладывать файлы настроек (такие как portal-ext.properties или system-ext.properties) поверх чистого лайфрея в зависимости от выбранного профиля сборки (например, local, dev, test). Конфигурация разбивается на шаги (executions) в рамках конкретных фаз жизненного цикла (покажем пример для maven):
<project xmlns="http://apache.org"
xmlns:xsi="http://w3.org"
xsi:schemaLocation="http://apache.org http://apache.org">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.liferay</groupId>
<artifactId>liferay-workspace-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<liferay.portal.tools.bundle.support.version>3.7.10</liferay.portal.tools.bundle.support.version>
<liferay.bundle.dir>${project.basedir}/bundles</liferay.bundle.dir>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.liferay</groupId>
<artifactId>com.liferay.portal.tools.bundle.support</artifactId>
<version>${liferay.portal.tools.bundle.support.version}</version>
<executions>
<!-- Полная очистка перед сборкой новой среды -->
<execution>
<id>clean-local-bundle</id>
<!-- Привязываем к стандартной фазе clean -->
<phase>clean</phase>
<goals>
<goal>clean-bundle</goal>
</goals>
</execution>
<!-- Скачивание и разворачивание чистого Liferay Bundle -->
<execution>
<id>initialize-liferay-server</id>
<!-- Привязываем к фазе инициализации проекта -->
<phase>initialize</phase>
<goals>
<goal>init-bundle</goal>
</goals>
<configuration>
<!-- URL для загрузки дистрибутива -->
<bundleURL>your URL</bundleURL>
<!-- Куда распаковывать -->
<destDir>${project.basedir}</destDir>
</configuration>
</execution>
<!-- Деплой -->
<execution>
<id>deploy-global-configs</id>
<!-- Выполняется на этапе валидации или перед деплоем модулей -->
<phase>validate</phase>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<bundleDir>${liferay.bundle.dir}</bundleDir>
<!-- Копируем кастомные конфиги -->
<configsDir>${project.basedir}/configs/local</configsDir>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Кроме того, возможно использование локального бандла (уже собранного), что особенно актуально при использовании Wildfly:
<configuration>
<appServerType>wildfly</appServerType>
<appServerBundleDir>${project.basedir}/bundles/wildfly</appServerBundleDir>
<!-- директория Liferay Home для этого бандла -->
<liferayHome>${project.basedir}/bundles</liferayHome>
</configuration>
2. com.liferay.portal.tools.service.builder
Представляет собой плагин для генерации слоя доступа к данным (Java-классы, интерфейсы, SQL-скрипты, Hibernate/Spring-конфигурации) на основе одного XML-файла описания. Создает интерфейсы и базовые реализации для сервисов, генерирует DDL, обновляет базу и многое другое:
<plugin>
<groupId>com.liferay</groupId>
<artifactId>com.liferay.portal.tools.service.builder</artifactId>
<version>1.0.420</version>
<executions>
<execution>
<id>generate-service</id>
<!-- Привязываем генерацию к фазе generate-sources, до компиляции Java -->
<phase>generate-sources</phase>
<goals>
<goal>build-service</goal>
</goals>
<configuration>
<!-- Главный файл с описанием сущностей и базы данных -->
<inputFile>${project.basedir}/src/main/resources/META-INF/service.xml</inputFile>
<!-- Куда сгенерируются интерфейсы и DTO -->
<apiDir>${project.parent.basedir}/my-app-api/src/main/java</apiDir>
<!-- Куда сгенерируется бизнес-логика и реализация -->
<implDir>${project.basedir}/src/main/java</implDir>
<!-- Папка для генерации SQL-скриптов создания таблиц и индексов -->
<sqlDir>${project.basedir}/src/main/resources/META-INF/sql</sqlDir>
<!-- Включать ли генерацию REST/JSON веб-сервисов -->
<buildRemoteService>true</buildRemoteService>
<!-- Включать ли генерацию локальных Java-сервисов -->
<buildLocalService>true</buildLocalService>
</configuration>
</execution>
</executions>
</plugin>
Чтобы плагин сработал, ему нужен файл конфигурации, где разработчик декларативно описывает сущности базы данных и их связи. Плагин же создает сотни строк сопутствующего кода. Вот минимальный пример файла src/main/resources/META-INF/service.xml для таблицы БД:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 7.4.0//EN" "http://liferay.com">
<service-builder dependency-injector="ds" package-path="com.example.myapp">
<namespace>MYAPP</namespace>
<!-- Первичный ключ -->
<column name="bookId" type="long" primary="true" />
<!-- Поля таблицы -->
<column name="title" type="String" />
<column name="author" type="String" />
<column name="createDate" type="Date" />
<!-- Индекс для быстрого поиска по автору -->
<finder name="Author" return-type="Collection">
<finder-column name="author" />
</finder>
</service-builder>
3. com.liferay.portal.tools.rest.builder
Представляет собой плагин для генерации API (эндпоинты, схемы запросов/ответов). Разработчик описывает контракт своего API в стандартном формате OpenAPI (YAML), а плагин автоматически генерирует JAX-RS эндпоинты, DTO-модели, валидацию и Jackson-маппинг. Разработчику остаётся только написать бизнес-логику в классах реализации. Кроме того, плагин автоматически разворачивает эндпоинты в интерфейсе Swagger UI портала, делая API доступным для тестирования фронтенд-разработчиками сразу после деплоя бандла. Подключается так:
<plugin>
<groupId>com.liferay</groupId>
<artifactId>com.liferay.portal.tools.rest.builder</artifactId>
<version>1.0.475</version>
<executions>
<execution>
<id>generate-headless-api</id>
<phase>generate-sources</phase>
<goals>
<goal>build</goal>
</goals>
<configuration>
<!-- Базовая папка, где лежат YAML схемы (rest-config.yaml, rest-openapi.yaml) -->
<baseDir>${project.basedir}</baseDir>
<!-- Относительный путь к подмодулю API, куда попадут сгенерированные интерфейсы -->
<apiDir>../my-headless-api/src/main/java</apiDir>
<!-- Путь в текущем модуле, куда попадет реализация REST -->
<implDir>src/main/java</implDir>
</configuration>
</execution>
</executions>
</plugin>
Для генерации API требуются два файла в модуле:
- rest-openapi.yaml -- стандартное описание путей, методов (GET/POST/PUT) и моделей данных по спецификации OpenAPI 3.0.
openapi: 3.0.0
info:
title: "My Custom API"
version: v1.0
paths:
/todos:
get:
operationId: getTodosPage
description: "Получить список задач"
responses:
200:
description: "Успешный ответ"
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Todo"
components:
schemas:
Todo:
type: object
properties:
id:
type: integer
format: int64
title:
type: string
completed:
type: boolean
- rest-config.yaml -- служебный файл Liferay, задает метаданные плагина, включая базовые пакеты, автора и системный контекст для OSGi:
apiPackagePath: "com.example.headless.api"
author: "Liferay Developer"
clientDir: "../my-headless-client/src/main/java" # если нужен клиент
compatibilityVersion: "7.4.0"
implPackagePath: "com.example.headless.internal"
jaxRsApplicationBaseUri: "/my-custom-api"
jaxRsApplicationName: "MyCustomAPI"
4. com.liferay.css.builder
Представляет собой плагин, который компилирует файлы стилей Sass (.scss) в стандартный CSS. В экосистеме Liferay этот плагин критически важен при сборке кастомных тем оформления, а также при стилизации отдельных портлетов и UI-компонентов. Он автоматически подтягивает глобальные стили ядра Liferay, обрабатывает импорты, миксины, переменные и минифицирует итоговый код. То есть CSS Builder предстает как Java-обертка над компилятором Sass, полностью интегрированная в сборочные контейнеры Gradle и Maven. Подключение на примере Maven:
<plugin>
<groupId>com.liferay</groupId>
<artifactId>com.liferay.css.builder</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>compile-sass-to-css</id>
<!-- Привязываем компиляцию стилей к фазе генерации ресурсов -->
<phase>generate-resources</phase>
<goals>
<goal>build</goal>
</goals>
<configuration>
<!-- Директория, где лежат исходные файлы .scss -->
<docRootDir>${project.basedir}/src/main/resources/META-INF/resources</docRootDir>
<!-- Подкаталог внутри docRootDir, где непосредственно искать .scss файлы -->
<inputDir>/</inputDir>
<!-- Куда складывать скомпилированные .css файлы -->
<outputDir>/</outputDir>
<!-- Включать ли генерацию Source Maps для удобной отладки в браузере -->
<generateSourceMap>true</generateSourceMap>
<!-- Стили, которые нужно исключить из прямой компиляции -->
<compilerExcludes>**/_*.scss</compilerExcludes>
<!-- Пути к сторонним Sass-библиотекам или темам -->
<importPaths>
<importPath>${project.basedir}/src/main/resources/META-INF/resources/node_modules</importPath>
</importPaths>
</configuration>
</execution>
</executions>
</plugin>
Итог
В заключение отметим, что комбинация этих четырех плагинов закрывает базовые потребности команды разработки, обеспечивая автоматизацию проекта на всех уровнях: от инфраструктурного слоя до баз данных, сетевых интерфейсов и визуального отображения.