Статьи

Совместное использование компонентов JSF и Flex

Exadel Fiji расширяет JavaServer Faces (JSF), позволяя использовать компоненты Flex на странице JSF. Фиджи означает «Интеграция Flex и JSF». При использовании компонентов Фиджи разработчики используют Flex с тем же компонентным подходом к созданию пользовательских интерфейсов, с которым они знакомы по JSF. Это означает, что компоненты Flex связаны со стандартными управляемыми компонентами JSF.

Фиджи — это структура, которая обеспечивает следующее:

  • Библиотека готовых компонентов Flex для JSF
  • Универсальная оболочка, которая позволяет использовать любой компонент Flex на странице JSF
  • Самое главное, что с Фиджи вы можете связать компоненты Flex с теми же свойствами или методами JSF-управляемых компонентов (или компонентами Seam или Spring), которые используются остальной частью вашего приложения JSF.

Текущая версия поставляется со следующими готовыми диаграммами:

  • Столбчатая диаграмма
  • Столбчатая диаграмма с накоплением
  • Гистограмма
  • Гистограмма с накоплением
  • Линейный график

Например, вот снимок экрана компонента Flex на странице JSF

[Img_assist | NID = 5013 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 341 | Высота = 398]

Вы можете увидеть все компоненты Фиджи в действии на http://livedemo.exadel.com/fiji-demo

Теперь, когда я дал вам краткое введение в Фиджи, вы, вероятно, задаетесь вопросом, какую проблему пытается решить Фиджи. Давайте посмотрим.

Почему Фиджи?

Давайте начнем с основ. JavaServer Faces (JSF) — это стандартная (Java EE) инфраструктура для построения пользовательских интерфейсов Web из компонентов. Сегодня мы заинтересованы в создании многофункциональных интернет-приложений, поэтому создание RichFaces делает JSF шаг вперед, позволяя упростить создание приложений на основе AJAX в JSF. (Если вы не знаете, RichFaces предлагает большое количество готовых к использованию компонентов AJAX.)

В то время как JSF постоянно растет, одной из областей, где ему все еще не хватает, является отображение многофункциональных и интерактивных диаграмм, графиков и других подобных визуальных элементов. Даже с AJAX любое серьезное построение графиков чрезвычайно сложно, не говоря уже о тестировании, которое потребуется для различных браузеров. Это действительно сводится к двум вещам. Во-первых, технологии, используемые в JSF, такие как HTML, JavaScript и CSS, не предназначены для отображения богатых и интерактивных визуальных данных (возможно, но очень сложно). Во-вторых, у людей гораздо более высокие ожидания от браузера. Один браузер никогда не предназначался для отображения таких визуальных данных. Это было прежде всего предназначено для отображения текста и статических изображений. Итак, в конце концов, это не вина JSF, мы просто просим базовые технологии (HTML, JavaScript, CSS, браузер) сделать слишком много.

Конечно, есть надежда. Мы можем использовать Flash Player для отображения многофункциональных и интерактивных диаграмм.

Adobe Flash

С помощью Flex сложные многофункциональные приложения могут быть скомпилированы и затем запущены внутри Flash-проигрывателя. Флеш-плеер — это виртуальная машина, которая устанавливается как плагин в любой браузер. Поскольку приложение (созданное с помощью Flex) работает внутри виртуальной машины, оно обеспечивает гораздо более превосходную среду для многофункциональных и интерактивных диаграмм и графиков, чем один только браузер (который просто интерпретирует HTML, JavaScript и т. Д.).

Следующий очевидный вопрос: почему бы не использовать компоненты Flex и JSF вместе сейчас? Хотя можно использовать компоненты Flex и JSF на одной странице, эти две технологии не знают друг друга. Это означает, что компоненты JSF привязаны к управляемым bean-компонентам JSF (или компонентам Seam, или bean-компонентам Spring), тогда как Flex привязан к совершенно другим объектам. Этот вид интеграции эквивалентен вставке изображения на страницу JSF — другими словами, не так много интеграции.
Вернуться на Фиджи

Это хорошее место для посещения Фиджи. Фиджи идеально подходит для решения вышеуказанной проблемы. Фиджи не только предоставляет готовые к использованию компоненты диаграмм и универсальную оболочку для использования любых компонентов Flex, но и с помощью Fiji можно связывать компоненты Flex со стандартными управляемыми компонентами JSF. Как разработчик JSF, вы просто используете стандартный и знакомый подход, основанный на компонентах JSF, а также можете использовать компоненты Flex.

Итак, где имеет смысл использовать Фиджи. Один из сценариев — если у вас есть существующее приложение JSF, и вы хотите вставить более богатый контент на основе Flash, продолжая использовать существующую модель (управляемые компоненты JSF, компоненты Seam или компоненты Spring). Этот контент может быть диаграммами, графиками или любым другим богатым контентом.

Другая ситуация, когда Фиджи имеет смысл, это когда у вас есть существующее JSF-приложение, но вы хотите использовать пользовательский интерфейс на основе Flash (вместо HTML / JavaScript). Используя Фиджи, вы все еще можете использовать существующую часть модели вашего приложения.

Однако, если честно, не имеет смысла использовать Фиджи, если у вас уже есть приложение, предназначенное только для Flash, и вы используете такой сервис, как GraniteDS, BlazeDS или Exadel Flamingo.

Теперь я думаю, что мы готовы к примерам.

Используя Фиджи

Есть три основных шага, чтобы начать.

  1. Скачать шаблон проекта
  2. Скачайте файл JAR и добавьте их в шаблон проекта
  3. Откройте проект в вашей любимой IDE

Скачать шаблон проекта

Скачайте и распакуйте шаблон проекта. <Ссылка>

Скачать файлы Фиджи JAR

  1. Перейдите по адресу http://exadel.com/web/portal/fiji и нажмите «Загрузить», чтобы загрузить дистрибутив Фиджи.
  2. Распакуйте загруженный файл
  3. На следующем шаге вы скопируете JAR-файлы из папки lib в каталог fiji / web / WEB-INF / lib
    1. Если вы используете Tomcat 5.5, скопируйте все файлы
    2. Если вы используете Tomcat 6, скопируйте все файлы, кроме:
    ¦ el-api.1.0.jar
    ¦ el-impl-1.0.jar

Импортировать проект

Импортируйте проект в вашу любимую IDE. Вот как это сделать в JBoss Tools (те же шаги для JBoss Developer Studio).

  1. Выберите Файл / Импорт
  2. Выбрать другой
  3. Выберите проект JSF
  4. Укажите местоположение файла web.xml в проекте.
  5. Нажмите «Далее
  6. Сохраните все настройки как есть (я предполагаю, что у вас есть определенный сервер)
  7. Нажмите Готово

По правде говоря, установить Фиджи очень просто. В основном это проект RichFaces (должен быть RichFaces версии 3.2.2 или выше) плюс файлы JAR для Фиджи:

  • фиджи-апи-1.xxjar
  • фиджи-щ-1.xxjar
  • flamingo-service-jsf-1.6.x.jar — использовать HttpService через компонент <fiji: endpoint>. Позже в статье.

Помимо использования HttpService, если вы хотите использовать DataServices (формат AMF), вам понадобятся два дополнительных файла JAR:

  • амф-сериализатору-1.6.x.jar

Вот и все. Больше ничего не нужно, даже изменения в web.xml.

Использование гистограммы

Давайте начнем с простого примера использования гистограммы. Первым шагом является создание данных для диаграммы. Поскольку мы можем легко привязать диаграммы к управляемым компонентам JSF, именно здесь мы собираемся создавать наши данные.

Java-бин выглядит так:

public class BarChartBean {
public BarChartBean() {
}
private Integer[] data;

public Integer[] getData() {
return data;
}
@PostConstruct
public void init () {
data = new Integer[5];
data[0] = 5;
data[1] = 2;
data[2] = -3;
data[3] = 10;
data[4] = 9;
}
}

Чтобы сделать его управляемым JSF-компонентом, нам нужно зарегистрировать его в файле конфигурации JSF:

<managed-bean>
<managed-bean-name>barChartBean</managed-bean-name>
<managed-bean-class>fiji.BarChartBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Пока что это просто базовый JSF. Давайте теперь создадим страницу.

Откройте файл start.xhtml. Посмотрите наверх, страница уже содержит пространство имен для библиотеки тегов Фиджи. Вставьте следующее между тегами <body>:

<h:form>
<fiji:barChart id="barChart" value="#{barChartBean.data}"
title="Bar chart" width="500" height="300">
<fiji:chartData type="name" value="Just some numbers" />
</fiji:barChart>
</h:form>

<fiji: barChart> похож на стандартный компонент JSF. Атрибут value связан с данными диаграммы внутри управляемого компонента. <fiji: chartData type = ”name” ..> устанавливает имя диаграммы.

Сохраните все и запустите страницу. Вы должны получить следующее:

[Img_assist | NID = 5014 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 672 | Высота = 394]


Давайте попробуем другой пример, на этот раз используя столбчатую диаграмму. Я уверен, что большинство из вас до сих пор помнят Летние Олимпийские игры, поэтому мы возьмем счет медалей и отобразим его в таблице.

Использование столбчатой ​​диаграммы

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

Мы собираемся взять тройку лидеров (США, Китай и Россия) и показать их количество золотых, серебряных и бронзовых медалей. Как и прежде, начнем с данных для графика.
Java-бин выглядит так:

public class MedalsBean {
private Map<String, Integer[]> medalsData = new LinkedHashMap<String,Integer[]>();
private ArrayList<String> colors = new ArrayList<String>();
private ArrayList<String> names = new ArrayList<String>();

private Integer[] medalsChina = new Integer[]{51, 21, 28};
private Integer[] medalsUSA = new Integer[]{36, 38, 36};
private Integer[] medalsRussia = new Integer[]{23, 21, 28};

@PostConstruct
private void init() {
medalsData.put("China", medalsChina);
medalsData.put("USA", medalsUSA);
medalsData.put("Russia", medalsRussia);

names.add("Gold");
names.add("Silver");
names.add("Bronze");

colors.add("#DAA520");
colors.add("#C0C0C0");
colors.add("#B87333");
}

public Map<String, Integer[]> getMedalsData() {
return medalsData;
}
public ArrayList<String> getColors() {
return colors;
}
public ArrayList<String> getNames() {
return names;
}
public Integer[] getMedalsChina() {
return medalsChina;
}
public Integer[] getMedalsUSA() {
return medalsUSA;
}
public Integer[] getMedalsRussia() {
return medalsRussia;
}
}

Поскольку теперь мы отображаем три столбца на страну (по одному на каждую медаль), мы используем объект Map и внутри него помещаем массив целых чисел, представляющих количество медалей.

Чтобы сделать его управляемым компонентом JSF, нам нужно зарегистрироваться в файле конфигурации JSF:

<managed-bean>
<managed-bean-name>medalsBean</managed-bean-name>
<managed-bean-class>fiji.MedalsBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Теперь мы готовы построить страницу. Страница не сильно отличается от первого примера:

<h:form>
<fiji:columnChart id="goldMedals" value="#{medalsBean.medalsData}"
legendPosition="top"
barColors="#{medalsBean.colors}"
width="250" height="300">
<fiji:chartData type="name" value="#{medalsBean.names}" />
</fiji:columnChart>
</h:form>

Запуск страницы приведет к следующему:

[Img_assist | NID = 5015 | название = fiji3 | убывание = | ссылка = нет | ALIGN = не определено | ширина = 339 | высота = 404]

Хотя интеграция с JSF является аккуратной (мы можем легко использовать управляемые компоненты JSF в качестве модели данных для компонентов Flex), мы можем даже сделать еще один шаг вперед. Можно щелкнуть диаграмму Flex, отправить запрос AJAX и выполнить частичное обновление страницы. Посмотрим, как это делается.

Обработчики событий

Компоненты Фиджи имеют обработчики событий, такие как onitemclick, которые очень похожи на стандартные обработчики событий DHTML, такие как onkeyup. Возвращаясь к нашему примеру, скажем, мы хотим щелкнуть по любому столбцу и отобразить информацию о медали за пределами графика. При нажатии на панель AJAX-запрос будет отправлен на сервер, свойства будут установлены, а затем повторно обработаны.

Изменения в управляемом бине минимальны. Все, что мы делаем, это добавляем три свойства:

private String countrySelected;
private String medalTypeSelected;
private String medalCountSelected;

// getter and setters methods

Не забудьте создать геттеры и сеттеры.

Так выглядит наша страница.

<h:form>
<fiji:columnChart id="goldMedals" value="#{medalsBean.medalsData}"
legendPosition="top"
barColors="#{medalsBean.colors}"
width="250" height="300">
<fiji:chartData type="name" value="#{medalsBean.names}" />
<a4j:support event="onitemclick" reRender="info">
<a4j:actionparam name="param1" value="event.x" assignTo="#{medalsBean.countrySelected}" noEscape="true"/>
<a4j:actionparam name="param2" value="event.y" assignTo="#{medalsBean.medalCountSelected}" noEscape="true"/>
<a4j:actionparam name="param3" value="event.name" assignTo="#{medalsBean.medalTypeSelected}" noEscape="true"/>
</a4j:support>
</fiji:columnChart>
</h:form>

<h:panelGrid id="info">
<h:outputText value="#{medalsBean2.countrySelected}"
style="text-decoration: underline;"/>
<h:outputText value="#{medalsBean2.medalTypeSelected}
#{medalsBean2.medalCountSelected}"/>
</h:panelGrid>

Мы используем самый популярный тег из RichFaces, <a4j: support>, чтобы прикрепить событие (onitemclick) к родительскому компоненту, <fiji: columnChart>. При щелчке столбца на диаграмме серверу отправляется запрос Ajax, передавая три аргумента, определенных тегом <a4j: actionparam>. Тег <a4j: actionparam> автоматически берет значение из атрибута value и присваивает его свойству, определенному в атрибуте assignTo. Переданы следующие три аргумента:

event.x — это данные оси X. В нашем случае это название страны
event.y — это данные по оси Y. В нашем случае это счетчик
медалей event.name — это активный бар. В нашем случае это будет выбранный тип медали

Я также установил noEscape = ”true” для каждого <a4j: actionparam>. Это необходимо для того, чтобы значение обрабатывалось как код JavaScript, а не заключалось в одинарные кавычки и просто передавалось на сервер в качестве параметра.

Наконец, мы перерисовываем информацию внутри сетки панели. Как вы можете видеть, мы используем стандартные методы RichFaces для отправки и перерисовки информации, даже если мы смешиваем компоненты Flex.

Использование универсальной обертки

До сих пор я показал вам, как использовать компоненты диаграмм, которые поставляются с Фиджи. Очевидно, вы можете использовать другие существующие компоненты Flex или даже создать свои собственные. Чтобы использовать любые другие компоненты Flex, мы используем универсальную оболочку или компонент <fiji: swf>.

Мы будем использовать один из графиков, предоставленных amCharts.com .
Примечание: мы можем использовать их графики бесплатно. Единственным ограничением является то, что появится маленький URL, указывающий на их веб-сайт. Я не думаю, что это такое ограничение для таких хороших графиков.

SWF-файл для диаграммы, а также данные диаграммы включены в шаблон в каталоге web / ampie. Вы также можете скачать их здесь:

SWF-файл — ampie.swf <ссылка>
Файл настроек — ampie_settings.xml <ссылка>
Файл данных — ampie_data.xml <ссылка>

Страница выглядит так:

<fiji:swf src="/ampie/ampie.swf" bgcolor="#FFFFFF" width="420" height="300">
<f:param name="path" value="/ampie" />
<f:param
name="settings_file"
value="#{facesContext.externalContext.requestContextPath}/ampie/ampie_settings.xml" />
<f:param
name="data_file"
value="#{facesContext.externalContext.requestContextPath}/ampie/ampie_data.xml" />
<f:param name="preloader_color" value="#999999" />
</fiji:swf>

Используя атрибут src <fiji: swf>, мы указываем на компонент Flash. Flash-компонент также может быть загружен как ресурс с помощью src = «resource: ///file.swf». Этот конкретный компонент Flash (ampie.swf) требует некоторых данных. Данные передаются с использованием стандартного атрибута JSF <f: param>. Когда объект Flash отображается на странице, он имеет специальный атрибут flashVars, который предоставляет аргументы модулю Flash. В нашем случае теги <f: param> с их информацией отображаются как аргументы flashVar для компонента Flash. Вот как графики получают свои данные.

Запуск страницы приведет к следующему:

[Img_assist | NID = 5016 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 539 | Высота = 384]

В случае, если вам необходимо обновить данные для диаграммы, один из возможных способов — это перерисовать компонент Flash с использованием стандартного подхода RichFaces.


Использование <fiji: конечная точка>

В качестве последнего примера я покажу вам, как использовать <fiji: swf> вместе с <fiji: endPoint>. Это позволит нам отправить параметр из компонента Flash в управляемый компонент JSF.

Давайте начнем с части Flash. Это приложение Flex, которое мы хотим использовать на нашей странице JSF:

hello.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private var userRequest:HTTPService;

private function send():void {
userRequest = new HTTPService();
userRequest.url = Application.application.parameters.fiji;
userRequest.addEventListener("result", httpResult);
var param:Object = {};
param["hello"] = username.text;
userRequest.send(param);
}
public function httpResult(event:ResultEvent):void {
if (event.result) {
helloLabel.text = event.result.value;
}
}
]]>
</mx:Script>

<mx:Form x="22" y="10" width="280">
<mx:Label id="helloLabel" styleName="text"
text="{Application.application.parameters.text}" />
<mx:HBox>
<mx:Label id="helloPerson" text="Username"/>
<mx:TextInput id="username"/>
</mx:HBox>
<mx:Button label="Submit" click="send()"/>
</mx:Form>
</mx:Application>

Это довольно простой файл MXML, который вы можете скомпилировать либо в Flex Builder, либо просто из командной строки после установки Flex SDK


> mxmlc hello.mxml

Я также предоставил SWF-файл внутри шаблона (и здесь hello.swf <link>) на случай, если вы захотите пропустить этап компиляции.

Файл MXML выдаст следующее:

[Img_assist | NID = 5017 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 267 | высота = 110]

Теперь давайте посмотрим на страницу JSF:

<h:form>

<fiji:swf src="/hello.swf"

bgcolor="#FFFFFF" width="350" height="200">

<f:param name="text" value="Hello Fiji World"/>

<fiji:endpoint name="fiji"

decoder="fiji.HelloDecoder"

encoder="fiji.HelloEncoder"

service="#{serviceBean.greeting}"/>

</h:form>

<fiji: swf> используется для включения компонента Flash, как мы делали раньше. Атрибут службы указывает на управляемый компонент JSF с методом приветствия:

public Object greeting(Object value){
if(value != null){
return "What's up, "+value+"?";
} else {
return "What's up, unknown?";
}
}

Это также должно быть зарегистрировано в файле конфигурации JSF:

<managed-bean>
<managed-bean-name>serviceBean</managed-bean-name>
<managed-bean-class>fiji.ServiceBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Я расскажу о HelloDecoder и HelloEncoder позже.

При запуске этой страницы мы получим нечто очень похожее на предыдущее изображение; однако теперь он находится внутри страницы JSF и, если мы введем значение для имени пользователя и нажмем кнопку «Отправить», мы получим следующее.

[Img_assist | NID = 5018 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 271 | высота = 118]

Вопрос в том, как мы можем отправить запрос в управляемый компонент JSF из компонента Flash? Это делается с помощью компонента <fiji: endpoint>:

<fiji:endpoint name="fiji"

decoder="com.exadel.fiji.demo.simple.HelloDecoder"

encoder="com.exadel.fiji.demo.simple.HelloEncoder"

service="#{serviceBean.greeting}"/>

Мы определяем конечную точку с именем Фиджи. Если вы посмотрите на файл MXML, у нас есть следующее:

private function send():void {
userRequest = new HTTPService();
userRequest.url = Application.application.parameters.fiji;
userRequest.addEventListener("result", httpResult);
var param:Object = {};
param["hello"] = username.text;
userRequest.send(param);
}

Inside the Flex component, the HTTP URL points to Application.application.parameters.fiji which in turn points to the Fiji endpoint defined in the JSF page by <fiji:endpoint> tag. When the Submit button inside the Flash is clicked, the URL is resolved. This is a standard JSF request and that’s how we invoke the serviceBean.greeting method inside a JSF managed bean. The URL is again passed via the flashVars attribute when the page is rendered.

Finally, the initial label value is set via

{Application.application.parameters.text}

Its value is set via this <f:param> tag:

<f:param name="text" value="Hello Fiji World"/>

Decoders and Encoders

First, why do we even need these decoders and encoders? Well, when using the Flex HttpService, the data is being sent to the server and returned in XML format. The JSF managed bean that we are using doesn’t know anything about XML. It simply returns a string value. So, in order to convert the request into a format that the managed bean understands, we use a decoder. When we invoke a method, the value returned has to be encoded in order for the Flash module to understand it. I know, it sounds complicated, but it’s really not.

The decoder shown below will be called by Fiji and the value returned will be passed to the greeting(Object) method inside a JSF managed bean. The decoder will just pull the value from the XML sent by the request.

public class HelloDecoder implements FlexDecoder , Serializable {

private static final String ENDPOINT_PARAM = "hello";

public Object decodeRequest(FacesContext context, UIComponent component) {
return context.getExternalContext().getRequestParameterMap().get(ENDPOINT_PARAM);
}
}

When the greeting(Object) method inside the JSF managed bean returns a value, this encoder will be called to convert the response back to XML format.

public class HelloEncoder implements FlexEncoder {

private static final String VALUE = "value";

public void encodeObject(FacesContext context, UIComponent component,
Object object) throws IOException {
ResponseWriter responseWriter = context.getResponseWriter();
responseWriter.startElement(VALUE, component);
responseWriter.writeText(object, null);
responseWriter.endElement(VALUE);

}
}

 

You can implement different encode and decode methods in case your Flash module requires the XML request/response to be in a specific format.

Summary

This article showed how you can use JSF and Flex component together while using standard JSF managed beans to provide data for the Flash components. That’s what makes this framework unique. As a developer, you can continue using the standard component-centric JSF approach, but now you are able to inject even richer content using Flash.

To learn more, please visit the Fiji home page: http://exadel.com/web/portal/fiji

About the Author

Max Katz is a Senior Systems Engineer at Exadel. He has been helping customers jump-start their RIA development as well as providing mentoring, consulting, and training. Max is a recognized subject matter expert in the JSF developer community. He has provided JSF/RichFaces training for the past three years, presented at many conferences, and written several published articles on JSF-related topics. Max also leads Exadel’s RIA strategy and writes about RIA technologies in his blog, http://mkblog.exadel.com. He is an author of Practical RichFaces book (Apress). Max holds a BS in computer science from the University of California, Davis.