Реализация взаимодействия между портлетами на стороне клиента с использованием Dojo и WebSphere Portal

В данной статье описывается, как добавить взаимодействие между портлетами IBM® WebSphere® Portal (здесь и далее WebSphere Portal) на стороне клиента, используя инструментарий Dojo JavaScript toolkit. Она предназначена для разработчиков, которые начинают использовать Ajax с WebSphere Portal и хотят воспроизвести на стороне клиента взаимодействие портлетов между собой, которое они реализовывали ранее на стороне сервера. Для лучшего понимания статьи вы должны хорошо разбираться в программировании на JavaScript, WebSphere Portal и разработке портлетов. Ссылки, которые помогут получить эти знания, приведены в разделе "Ресурсы". Пример портлет-приложения для данной статьи был разработан с использованием IBM Rational® Application Developer v7 и протестирован на WebSphere Portal V6.0.

Эйрон Уолакер, специалист по информационным технологиям, IBM Software Services for WebSphere, IBM

Арон Уолакер (Aron Wallaker) работает специалистом по информационным технологиям в IBM Software Lab, Toronto, Canada. Он занимается разработкой WebSphere Portal и Web-приложений в группе IBM Software Services for WebSphere (ISSW).



13.11.2007

Введение

Многие разработчики порталов, стремясь повысить эффективность работы пользователей, используют WebSphere Portal для создания кооперативных (совместно работающих) портлетов с общими событиями и данными. Например, выбор варианта в одном портлете мог бы вызывать обновление информации, отображающейся в нескольких других портлетах, которые, таким образом, были бы синхронизированы между собой. Эта функциональность реализована на сервере и основана на портлетах, передающих запросы действия (action request) на сервер, вследствие чего может выполняться передача данных перед обновлением страницы.

Этот подход перестает работать, если вы добавите к портлетам функциональность Ajax, поскольку отображаемые портлетом данные обновляются динамически без передачи запросов действия или обновлений страницы. В данной статье рассказывается, как применить Dojo JavaScript toolkit для совместного использования портлетами данных и событий в браузере, обеспечивая поддержку совместной работы динамически обновляемых портлетов.


Что такое Dojo?

Dojo - это набор JavaScript-программ с открытыми исходными кодами, который можно использовать для разработки динамических Web-приложений. В многочисленные библиотеки Dojo включены поддержка Ajax, программы управления DOM, система обработки событий и набор настраиваемых виджетов. Dojo комбинирует эти библиотеки с гибкой системой пакетирования, позволяющей импортировать только необходимые библиотеки; Dojo разрешает все межбиблиотечные зависимости автоматически.

Использование Dojo

Динамическая система пакетирования различает использование Dojo-библиотек и традиционные механизмы включений JavaScript. Подключение Dojo-библиотек - это двухэтапный процесс:

  1. Подключите начальный загрузчик Dojo.
    <script type="text/javascript" src="/path/to/dojo/dojo.js"> 
    </script>
  2. Идентифицируйте Dojo-библиотеки, необходимые вашему приложению. Для подключения функций управления Dojo-виджетами (dojo.widget.*) и виджета Button (dojo.widget.Button) используйте оператор dojo.require.
     <script type="text/javascript">
     dojo.require("dojo.widget.*");
     dojo.require("dojo.widget.Button");
     </script>

Операторы dojo.require указывают Dojo-ресурсы, использующиеся в приложении. Начальный загрузчик Dojo просканирует страницу в поиске этих операторов dojo.require и динамически подключит соответствующие библиотеки. Также процесс динамической загрузки тоже обрабатывает все зависимости между Dojo-библиотеками, поэтому операторы require нужно добавить только для ресурсов, использующихся непосредственно.

Использование Dojo с WebSphere Portal

Уникальная стратегия загрузки Dojo ставит проблему перед разработчиками портлетов. Начальный загрузчик Dojo dojo.js должен быть подключен в HTML-страницу только один раз. В зависимости от браузера подключение dojo.js более одного раза может привести к отображению конечному пользователю сообщений о JavaScript-ошибках. Простейший способ избежать этой проблемы в WebSphere Portal - включить dojo.js в JSP темы и поместить операторы dojo.require в JSP темы и портлета.

Однако в примере приложения я хотел, чтобы читатели могли развертывать портлеты, не меняя тему. Поэтому я подключил Dojo-библиотеки в проект портлета и написал условный загрузчик на JavaScript.

Условный загрузчик содержится в файле dojoLoader.jsp:

<script type="text/javascript">
	var path = "<%=request.getContextPath() %>/dojo/dojo.js";
	if(typeof dojo=="undefined") {
		document.write('<S');
		document.write('CRIPT type=\"text/javascript\" src=\"');
		document.write(path);
		document.write('\" ><\/S');
		document.write('CRIPT>');
	} 
</script>

Данный код проверяет существование JavaScript-объекта dojo; если этот объект не определен, то в текущий HTML-документ вставляется сценарий включения dojo.js . JavaScript-код, выполняющий это, немного труден для чтения - все экземпляры <script> или </script> встроках должны разделяться, в противном случае некоторые браузеры будут считать их реальным началом и концом сценария. Изменение JSP-темы было бы намного более понятным и аккуратным решением. Используйте этот метод условной загрузки только при невозможности изменения JSP-темы.

Использование Dojo-событий

В Dojo имеется система взаимодействия событий, ккоторая позволяет разработчикам подключать компоненты приложения. Эта возможность выходит за рамки традиционных DOM-событий отображения их в любое свойство, объект или элемент; она включает такие продвинутые функциональные возможности как аспектно-ориентированное программирование (Aspect-Oriented Programming, AOP) или публикация/подписка событий (publish/subscribe, pub/sub). В данной статье рассматривается система публикации/подписки событий, известная под названием topics, а также способы ее использования для взаимодействия между портлетами.

Система публикации/подписки событий Dojo обеспечивает метод анонимного взаимодействия между компонентами на основе общей темы или очереди. JavaScript-компонент может использовать библиотеку событий Dojo для публикации или подписки на тему. Публикующий компонент может создать объект с данными, относящимися к событию, и затем опубликовать объект в теме. Все подписчики данной темы вызываются с опубликованным объектом, передаваемым в качестве параметра, что позволяет им отреагировать на новые данные; например, подписчик мог бы выполнить асинхронный вызов и/или обновить отображаемую информацию.

Такая схема очень хорошо отображается на взаимодействия между портлетами на стороне клиента. Поскольку портлеты должны использовать тег <portlet:namespace>, чтобы различать свои DOM и JavaScript-элементы, одному портлету очень тяжело слушать DOM-события от HTML другого портлета. Используя темы Dojo-событий, можно реализовать реакцию нескольких портлетов на DOM-событие в одном портлете и, в то же время, не нарушить их независимость. Например, динамический портлет может выполнять асинхронный вызов для извлечения информации и делать эту информацию доступной для других портлетов, использующих тему события.

Резюме по dojo.event.topic API

Ниже приведен краткий обзор Dojo topics API и описывается, как можно использовать различные методы для взаимодействия между JavaScript-компонентами.

dojo.event.topic.registerPublisher (String topic, Object obj, String funcName)
Регистрирует функцию как издателя темы. Любой последующий вызов функции будет вызывать публикацию события в теме с передачей аргументов функции всем зарегистрированным слушателям темы.
dojo.event.topic.publish(String topic, Object message )
Вручную публикует переданный объект в указанную тему. Этот объект затем будет передаваться всем зарегистрированным слушателям темы.
dojo.event.topic.subscribe(String topic, Object obj, String funcName)
Подписывает функцию на указанную тему. Все последующие события, опубликованные в этой теме, будут вызывать подписанную функцию. Слушатель может подписаться на тему в любое время, даже перед тем, как издатель сошлется на тему. Dojo создает тему, когда на нее первый раз сошлется подписчик или издатель.
dojo.event.topic.unsubscribe(String topic, Object obj, String funcName )
Отменяет подписку функции на указанную тему.
dojo.event.topic.destroy(String topic)
Уничтожает тему и отменяет регистрацию всех слушателей темы.

Topic API указывает объект и имя функции, когда вы ссылаетесь на издателя или подписчика. Этот подход предназначен для работы с системой Dojo-виджетов, чтобы регистрация могла быть проведена для конкретного экземпляра виджета. Если виджеты не используются, можно реализовать подписчика темы в виде JavaScript-объекта или простой функции.

В примере приложения подписчики темы реализованы в виде JavaScript-объектов. Если вы предпочитаете использовать вместо них простую JavaScript-функцию, можете сделать это, указав объект window.

Например:

dojo.event.topic.subscribe( "/myApp/myTopic", window, "myHandler");

Этот код будет создавать подписку на тему "/myApp/myTopic". При публикации события в данной теме будет вызываться JavaScript-функция myHandler с опубликованным событием, передаваемым в качестве параметра.


Рабочий пример

Давайте исследуем простую конфигурацию с портлетом публикации событий, двумя портлетами-слушателями и одной темой. Опубликованный объект event будет содержать два поля данных, используемых портлетами-слушателями. Последовательность событий при взаимодействии между портлетами будет следующей:

Рисунок 1. Последовательность событий примера портлета
Рисунок 1. Последовательность событий примера портлета
  1. Пользователь нажимает кнопку Publish Event в портлете публикации событий. Это создает DOM-событие, которое активизирует JavaScript-функцию обработчика событий.
  2. Этот обработчик использует Dojo-библиотеку для создания независимого объекта event и публикации его в теме. Этот новый объект event принимается всеми подписчиками темы, без необходимости какой-либо связи с оригинальной кнопкой Publish Event.
  3. Прослушивающие портлеты содержат функции подписки на тему, которые вызываются Dojo и принимают объект event. Эти функции обновляют экран портлета информацией, содержащейся в данном объекте event.

В примере публикующий портлет хранит счетчик нажатий кнопки Publish Event. Опубликованное событие содержит этот счетчик и текстовое сообщение. Каждый из слушающих портлетов обновляет свой экран, используя один из элементов сообщения события. Каждый раз, когда слушающие портлеты обрабатывают событие, обновленная область мигает для привлечения внимания к изменениям. Этот эффект мигания не является частью цикла публикации/подписки события; он был добавлен для повышения наглядности.

Портлет публикации событий

Портлет публикации событий нуждается в кнопке, которую может нажать пользователь для публикации события, и в счетчике для хранения количества нажатий этой кнопки. В листинге 1 приведен исходный код на HTML/ JavaScript для создания этой кнопки, добавления функции-обработчика событий нажатия кнопки, инкрементирования счетчика и, наконец, публикации события.

Листинг 1. Исходный код портлета публикации событий
<P>
The button below will publish a Dojo event to all registered subscribers.<br />
<button dojoType="Button" 
  widgetId="<portlet:namespace />_publishButton">Publish Event
</button>
</P>
<script type="text/javascript">
	// Загрузить Dojo-код, относящийся к функциям управления виджетами
	dojo.require("dojo.widget.*");	
	// Загрузить Dojo-код, относящийся к виджету Button 
	dojo.require("dojo.widget.Button");
	// Загрузить функциональность обработки событий Dojo
	dojo.require("dojo.event.*");
	dojo.require("dojo.event.topic.*");

	// Зарегистрировать функцию init 
	dojo.addOnLoad( <portlet:namespace />_init ); 
	
	// Счетчик нажатий
	var <portlet:namespace />_counter = 0;

	// Функция Init для Dojo-компонентов этого портлета
	function <portlet:namespace />_init() {
		var pubButton = dojo.widget.byId("<portlet:namespace />_publishButton");
		dojo.event.connect(pubButton,'onClick','<portlet:namespace />_onButton');
	}

	// Обработчик кнопки onClick 
	function <portlet:namespace />_onButton() {
		<portlet:namespace />_counter++;
		var evt = {
			count: <portlet:namespace />_counter,
			message: "Click message #" + <portlet:namespace />_counter
		};
		dojo.event.topic.publish("/myApp/myTopic", evt);
	}
</script>

Просматривая код, вы увидите, что тег dojoType идентифицирует кнопку Publish Event как Dojo-виджет Button. В JavaScript-разделе операторы dojo.require идентифицируют Dojo-библиотеки, используемые этим компонентом. Вызов dojo.addOnLoad() добавляет функцию init к списку функций, которые Dojo будет вызывать после завершения загрузки дерева DOM-объектов страницы. Такой подход аналогичен установке функции в обработчике window.onLoad, за исключением того, что Dojo обрабатывает несколько имеющихся функций init, которые нужно выполнить после загрузки документа. Эта возможность является очень полезной в приложениях-порталах, поскольку она позволяет каждому портлету указывать JavaScript-функцию init, не беспокоясь о перезаписи обработчика window.onLoad.

Для указания JavaScript-функций и переменных в этом портлете используется тег <portlet:namespace> из стандартной библиотеки тегов портлета. Этот тег заменяется алфавитно-цифровой строкой, являющейся уникальной для экземпляра портлета, что предотвращает конфликты пространства имен при наличии на странице нескольких портлетов. Функция init находит кнопку Publish Event по ее widgetId и подключает событие onclick этого виджета к обработчику событий. Этот обработчик событий увеличивает счетчик, создает объект event и использует dojo.event.topic.publish API для публикации объекта event в теме myApp/myTopic. Объект event имеет два элемента:

  • count - значение счетчика
  • message - текстовое сообщение, содержащее счетчик

Dojo будет передавать объект event каждому из подписчиков на событие, которые затем смогут обработать содержимое по своему усмотрению.

Портлет подписки на событие

Портлет подписки на событие должен отображать поле, которое будет обновляться информацией, поступающей из опубликованного события. Портлет-подписчик также должен зарегистрировать свою функцию обработки событий для темы. Эту регистрацию наиболее удобно выполнить в функции init, аналогичной использующейся издателем события. Исходный код на HTML/ JavaScript портлета подписки на событие приведен в листинге 2.

Листинг 2. Исходный код портлета подписки на событие
<P>Button Click Count<br />
<span id="<portlet:namespace />_count" style="font-size : x-large;">0</span>
</P>
<script type="text/javascript">
  // Загрузить функциональность обработки событий Dojo
  dojo.require("dojo.event.*");
  dojo.require("dojo.event.topic.*");
  dojo.require("dojo.lfx.html");
  dojo.require("dojo.gfx.color");

  dojo.addOnLoad( <portlet:namespace />_init ); 

  // Функция Init для Dojo-компонентов этого портлета
  function <portlet:namespace />_init() {
	<portlet:namespace />_myListener = new <portlet:namespace />_listener();
	<portlet:namespace />_myListener.load();
  }

  // объект слушателя событий
  function <portlet:namespace />_listener() {
    // Прослушиватель событий - переопределите для каждого портлета
    this.handleEvent = function(args) {
	  var countElement = document.getElementById("<portlet:namespace />_count");
	  countElement.innerHTML = args.count;
	  dojo.lfx.html.highlight("<portlet:namespace />_count",
	    dojo.gfx.color.named.blue,500).play();
     }
	    
    this.load = function() {
        dojo.event.topic.subscribe("/myApp/myTopic", this, this.handleEvent);
     }
  }
</script>

Аналогично портлету публикации событий, операторы dojo.require указывают Dojo-библиотеки, нужные для данного компонента, а dojo.addOnLoad регистрирует функцию init портлета. Функция init создает новый объект слушателя событий и подписывает его на тему /myApp/myTopic путем вызова его метода load. При публикации события в этой теме вызывается метод handleEvent слушателя. Прослушиватель событий ищет DOM-элемент, в котором отображается счетчик, и обновляет HTML элемента значением, переданным в объекте event.

Затем, обработчик вызывает dojo.lfx.html.highlight() для создания визуального эффекта мигания для привлечения внимания пользователя к обновленной области.

Пример приложения содержит второй портлет подписки на событие с практически аналогичной функциональностью; он отображает сообщение события вместо счетчика. Оба слушателя принимают один и тот же объект, но работают с различными переменными-членами объекта.

Выполнение примера

Давайте рассмотрим, как портлеты примера приложения работают совместно.

  1. Если вы еще этого не сделали, загрузите пример проекта обмена файлами Rational Application Developer 7, который содержит рассматриваемые в данной статье портлеты.
  2. Выполните импорт файла в Application Developer.
  3. Для развертывания портлетов выполните экспорт WAR-файла и разверните его в WebSphere Portal либо запустите портлеты в интегрированной среде тестирования.
  4. Создайте новую тестовую страницу и добавьте в нее три портлета.
  5. Для тестирования приложения просто перейдите на тестовую страницу, созданную на шаге 4, и нажмите кнопку Publish Event.

При каждом нажатии кнопки страница отображает два портлета-слушателя событий, которые мигают и обновляются новыми значениями счетчика и сообщения, опубликованными портлетом публикации события.

Рисунок 2. Примеры портлетов
Рисунок 2. Примеры портлетов

Заключение

Добавление Ajax-функциональности в Web-приложения может значительно улучшить работу пользователей. В среде WebSphere Portal использование Ajax в портлетах может нарушить работу такой функциональности как совместно выполняющиеся портлеты. Однако можно использовать Dojo toolkit для добавления возможности взаимодействия между портлетами на стороне клиента. Разработчики портлетов могут использовать эту методику для создания динамических, совместно выполняющихся портлетов, которые будут оставаться синхронизированными друг с другом, одновременно минимизируя количество обновлений страницы и повышая чувствительность приложения.


Загрузка

ОписаниеИмяРазмер
Примеры кодаdojoC2A.zip1466 KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere
ArticleID=268773
ArticleTitle=Реализация взаимодействия между портлетами на стороне клиента с использованием Dojo и WebSphere Portal
publish-date=11132007