Преждевременная оптимизация является первопричиной всех бед в программировании. Дональд Кнут

Java EE и Flex, Часть 1: Совместимая комбинация

Оригинал статьи: Java EE and Flex, Part 1: A compelling combination.

Перевод: Евгений Неруш

Уровень читателя: Начинающий.

Разрабатывая приложение на JavaEE, и обдумывая, каким образом должна быть реализована клиентская часть, все чаще взор разработчиков падает на технологию Adobe Flex, которая в свою очередь предоставляет гибкие возможности для построения пользовательских интерфейсов. В этой статье Дастин Маркс описывает, каким образом Flex взаимодействует с бизнес логикой, реализованной на JavaEE, и какие высоко интерактивные компоненты могут быть использованы для построения гибких пользовательских интерфейсов.

Введение

Flex 3 предоставляет вам другой уникальный способ построения UI для ваших JavaEE приложений.  Вы узнаете, какие возможности предоставляет Flex при работе с таблицами, как описывать лэйаут приложения на языке разметки XML, и как заставить Flex и JavaEE работать вместе. Перед инсталляцией Flex и запуском приложения, давайте рассмотрим преимущества  данной технологии:

  • Код, написанный на Flex, может быть запущен в любом браузере. Всё что для этого нужно – это предварительно установленный плагин для Flash плеера (на данный момент у 95% браузеров Flash плеер уже установлен, что в свою очередь не может не радовать как разработчиков, так и пользователей)
  • Языки сценариев ActionScript и JavaScript основаны на стандарте ECMA-262 – международном стандарте для языка сценариев ECMAScript. По этой причине разработчики, знающие JavaScript, сразу найдут ActionScript хорошо известным языком. Flex так же предоставляет на вооружение разработчикам язык разметки MXML, позволяющий эфективно описывать лэйаут приложения
  • Flex имеет простой механизм связывания свойств одного объекта со свойствами другого объекта приложения
  • Flex имеет встроенную поддержку коммуникации с бек-энд системами как по HTTP протоколу так и по SOAP ориентированным веб сервисам
  • А также Flex предоставляет богатый набор компонентов, использование которых дает разработчикам возможность строить интерактивные пользовательские интерфейсы (включая работу с анимацией, видео и звуком)

Одним из главных преимуществ является поразительное сходство синтаксиса между ActionScript 3.0 и Java. Языки используют похожие условные выражения, похожий синтаксис написания циклов, а так же код конвеншин и правила документирования кода. Структура пакетов в ActionScript родственна к структуре директорий, как и в Java. ActionScript 3 предоставляет объектно-ориентированный подход к программированию, что позволяет работать с наследованием и интерфейсами. Возможности Flex в коммуникации с Java EE приложением используя SOAP или HTTP очень развиты, но вы не лимитированны в использовании только таких подходов к коммуникации. Blaze DS – продукт компании Adobe с открытым исходным кодом, который предоставляет дополнительный гибкий подход к коммуникации с JMS. В качестве альтернативы для реализации коммуникации вы можете использовать GraniteDS, который как и Blaze DS использует бинарный AMF3 формат для общения. GraniteDS легко интегрируется с такими фреймворками, как Spring, Guice, Seam.

Инсталляция Flex

В примерах данной статьи используется Flex 3.2 SDK. Если вы хотите собрать и запустить примеры, скачайте Flex SDK (включая компилятор коммандной строки и отладчик).  Распакуйте архив в одну из директорий, например, в C:flex_sdk_3_2. Для удобства добвьте в PATH путь к bin директории, создав предварительно переменную окружения FLEX_HOME.

Например:
set FLEX_HOME=C:flex_sdk_3_2
set PATH=%PATH%;%FLEX_HOME%bin;

Корректную инсталляцию Flex вы можете проверить выполнив команду mxmlc -version в командном интерпритаторе.

Рисунок 1. Проверка корректной установки Flex

MXML: Описываем лэйаут на языке разметки XML

Flex использует MXML для описайния лэйаута приложения. Файлы, в которых описываются лэйауты, имеют расширение .mxml. MXML код должен соответствовать хорошо оформленному XML и использовать пространства имён XML. В Листинге 1 описан простой и готовый к выполнению лэйаут Flex приложения, написанный на языке разметки MXML.

Листинг 1. Простой пример MXML

<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                width="1100" height="700">
   <mx:Panel title="Some of Dustin's Favorite JavaWorld Articles">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                fontSize="14" fontWeight="bold" />
      <mx:Grid>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Designing with Exceptions"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Inheritance Versus Composition"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="JSP Best Practices"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="More JSP Best Practices"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Extends is Evil"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Getter and Setter Methods Are Evil"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="New Features Added to Servlet 2.5"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Jason Hunter" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="REST for Java Developers, Part 1"
                         fontWeight="bold" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Brian Sletten" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html" />
            </mx:GridItem>
         </mx:GridRow>
      </mx:Grid>
   </mx:Panel>
</mx:Application>

Не смотря на то, что этот пример является довольно простым и не отображает всю мощь использования Flex и Flash, он все же является простым и хорошим введением в MXML. Весь код, приведённый в Листинге 1, является хорошо оформленным XML документом. В этом примере мы наглядно видим, как просто создать даблицу, содержащую статические данные. Обратив внимание на иерархию расположения таких тегов как <Grid>, <GridRow>, <GridItem>, вы найдёте большое сходство в формировании таблицы в HTML используя такие теги как <table>, <tr>, <td>.

Для того, чтобы скомпилировать этот пример, предварительно сохраните файл с именем Examplу1.mxml, после чего используйте компилятор командной строки, выполнив команду:

mxmlc Example1.mxml

Согласно настроек компилятора по умолчанию, наш MXML файл скомпилируется в SWF файл Example1.swf в той же директории, в которой расположен Example1.mxml. Открыв SWF файл в браузере, вы увидите такое же приложение как, на Рисунке 2.


Рисунок 2. Скомпилированное приложение.

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

Добавление стилей и ссылок

Листинг 2 включает в себя код из Листинга 1, но вдобавок имеет ряд изменений: мы добавляем стили и делаем ссылки кликабельными.

Листинг 2. Приложение со стилями и кликабельными ссылками.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                width="1100" height="700">
   <mx:Style>
      .articleTitle
      {
         font-weight: bold;
      }
      .gridLabel
      {
         font-weight: bold;
         font-size: 14;
      }
   </mx:Style>
   <mx:Panel title="Some of Dustin's Favorite JavaWorld Articles">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                styleName="gridLabel" />
      <mx:Grid>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Designing with Exceptions"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="exceptionsUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html'>http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html&lt;/a>"
                         selectable="true"
                         mouseOut="exceptionsUrl.setStyle('textDecoration', 'none');"
                         mouseOver="exceptionsUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Inheritance Versus Composition"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="inheritanceUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html'>http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html&lt;/a>"
                         selectable="true"
                         mouseOut="inheritanceUrl.setStyle('textDecoration', 'none');"
                         mouseOver="inheritanceUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="JSP Best Practices"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="jspBestPractices1Url"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html'>http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html&lt;/a>"
                         selectable="true"
                         mouseOut="jspBestPractices1Url.setStyle('textDecoration', 'none');"
                         mouseOver="jspBestPractices1Url.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="More JSP Best Practices"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="jspBestPractices2Url"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html'>http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html&lt;/a>"
                         selectable="true"
                         mouseOut="jspBestPractices2Url.setStyle('textDecoration', 'none');"
                         mouseOver="jspBestPractices2Url.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Extends is Evil"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="evilExtendsUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html'>http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html&lt;/a>"
                         selectable="true"
                         mouseOut="evilExtendsUrl.setStyle('textDecoration', 'none');"
                         mouseOver="evilExtendsUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Getter and Setter Methods Are Evil"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="getSetEvilUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html'>http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html&lt;/a>"
                         selectable="true"
                         mouseOut="getSetEvilUrl.setStyle('textDecoration', 'none');"
                         mouseOver="getSetEvilUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="New Features Added to Servlet 2.5"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Jason Hunter" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="servletUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html'>http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html&lt;/a>"
                         selectable="true"
                         mouseOut="servletUrl.setStyle('textDecoration', 'none');"
                         mouseOver="servletUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="REST for Java Developers, Part 1"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Brian Sletten" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label id="restUrl"
                         htmlText="&lt;a href='http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html'>http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html&lt;/a>"
                         selectable="true"
                         mouseOut="restUrl.setStyle('textDecoration', 'none');"
                         mouseOver="restUrl.setStyle('textDecoration', 'underline');" />
            </mx:GridItem>
         </mx:GridRow>
      </mx:Grid>
   </mx:Panel>
</mx:Application>

Сохраните этот MXML код в файл с именем Example2.mxml. Скомпилируйте его с помощью компилятора mxml, после чего на выходе вы получите Example2.swf, и запустите в браузере. Вы увидите такое же приложение, как на Рисунке 3.

Рисунок 3. Скомпилированное приложение с гипертекстовыми ссылками.

Как мы видим на рисунке/в приложении, к каждой ссылке применён стиль. При наведении курсора мыши на одну из ссылок в таблице, последняя принемает стиль подчеркивания. Такая функциональность реализована с помощью событий mouseOver и mouseOut соответственно. Если мы детально посмотрим на код в нашем втором примере, мы сможем заметить, что он довольно избыточен. Для того, что бы это исправить, давайте напишим собственный компонент, что позволит нам внести гибкость в разработку и избавиться от избыточного кода.

Реализация собственного компонента

Листинг 3 прекрасно демонстрирует создание специализированного компонента Label, использование которого в конечном итоге позволит нам избавиться от избыточного кода в нашем приложении.

Листинг 3. Реализация компонента UrlLabel.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Label xmlns:mx="http://www.adobe.com/2006/mxml"
          selectable="true"
          mouseOut="this.setStyle('textDecoration', 'none');"
          mouseOver="this.setStyle('textDecoration', 'underline');"
          creationComplete="initializeHtmlText();">
   <mx:Script>
   <![CDATA[
   public function initializeHtmlText():void
   {
      this.htmlText = "<a href='" + this.text + "'>" + this.text + "</a>";
   }
   ]]>
   </mx:Script>
</mx:Label>

Листинг 3 описывает создание нового компонента UrlLabel(заметьте, имя компонента соответствует с именем файла UrlLabel.mxml).  Этот компонент инкапсулирует процесс создания ссылки, а также задает поведение для таких событий, как mouseOut и mouseOver. Проведя небольшой рефакторинг кода из Листинга 3, мы получаем менее избыточный код в Листинге 4.

Листинг 4. Пример использования собственного компонента UrlLabel.mxml

<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:jw="components.*"
                width="1100" height="700">
   <mx:Style>
   .articleTitle
   {
      font-weight: bold;
   }
   .gridLabel
   {
      font-weight: bold;
      font-size: 14;
   }
   </mx:Style>
   <mx:Panel title="Some of Dustin's Favorite JavaWorld Articles">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                styleName="gridLabel" />
      <mx:Grid>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Designing with Exceptions"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="exceptionsUrl"
                            text="http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Inheritance Versus Composition"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Bill Venners" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="inheritanceUrl"
                            text="http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="JSP Best Practices"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="jspBestPractices1Url"
                            text="http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="More JSP Best Practices"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Dustin Marx" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="jspBestPractices2Url"
                            text="http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Extends is Evil"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="evilExtendsUrl"
                            text="http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="Why Getter and Setter Methods Are Evil"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Allen Holub" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="getSetEvilUrl"
                            text="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="New Features Added to Servlet 2.5"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Jason Hunter" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="servletUrl"
                            text="http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html" />
            </mx:GridItem>
         </mx:GridRow>
         <mx:GridRow>
            <mx:GridItem>
               <mx:Label text="REST for Java Developers, Part 1"
                         styleName="articleTitle" />
            </mx:GridItem>
            <mx:GridItem>
               <mx:Label text="Brian Sletten" />
            </mx:GridItem>
            <mx:GridItem>
               <jw:UrlLabel id="restUrl"
                            text="http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html" />
            </mx:GridItem>
         </mx:GridRow>
      </mx:Grid>
   </mx:Panel>
</mx:Application>

Дополнительный рефакторинг

Если мы вынесем создание каждого элемента GridRow в наш собственный компонент, мы существенно упрости код приложения. Листинг 5демонстрирует нам создание собственного ArticleGridRow компонента.

Листинг 5. ArticleGridRow.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:GridRow xmlns:mx="http://www.adobe.com/2006/mxml"
            xmlns:jw="components.*">
   <mx:Script>
   <![CDATA[
   [Bindable] public var articleUrl:String = "N/A";
   [Bindable] public var articleTitle:String = "N/A";
   [Bindable] public var articleAuthor:String = "N/A";
   ]]>
   </mx:Script>

   <mx:GridItem>
      <mx:Label text="{articleTitle}" styleName="articleTitle" />
      </mx:GridItem>
      <mx:GridItem>
         <mx:Label text="{articleAuthor}" />
      </mx:GridItem>
      <mx:GridItem>
      <jw:UrlLabel text="{articleUrl}" />
   </mx:GridItem>
</mx:GridRow>

ArticleGridRow.mxml использует уже написаный нами ранее компонент UrlLabel и инкапсулирует процесс создания строки для нашей таблицы. Этот компактный компонент делает код нашего приложения более гибким, в чем вы можете удостовериться просмотрев Листинг 6.

Листинг 6. Example4.mxml

<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:jw="components.*"
                width="1100" height="700">
   <mx:Style>
   .articleTitle
   {
      font-weight: bold;
   }
   .gridLabel
   {
      font-weight: bold;
      font-size: 14;
   }
   </mx:Style>
   <mx:Panel title="Some of Dustin's Favorite JavaWorld Articles">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                styleName="gridLabel" />
      <mx:Grid>
         <jw:ArticleGridRow articleTitle="Designing with Exceptions"
                            articleAuthor="Bill Venners"
                            articleUrl="http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html" />
         <jw:ArticleGridRow articleTitle="Inheritance Versus Composition"
                            articleAuthor="Bill Venners"
                            articleUrl="http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html" />
         <jw:ArticleGridRow articleTitle="JSP Best Practices"
                            articleAuthor="Dustin Marx"
                            articleUrl="http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html" />
         <jw:ArticleGridRow articleTitle="More JSP Best Practices"
                            articleAuthor="Dustin Marx"
                            articleUrl="http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html" />
         <jw:ArticleGridRow articleTitle="Why Extends is Evil"
                            articleAuthor="Allen Holub"
                            articleUrl="http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html" />
         <jw:ArticleGridRow articleTitle="Why Getter and Setter Methods Are Evil"
                            articleAuthor="Allen Holub"
                            articleUrl="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html" />
         <jw:ArticleGridRow articleTitle="New Features Added to Servlet 2.5"
                            articleAuthor="Jason Hunter"
                            articleUrl="http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html" />
         <jw:ArticleGridRow articleTitle="REST for Java Developers, Part 1"
                            articleAuthor="Brian Sletten"
                            articleUrl="http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html" />
      </mx:Grid>
   </mx:Panel>
</mx:Application>

Итак, наше Flex приложение уже:

  • Использует CSS стили
  • Демонстрирует грамматику и синтаксис языка разметки MXML
  • Демонстрирует создание собственных компонентов

Не смотря на пункты указанные выше, процесс работы с данными в нашем приложение остается статическим, т.е. таким, которое не работает с динамическими данными.

Совмещаем Java EE и Flex

Flex предоставляет несколько типов таблиц, поддерживающих работу с динамическими данными. Мы сфокусируемся на главном компоненте DataGrid, который поставляется вместе с Flex SDK (в состав стандартных компонентов Flex так же входит AdvancedDataGrid, кроме этого так же доступны компоненты сторонних разработчиков).

The Flex 3 Language Reference и Flex 3 Component Explorer включают примеры исходного кода визуальных компонентов.

Давайте рассмотрим версию кода нашего приложения после рефакторинга, приведённую в Листинге 7, которая использует компонент DataGrid.

Листинг 7. Example5.mxml

<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:jw="components.*"
                width="1100" height="700">
   <mx:Style>
   .articleTitle
   {
      font-weight: bold;
   }
   .gridLabel
   {
      font-weight: bold;
      font-size: 14;
   }
   </mx:Style>
   <mx:XMLList id="articles">
      <article>
         <title>Designing with Exceptions</title>
         <author>Bill Venners</author>
         <url>http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html</url>
      </article>
      <article>
         <title>Inheritance Versus Composition</title>
         <author>Bill Venners</author>
         <url>http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html</url>
      </article>
      <article>
         <title>JSP Best Practices</title>
         <author>Dustin Marx</author>
         <url>http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html</url>
      </article>
      <article>
         <title>More JSP Best Practices</title>
         <author>Dustin Marx</author>
         <url>http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html</url>
      </article>
      <article>
         <title>Why Extends is Evil</title>
         <author>Allen Holub</author>
         <url>http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html</url>
      </article>
      <article>
         <title>Why Getter and Setter Methods Are Evil</title>
         <author>Allen Holub</author>
         <url>http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html</url>
      </article>
      <article>
         <title>New Features Added to Servlet 2.5</title>
         <author>Jason Hunter</author>
         <url>http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html</url>
      </article>
      <article>
         <title>REST for Java Developers, Part 1</title>
         <author>Brian Sletten</author>
         <url>http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html</url>
      </article>
   </mx:XMLList>

   <mx:Panel id="mainPanel" title="Some of Dustin's Favorite JavaWorld Articles"
             width="{application.width}">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                styleName="gridLabel" />
      <mx:DataGrid id="dataGrid"
                   width="{mainPanel.width*0.9}"
                   rowCount="5" dataProvider="{articles}"
                   editable="false">
            <mx:columns>
                <mx:DataGridColumn id="titleColumn"
                                   dataField="title"
                                   headerText="Article Title"
                                   width="{dataGrid.width*0.25}"
                                   editable="false" />
                <mx:DataGridColumn id="authorColumn"
                                   dataField="author"
                                   headerText="Article Author"
                                   width="{dataGrid.width*0.25}"
                                   editable="false" />
                <mx:DataGridColumn id="urlColumn"
                                   dataField="url"
                                   headerText="Article URL"
                                   editable="true">
                  <mx:itemRenderer>
                     <mx:Component>
                        <jw:UrlLabel />
                     </mx:Component>
                  </mx:itemRenderer>
                </mx:DataGridColumn>
            </mx:columns>
      </mx:DataGrid>
   </mx:Panel>
</mx:Application>

В Листинге 7 мы заменили компонент Grid на DataGrid. Использование компонента DataGrid даёт нам прекрасную возможность работать с данными через dataProvider аттрибут, этим самым отделяя модель (XMLList) от вида (DataGrid).

Скомпилировав Example5.mxml мы получим приложение, показанное на рисунке 4.

Рисунок 4. Использование DataGrid компонента (кликните на рисунке чтобы увеличить).

Как показано на рисунке 4, количество отображаемых записей соответствует значению аттрибута rowCount. Строки компонента DataGrid могут быть как отсортированы, так и изменены в размере по высоте.

Не смотря на то, что мы вынесли данные в XMLList, мы всё ещё имеем проблему хардкодинга в нашем последнем примере. В следующем примере мы воспользуемся данными, приходящими с сервера. Для этого мы обратимся к входящему в состав Flex HTTPService сервису, использование которого описано в Листинге 8.

Листинг 8. Example6.mxml

<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:jw="components.*"
                width="1100" height="700"
                applicationComplete="articles.send();">
   <mx:Style>
   .articleTitle
   {
      font-weight: bold;
   }
   .gridLabel
   {
      font-weight: bold;
      font-size: 14;
   }
   </mx:Style>

   <mx:Script>
   import mx.controls.Alert;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;
   import mx.rpc.Fault;
   import mx.utils.ObjectUtil;

   public function faultHandler(event:FaultEvent):void
   {
      const fault:Fault = event.fault;
      const faultString:String =
           "FAULT CODE: " + fault.faultCode + "nn"
         + "FAULT DETAIL: " + fault.faultDetail + "nn"
         + "FAULT STRING: " + fault.faultString + "nn";
      Alert.show( "FAULT!nn" + faultString );
   }

   public function resultHandler(event:ResultEvent):void
   {
      trace("Response from service received.");
      // The ResultEvent includes a property "message" that contains
      //   the actual payload/contents of the result.  This is useful
      //   when no fault is occurring, but no data is being displayed
      //   in the component either.
   }
   </mx:Script>

   <mx:HTTPService id="articles"
                   url="http://localhost:8080/jwFlexJEEArticles/articles"
                   method="GET"
                   resultFormat="e4x"
                   fault="faultHandler(event);"
                   result="resultHandler(event);" />

   <mx:Panel id="mainPanel"
             title="Some of Dustin's Favorite JavaWorld Articles"
             width="{application.width}">
      <mx:Label text="A Small Sample of Favorite JavaWorld Articles"
                styleName="gridLabel" />
      <mx:DataGrid id="dataGrid"
                   width="{mainPanel.width*0.9}"
                   rowCount="5" dataProvider="{articles.lastResult.article}"
                   editable="false">
            <mx:columns>
                <mx:DataGridColumn id="titleColumn"
                                   dataField="title"
                                   headerText="Article Title"
                                   width="{dataGrid.width*0.25}"
                                   editable="false" />
                <mx:DataGridColumn id="authorColumn"
                                   dataField="author"
                                   headerText="Article Author"
                                   width="{dataGrid.width*0.25}"
                                   editable="false" />
                <mx:DataGridColumn id="urlColumn"
                                   dataField="url"
                                   headerText="Article URL"
                                   editable="true">
                  <mx:itemRenderer>
                     <mx:Component>
                        <jw:UrlLabel />
                     </mx:Component>
                  </mx:itemRenderer>
                </mx:DataGridColumn>
            </mx:columns>
      </mx:DataGrid>
   </mx:Panel>
</mx:Application>

Сейчас, когда мы имеем HTTPService связанный с определённым URL, нам необходимо реадизовать ответ на запрос. В этом нам поможет простой сервлет, приведённый в Листинге 9.

Листинг 9. ArticleServer.java

package javaworld.dustin;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Simplistic servlet to serve up basic article information.
 *
 * @author Dustin
 */
public class ArticleServer extends HttpServlet
{
   /**
    * Handles the HTTP <code>GET</code> method.
    *
    * @param request Servlet request.
    * @param response Servlet response.
    * @throws ServletException
    * @throws IOException
    */
   @Override
   protected void doGet(
      final HttpServletRequest request, final HttpServletResponse response)
      throws ServletException, IOException
   {
      response.setContentType("text/html;charset=UTF-8");
      final PrintWriter out = response.getWriter();
      try
      {
         final ServletContext context = this.getServletContext();
         final InputStream articlesXmlInput =
            context.getResourceAsStream("/Articles.xml");
         final InputStreamReader reader = new InputStreamReader(articlesXmlInput);
         final BufferedReader bufferedReader = new BufferedReader(reader);
         String line = null;
         while ((line = bufferedReader.readLine()) != null)
         {
            out.println(line);
         }
      }
      finally
      {
         out.close();
      }
   } 

   /**
    * Handles the HTTP <code>POST</code> method.
    * @param request servlet request
    * @param response servlet response
    * @throws ServletException
    * @throws IOException
    * @throws UnsupportedOperationException Thrown if this method is called
    *    because this method is not intended for clients to call.
    */
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException
   {
      throw new UnsupportedOperationException(
         "Only GET HTTP method applies for this service.");
   }

   /**
    * Returns a short description of the servlet.
    */
   @Override
   public String getServletInfo()
   {
      return "Provides basic information on select JavaWorld articles via GET request.";
   }
}

Этот сервлет возвращает содержимое файла Articles.xml, приведённого в Листинге 10.

Листинг 10. Articles.xml

<?xml version="1.0" encoding="UTF-8"?>
<Articles>
   <article>
      <title>Designing with Exceptions</title>
      <author>Bill Venners</author>
      <url>http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html</url>
   </article>
   <article>
      <title>Inheritance Versus Composition</title>
      <author>Bill Venners</author>
      <url>http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html</url>
   </article>
   <article>
      <title>JSP Best Practices</title>
      <author>Dustin Marx</author>
      <url>http://www.javaworld.com/javaworld/jw-11-2001/jw-1130-jsp.html</url>
   </article>
   <article>
      <title>More JSP Best Practices</title>
      <author>Dustin Marx</author>
      <url>http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-morejsp.html</url>
   </article>
   <article>
      <title>Why Extends is Evil</title>
      <author>Allen Holub</author>
      <url>http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html</url>
   </article>
   <article>
      <title>Why Getter and Setter Methods Are Evil</title>
      <author>Allen Holub</author>
      <url>http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html</url>
   </article>
   <article>
      <title>New Features Added to Servlet 2.5</title>
      <author>Jason Hunter</author>
      <url>http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html</url>
   </article>
   <article>
      <title>REST for Java Developers, Part 1</title>
      <author>Brian Sletten</author>
      <url>http://www.javaworld.com/javaworld/jw-10-2008/jw-10-rest-series-1.html</url>
   </article>
</Articles>

Листинг 11 отображает содержимое web.xml файла.

Листинг 11. web.xml

<?xml version = '1.0' encoding = 'utf-8'?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee">
   <display-name>JavaWorld Flex/Java EE Part 1 Article</display-name>
   <description>Server-side functionality for JavaWorld Flex/Java EE Part 1 Article</description>
   <servlet>
      <servlet-name>ArticleServer</servlet-name>
      <servlet-class>javaworld.dustin.ArticleServer</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>ArticleServer</servlet-name>
      <url-pattern>/articles</url-pattern>
   </servlet-mapping>

   <session-config>
      <session-timeout>35</session-timeout>
   </session-config>
   <mime-mapping>
      <extension>html</extension>
      <mime-type>text/html</mime-type>
   </mime-mapping>
   <mime-mapping>
      <extension>txt</extension>
      <mime-type>text/plain</mime-type>
   </mime-mapping>
</web-app>

Теперь наступило время собрать и развернуть приложение на одном из серверов приложений (в нашем случае использование контейнера сервлетов Tomcat будет достаточным).

Тэги: ,

Оставить сообщение