В состав Liferay интегрировано множество стандартных портлетов практически на все случаи жизни, но не всегда их интерфейс устраивает нас как конечного пользователя. При этом, в большинстве таких случаев требуются только косметические изменения в стандартных портлетах, а их логика не требует модификации. Здесь нам на помощь приходят hook-плагины, позволяющие в широких пределах модифицировать интегрированные в Liferay портлеты. Рассмотрим создание такого плагина на практическом примере.
Портлет "Blogs aggregator" (или "Агрегатор дневников" в русском переводе) отлично справляется со своей работой, но нам на нашем сайте захотелось немного улучшить его внешний вид - добавить к постам портреты авторов и иконку с количеством комментариев.
Если покопаться во "внутренностях" модифицируемого нами портлета, то можно обнаружить, что за вывод содержимого поста отвечает всего один JSP-файл - view_entry_content.jspf
. Таким образом, чтобы вывод поста выглядел так, как нам хочется, нам нужно подменить в hook-плагине этот файл своим.
Для начала создадим новый hook-плагин. Чтобы работа шла быстрее, воспользуемся связкой Eclipse + Liferay IDE + Liferay Plugins SDK.
1. Создаём новый плагин - File -> New -> Liferay Project.
2. В открывшемся всплывающем окне вводим имя плагина, выбираем тип - "Hook" и кликаем "Finish":
3. Теперь надо сконфигурировать наш плагин, чтобы наша JSP-страница подменяла собой стандартную. Для этого надо задать в конфигурации каталог, в котором будут находиться наши JSP-страницы. Вся конфигурация hook-плагина задаётся в файле /docroot/WEB-INF/liferay-hook.xml
. Модифицируем его содержимое следующим образом:
<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.0.0//EN"
"http://www.liferay.com/dtd/liferay-hook_6_0_0.dtd">
<hook>
<custom-jsp-dir>/custom_jsps</custom-jsp-dir>
</hook>
Элемент custom-jsp-dir
указывает на каталог, в котором будут находиться наши JSP-файлы (путь указывается относительно директории /docroot
).
4. Создадим каталог /docroot/custom_jsps
и поместим в него наш переопределённый JSP-файл. Важный момент - если мы хотим, чтобы на JSP-файл переопределял собой стандартный, мы должны поместить его внутри каталога custom_jsps
по тому же относительному пути, по которому оригинальный файл находится относительно корневого каталога веб-приложения портала. Т.е., в нашем случае, т.к. мы подменяем файл $LIFERAY_WEBAPP_ROOT/html/portlet/blogs_aggregator/view_entry_content.jspf
, наш файл должен находиться в каталоге /docroot/custom_jsps/html/portlet/blogs_aggregator/
(и тоже должен называться view_entry_content.jspf
):
5. Для начала, скопируем в наш JSP-файл содержимое переопределяемого оригинала. Чтобы добавить портрет автора поста, нужно добавить в JSP следующий элемент:
...
<img class="avatar" width="65" style="float: left; margin: 5px 10px 5px 0;" src="/image/user_portrait?img_id=<%= user2.getPortraitId() %>;">
...
Здесь user2
- это автор поста (переменная инициализируется в скриптлете в начале файла), а для получения идентификатора портрета используется метод getPortraitId()
.
6. Теперь добавим в наш плагин иконку комментария. Для этого поместим её в какой-нибудь каталог внутри /docroot/custom_jsps
- например, в специально созданный каталог icons
:
7. А теперь добавим на страницу количество комментариев к посту. В принципе, весь нужный код уже имеется на модифицируемой JSP, но по умолчанию показ количества комментариев взаимно альтернативен показу ссылки "Читать дальше >>>":
<c:if test="<%= enableComments %>">
<span class="comments">
<%
long classNameId =
PortalUtil.getClassNameId(BlogsEntry.class.getName());
int messagesCount =
MBMessageLocalServiceUtil.getDiscussionMessagesCount(
classNameId, entry.getEntryId(),
WorkflowConstants.STATUS_APPROVED
);
%>
<c:choose>
<c:when test='<%= strutsAction.equals("/blogs/view_entry") %>'>
<%= messagesCount %>
<liferay-ui:message
key='<%= (messagesCount == 1) ? "comment" : "comments" %>' />
</c:when>
<c:otherwise>
<aui:a href='<%= viewEntryURL
+ StringPool.POUND
+ renderResponse.getNamespace()
+ "messageScroll0" %>'>
<%= messagesCount %>
<liferay-ui:message
key='<%= (messagesCount == 1) ? "comment" : "comments" %>' />
</aui:a>
</c:otherwise>
</c:choose>
</span>
</c:if>
Заменим этот код своим (он, как ни странно, гораздо проще):
<%
long classNameId = PortalUtil.getClassNameId(BlogsEntry.class.getName());
int messagesCount =
MBMessageLocalServiceUtil.getDiscussionMessagesCount(
classNameId,
entry.getEntryId(), WorkflowConstants.STATUS_APPROVED
);
%>
<a href="<%= viewEntryURL %>#<portlet:namespace />messageScroll0"
style="text-decoration: none;">
<img src="/icons/comments.png"
alt="<%= LanguageUtil.get(pageContext, "comments") %>"
style="vertical-align: middle; margin-right: 5px;">
</a>
<a href="<%= viewEntryURL %>#<portlet:namespace />messageScroll0" style="margin-right: 10px;">
<%= messagesCount %>
</a>
<a href="<%= viewEntryURL %>" class="entry-tags">
<liferay-ui:message
arguments='<%= new Object[] {"aui-helper-hidden-accessible", entry.getTitle()} %>'
key="read-more-x-about-x" />
»
</a>
Всё! Плагин готов! Теперь соберём его и развернём на сервере. На локальном сервере нам в этом поможет eclipse, а для развёртывание на production-портале нам понадобится сделать war-файл:
cd %HOOK_PLUGIN_HOME%
ant war
и скопировать его в autodeploy-каталог портала.
В итоге разница налицо.
Было:
Стало:
Скачать hook-плагин - src, war