В Liferay публикаторы контента (Content Display Templates) используются для визуализации и форматирования данных, полученных из различных источников. Как правило, они реализуются с помощью шаблонов на FreeMarker (FTL) и применяются для вывода списков сущностей, результатов поиска, фильтров и прочих визуальных компонентов.
Ручное добавление таких шаблонов через интерфейс администратора может быть неудобным и подверженным ошибкам. Главной причиной создания данного модуля стало стремление к полной автономности Liferay-модулей: после их деплоя в систему больше не требуется ручного вмешательства для создания или обновления шаблонов.
Структура решения
Решение включает:
- .properties-файл со списком шаблонов и их метаданными;
- FTL-файлы самих шаблонов;
- OSGi-модуль, который загружает шаблоны, проверяет их наличие и обновляет/создаёт при необходимости.
Пример конфигурационного файла
Файл templates.properties содержит информацию о шаблонах:
TEST_TEMPLATE_KEY=Тестовый публикатор,adt/test_publisher.ftl,1.0,com.liferay.portal.search.web.internal.result.display.context.SearchResultSummaryDisplayContext
Каждая строка описывает шаблон и состоит из:
- Ключа шаблона (templateKey);
- Имени (templateName);
- Пути к FTL-файлу (templatePath);
- Версии (templateVersion);
- Класса отображения (templateClassName).
Компоненты модуля
TemplateData
Класс-обёртка для метаданных шаблона:
public class TemplateData {
private String templateKey;
private String templateName;
private String templatePath;
private String templateVersion;
private String templateClassName;
public TemplateData(String templateKey, String templateName, String templatePath, String templateVersion, String templateClassName) {
this.templateKey = templateKey;
this.templateName = templateName;
this.templatePath = templatePath;
this.templateVersion = templateVersion;
this.templateClassName = templateClassName;
}
// Геттеры
}
ResourceLoader
Загрузка FTL-файлов и .properties:
public String loadTemplate(InputStream inputStream) throws Exception {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
public Properties loadTemplateProperties(InputStream inputStream) throws IOException {
Properties properties = new Properties();
try (Reader reader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8)) {
properties.load(reader);
}
return properties;
}
TemplateCreator
Создание и обновление шаблонов:
public void createTemplate(Group group, long resourceClassNameId, TemplateData templateData, InputStream inputStream) {
// ...
ddmTemplateLocalService.addTemplate(
UserLocalServiceUtil.getDefaultUserId(group.getCompanyId()),
group.getGroupId(),
PortalUtil.getClassNameId(templateData.getTemplateClassName()),
0,
resourceClassNameId,
templateData.getTemplateKey(),
nameMap,
null,
DDMTemplateConstants.TEMPLATE_TYPE_DISPLAY,
null,
"ftl",
templateScript,
false,
false,
null,
null,
serviceContext
);
}
TemplateRegistrator
Главная точка входа — регистрация шаблонов:
public List<TemplateData> getTemplateList(InputStream inputStream) {
Properties properties = resourceLoader.loadTemplateProperties(inputStream);
List<TemplateData> templates = new ArrayList<>();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
String[] parts = value.split(",", 4);
if (parts.length == 4) {
templates.add(new TemplateData(key, parts[0].trim(), parts[1].trim(), parts[2].trim(), parts[3].trim()));
}
}
return templates;
}
Проверка существования и сравнение версий шаблонов:
if (template.getTemplateKey().equals(newTemplate.getTemplateKey())) {
if (Double.parseDouble(template.getVersion()) < Double.parseDouble(newTemplate.getTemplateVersion())) {
templateCreator.updateTemplate(template, newTemplate, inputStream);
}
found = true;
}
Использование
- Поместите .ftl шаблоны в resources/adt/.
- Укажите шаблоны в templates.properties.
- При загрузке модуля вызовите getTemplateList() и затем для каждого шаблона вызовите addTemplate(...).
Это можно сделать вручную или автоматически в @Activate-методе OSGi-компонента.