null

Модификация интегрированного в Liferay портлета с помощью hook-плагина

В состав 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" />
	 &raquo;
</a>

Всё! Плагин готов! Теперь соберём его и развернём на сервере. На локальном сервере нам в этом поможет eclipse, а для развёртывание на production-портале нам понадобится сделать war-файл:

cd %HOOK_PLUGIN_HOME%
ant war

и скопировать его в autodeploy-каталог портала.

В итоге разница налицо.

Было:

Стало:

Скачать hook-плагин - src, war

Коротко о себе:

Работаю ведущим программистом в компании Tune IT и ассистентом кафедры Вычислительной техники в Университете ИТМО .

Занимаюсь проектами, связанными с разработкой разного рода веб-приложений (порталы, CRM-системы, системы электронного документооборота), а также, в рамках научной работы на кафедре, изучаю возможности применения семантического анализа в задачах САПР.