Эта статья является обновлением моей предыдущей статьи, посвящённой встраиванию портлетов в тему Liferay 6.2, т.к. в новой версии портала подход и синтаксис немного изменились, и старые способы попросту не работают.
Два способа встроить портлет в тему
Итак, в Liferay 7.2 у вас есть два способа встроить портлет в шаблон темы.
Способ 1. Вставка веб-контента по имени класса и действию.
<@liferay_portlet["runtime"]
portletProviderAction=portletProviderAction.ADD
portletProviderClassName="com.liferay.journal.model.JournalArticle"
defaultPreferences="${defaultPortletPreferences}"
/>
Способ 2. Вставка веб-контента по имени портлета:
<@liferay_portlet["runtime"]
portletName="com_liferay_journal_content_web_portlet_JournalContentPortlet"
defaultPreferences="${defaultPortletPreferences}"
/>
В примере специально приведена вставка одного и того же портлета - отображения сетевого контента. То есть результат в обоих случаях будет одинаков. Разберём каждый способ подробнее.
Встраивание портлета по имени класса и типу действия
Встроить портлет в тему теперь можно, объявив имя класса (entity type) и тип действия (action). Портал сам найдёт подходящий портлет с наивысшим рангом (service.ranking). В примере ниже встраивается портлет переключения языков.
<@liferay_portlet["runtime"]
defaultPreferences="${languagePortletPreferences}"
portletProviderAction=portletProviderAction.VIEW
portletProviderClassName="com.liferay.portal.kernel.servlet.taglib.ui.LanguageEntry"
/>
Здесь следует пояснить, как именно портал ассоциирует портлеты с типами сущностей. Обратимся к к исходникам портлета SiteNavigationLanguagePortlet.
com.liferay.site.navigation.language.web.internal.portlet.SiteNavigationLanguagePortlet.java
com.liferay.site.navigation.language.web.internal.portlet.SiteNavigationLanguageViewPortletProvider.java
В одном пакете с классом портлета лежит класс - SiteNavigationLanguageViewPortletProvider. Он занимается сопоставлением типа сущности, действия и портлета.
Согласно конвенции об именовании, приведённой на сайте Liferay, этот класс должен называться SiteNavigationLanguageEntryViewPortletProvider (тип сущности + действие + PortletProvider). Но как мы видим на практике, разработчики сделали выбор в пользу коротких имён классов и не соблюдают собственные рекомендации.
Требования к провайдеру (PortletProvider):
1. Класс провайдера должен наследоваться от BasePortletProvider и реализовывать один из интерфейсов: AddPortletProvider, BrowsePortletProvider, EditPortletProvider, ManagePortletProvider, PreviewPortletProvider или ViewPortletProvider, указывающих на тип действия.
2. В аннотации к классу должен быть указан тип сущности, это делается через параметр model.class.name, и сервис (класс интерфейса *PortletProvider), совпадающий с тем, что реализует ваш класс.
@Component(
immediate = true,
property = {"model.class.name=CLASS_NAME"},
service = INTERFACE.class
)
3. Класс должен реализовывать методы для получения уникального идентификатора портлета и страницы - getPortletId() и getPlid(ThemeDisplay). Тема использует этим методы для определения, какой портлет и на какую страницу должен быть вставлен.
Посмотрим как эти требования реализованы в коде SiteNavigationLanguageViewPortletProvider.java
@Component(
immediate = true,
property = "model.class.name=com.liferay.portal.kernel.servlet.taglib.ui.LanguageEntry",
service = ViewPortletProvider.class
)
public class SiteNavigationLanguageViewPortletProvider
extends BasePortletProvider implements ViewPortletProvider {
@Override
public String getPortletName() {
return SiteNavigationLanguagePortletKeys.SITE_NAVIGATION_LANGUAGE;
}
@Override
public PortletURL getPortletURL(
HttpServletRequest httpServletRequest, Group group)
throws PortalException {
return PortletURLFactoryUtil.create(
httpServletRequest, getPortletName(), PortletRequest.RENDER_PHASE);
}
/**
* @deprecated As of Judson (7.1.x)
*/
@Deprecated
@Override
protected long getPlid(ThemeDisplay themeDisplay) throws PortalException {
return themeDisplay.getPlid();
}
}
В случае, если вы захотите определить свой собственный портлет для переключения языков, то есть портлет с таким же типом сущности и действием (VIEW), вам понадобится убедить Liferay использовать именно ваш портлет вместо дефолтного. Для этого используются ранги. Чем выше ранг, тем приоритетнее портлет, и выбран будет тот, у кого ранг выше. Для этого нужно добавить в аннотацию @Component свойство service.ranking с бОльшим значением, чем у дефолтных портлетов.
property={"service.ranking:Integer=20"}
Однако в документации не сказано, какое значение ранга стоит у портлетов по умолчанию. А в коде портлета мы не видим данного параметра в аннотации @Component.
Встраивание портлета по его имени
Второй способ аналогичен привычному нам из Liferay 6.2, с небольшими изменениями в синтаксисе. Он подходит для любых портлетов, в том числе не являющихся OSGI модулями (и не имеющих аннотации @Component). В общем виде он выглядит так:
<@liferay_portlet["runtime"]
instanceId="INSTANCE_ID"
portletName="PORTLET_NAME"
/>
Способ формирования ИД портлета не изменился, он был подробно изложен в предыдущей статье, и я не буду его копировать. Если портлет может иметь инстансы, нужно указать ИД инстанса. В противном случае этот параметр просто не указывается.
Ниже несколько примеров.
<@liferay_portlet["runtime"]
defaultPreferences="${defaultPortletPreferences}"
portletName="com_liferay_asset_publisher_web_portlet_AssetPublisherPortlet"
/>
<@liferay_portlet["runtime"]
portletName="stocksportlet_WAR_stocksportlet"
defaultPreferences="${defaultPortletPreferences}"
/>
Настройки отображения (defaultPreferences)
Мы рассмотрели два способа встраивания портлета в тему, но ничего не сказали о параметре defaultPreferences. Принцип остался таким же, как в Liferay 6.2, это переменная для передачи настроек портлета. Немного поменялся способ её заполнения, но тут всё должно стать очевидно из примера.
<#assign defaultPortletPreferences = freeMarkerPortletPreferences.getPreferences(
"portletSetupPortletDecoratorId", "barebone"
)
/>
<#assign languagePortletPreferences = freeMarkerPortletPreferences.getPreferences({
"displayStyle": "ddmTemplate_LANGUAGE-SHORT-TEXT-FTL",
"portletSetupPortletDecoratorId": "barebone"
}) />