JSF 2 fu: Компоненты с поддержкой Ajax

Разработка Ajax-компонентов многократного использования средствами JSF 2

Этой публикацией Дэвид Джири, член экспертной группы JSF 2.0, начинает новую серию статей, рассчитанную на углубленное изучение технологий JSF 2. Первая статья серии расскажет о возможностях интеграции составных компонентов JSF 2 с технологией Ajax, поддерживаемой инфраструктурой JSF 2.

Дэвид Джири, президент, Clarity Training, Inc.

David GearyАвтор, лектор и консультант Дэвид Джири является президентом компании Clarity Training, Inc., Он обучает разработчиков создавать Web-приложения с использованием JSF и Google Web Toolkit (GWT). Он участвовал в экспертных группах JSTL 1.0 и JSF 1.0/2.0, был соавтором сертификационного экзамена Web Developer Certification Exam компании Sun, а также принимал участие в проектах с открытым кодом, в том числе Apache Struts и Apache Shale. Книга Дэвида Graphic Java Swing стала одной из самых продаваемых книг о Java, а Core JSF (в соавторстве с Кэем Хорстманом) - одна из самых продаваемых книг о JSF. Дэвид регулярно выступает на конференциях и встречах пользовательских групп. Он является регулярным участником конференций NFJS с 2003 года, проводил курсы в университете Java и дважды удостаивался звания JavaOne rock star.



19.10.2011

Составные компоненты и поддержка Ajax являются, пожалуй, наиболее привлекательными из всего спектра новых возможностей JSF 2. Однако преимущества каждой этих возможностей проявляются в наиболее выигрышном свете при их совместном использовании. Сочетание Ajax и составных компонентов предоставляет вам уникальную возможность с минимальными усилиями создавать пользовательские компоненты с поддержкой Ajax.

Об этой серии статей

Серия JSF 2 fu является продолжением серии из трех ознакомительных статей и публикуется под тем же названием. Статьи второй серии помогут вам отточить навыки JSF 2 и стать настоящим мастером кун-фу в вопросах использования инфраструктуры JSF 2. Вторая серия поможет вам глубже изучить возможности JSF 2 и его экосистемы, а также представит краткий обзор возможностей интеграции Java EE технологий, таких как CDI (Contexts and Dependency Injection), с JSF.

В этой статье я расскажу вам, как создать компонент автозаполнения текстового поля, который использует Ajax для управления списком элементов заполнения. В процессе разработки вы узнаете, как интегрировать Ajax в ваши составные компоненты.

Примеры, используемые в этой серии статей, основаны на JSF 2, работающем на сервере приложений, таком, как GlassFish или Resin. Последний раздел статьи представляет собой пошаговую инструкцию по установке и запуску приложения, рассматриваемого в данной статье, на сервере GlassFish.

Пользовательский компонент автозаполнения текстового поля в JSF

Поля с функцией автозаполнения, или поля с подсказкой, получившие свою популярность благодаря строке поиска Google, сейчас являются основным компонентом множества веб-приложений. Они же представляют собой наиболее типичный случай использования Ajax. Поля с функцией автозаполнения входят в состав большинства инфрастуктур Ajax (например, Scriptaculous и JQuery). Например, на рисунке 1— показан экран коллекции компонентов автозаполнения AjaxDaddy (см. Ресурсы).

Рисунок 1. Компоненты автозаполнения AjaxDaddy
Screen shot of AjaxDaddy

В этой статье мы рассмотрим один из способов реализации в JSF текстового поля с функцией автозаполнения, использующей вызовы Ajax. Наш пример будет выводить показанное на рисунке 2, текстовое поле, которое предназначено для ввода названия вымышленной страны (список стран позаимствован из статьи Википедии "Список вымышленных стран" - см. Ресурсы):

Рисунок 2. Текстовое поле с функцией автозаполнения
The autocomplete field

На рисунке 3 и 4 показано, как работает наше поле с функцией автозаполнения. Рисунок 3 соответствует ситуации, когда пользователь набрал в поле Al, при этом список стран, предлагаемых ему для ввода, сокращается, ограничиваясь только теми названиями, которых начинаются с введенных пользователем букв:

Рисунок 3. Элементы автозаполнения, названия которых начинаются с Al
Completion items that start with Al

Аналогичный пример продемонстрирован на рисунке 4, только в этом случае пользователь набрал Bar. Как и в предыдущем примере, список стран, предлагаемых для заполнения поля, содержит только те страны, чье название начинается с Bar.

Рисунок 4. Элементы автозаполнения, названия которых начинаются с Bar
Completion items that start with Bar

Использование компонента автозаполнения

Составные компоненты: основы

Если вы еще не знакомы с принципами разработки и использования составных компонентов JSF 2, статья JSF 2 fu: Часть 2. Шаблоны и составные компоненты поможет вам освоить основные шаги по их реализации.

Поле Locations с функцией автозаполнения является составным компонентом JSF и используется в facelet, приведенном в листинге 1:

Листинг 1. Facelet
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:util="http://java.sun.com/jsf/composite/util">
   <h:head>
      <title>#{msgs.autoCompleteWindowTitle}</title>
   </h:head>

   <h:body>
      <div style="padding: 20px;">
         <h:form>
            <h:panelGrid columns="2">
               #{msgs.locationsPrompt}
               <util:autoComplete value="#{user.country}"
                     completionItems="#{autoComplete.countries}" />
            </h:panelGrid>
         </h:form>
      </div>
   </h:body>
</html>

Как вы видите, facelet, приведенный в листинге 1, использует составной компонент autoComplete - на это указывает декларация соответствующего пространства имен util и использование тега компонента <util:autoComplete>.

Обратите внимание на два атрибута тега <util:autoComplete>, показанные в листинге 1:

  • в качестве value используется свойство country управляемого bean-компонента user.
  • completionItems соответствует полному списку вариантов заполнения поля.

Класс User - это простой управляемый bean-компонент, который вводится, очевидно, только для создания автозаполняемого поля. Код класса показан в листинге 2:

Листинг 2. Класс User
package com.corejsf;

import java.io.Serializable;

import javax.inject.Named; 
import javax.enterprise.context.SessionScoped; 

@Named()
@SessionScoped
public class User implements Serializable {
  private String country;
  public String getCountry() { return country; }
  public void setCountry(String country) { this.country = country; }
}

Обратите внимание на аннотацию @Named, которая, в сочетании с аннотацией @SessionScoped, и создает управляемый bean-компонент с именем user в рамках одного сеанса в тот момент, когда JSF в первый раз встречает #{user.country} в facelet. Единственный указатель на элемент этого класса #{user.country} используется в листинге 1, когда я объявляю свойство country управляемого bean-компонента user в качестве значения для компонента <util:autoComplete>.

В листинге 3 приведен код класса AutoComplete, который определяет свойство countries. Это свойство я использую в качестве полного списка всех вариантов заполнения поля:

Листинг 3. Список элементов для заполнения поля
package com.corejsf;

import java.io.Serializable;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

@Named
@ApplicationScoped
public class AutoComplete implements Serializable {
   public String[] getLocations() {
      return new String[] {
    		  "Abari", "Absurdsvanj", "Adjikistan", "Afromacoland",
    		  "Agrabah", "Agaria", "Aijina", "Ajir", "Al-Alemand",
    		  "Al Amarja", "Alaine", "Albenistan", "Aldestan",
    		  "Al Hari", "Alpine Emirates", "Altruria",
    		  "Allied States of America", "BabaKiueria", "Babalstan",
    		  "Babar's Kingdom","Backhairistan", "Bacteria",
    		  "Bahar", "Bahavia", "Bahkan", "Bakaslavia",
    		  "Balamkadar", "Baki", "Balinderry", "Balochistan",
    		  "Baltish", "Baltonia", "Bataniland, Republic of",
    		  "Bayview", "Banania, Republica de", "Bandrika",
    		  "Bangalia", "Bangstoff", "Bapetikosweti", "Baracq",
    		  "Baraza", "Barataria", "Barclay Islands",
    		  "Barringtonia", "Bay View", "Basenji",
      };
   }
}

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


Как работает компонент автозаполнения

Компонент автозаполнения является составным компонентом JSF 2, поэтому, как и большинство составных компонентов, он реализуется в виде XHTML-файла. Компонент состоит из поля для ввода текста, списка значений для автозаполнения и некоторого количества JavaScript-кода. Сначала в качестве параметра style для отображения списка используется конструкция display: none, что делает список невидимым.

Компонент автозаполнения реагирует на три типа событий:

  • keyup - ввод текста в текстовом поле
  • blur - потеря фокуса текстовым полем
  • change - выбор значения из списка автозаполнения

Когда пользователь вводит какой-либо символ в текстовом поле, в ответ на событие keyup компонент автозаполнения вызывает функцию JavaScript. Эта функция «склеивает» несколько событий нажатия клавиши в одно, чтобы вызов Ajax выполнялся не чаще чем один раз в 350 миллисекунд. Таким образом, в ответ на событие keyup в текстовом поле (но не чаще, чем раз в 350 миллисекунд) компонент автозаполнения выполняет Ajax-обращение к серверу. Ограничение частоты вызовов необходимо для того, чтобы пользователи, обладающие высокой скоростью печати, не создавали чрезмерно большого потока вызовов Ajax. На практике требованием «склеивания» часто повторяющихся событий можно пренебречь, однако имеет смысл разобрать реализацию «склеивания» событий в JavaScript на конкретном примере, поскольку эта функциональность довольно часто используется при решении практических задач.

Когда пользователь выбирает нужное значение из списка, компонент автозаполнения выполняет еще одно Ajax-обращение к серверу.

Для текстового поля и списка элементов автозаполнения существуют свои собственные обработчики событий («слушатели»), которые, в ответ на Ajax-вызовы, и выполняют всю основную работу на сервере. В ответ на событие keyup обработчик событий текстового поля обновляет список элементов, предлагаемых для заполнения, а при выборе пользователем значения из списка обработчик событий списка копирует выбранное значение в поле для ввода и затем прячет список.

Теперь, когда мы разобрались с тем, как работает компонент автозаполнения, перейдем к его реализации.


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

Компонент автозаполнения текстового поля состоит из следующих частей:

  • Составной компонент
  • Набор функций JavaScript
  • Обработчик событий, который меняет список предлагаемых вариантов для автозаполнения.

Начнем с составного компонента, код которого приведен в листинге 4:

Листинг 4. Компонент autoComplete
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"    
    xmlns:composite="http://java.sun.com/jsf/composite">
    
    <!-- INTERFACE -->
    <composite:interface>
      <composite:attribute name="value" required="true"/>
      <composite:attribute name="completionItems" required="true"/>
    </composite:interface> 

    <!-- IMPLEMENATION -->          
    <composite:implementation>
      <div id="#{cc.clientId}">
        <h:outputScript library="javascript" 
           name="prototype-1.6.0.2.js" target="head"/>
        
        <h:outputScript library="javascript" 
           name="autoComplete.js" target="head"/>
      
        <h:inputText id="input" value="#{cc.attrs.value}" 
           onkeyup="com.corejsf.updateCompletionItems(this, event)"
           onblur="com.corejsf.inputLostFocus(this)"
           valueChangeListener="#{autocompleteListener.valueChanged}"/>
            
        <h:selectOneListbox id="listbox" style="display: none"
           valueChangeListener="#{autocompleteListener.completionItemSelected}">
        
            <f:selectItems value="#{cc.attrs.completionItems}"/>
            <f:ajax render="input"/>
          
        </h:selectOneListbox>
      <div>
    </composite:implementation>    
</ui:composition>

В секции IMPLEMENATION кода, приведенного в листинге 4, происходят три вещи. Во-первых, компонент осуществляет вызов Ajax в ответ на событие keyup в текстовом поле, а при потере фокуса текстовым полем компонент скрывает список предлагаемых значений. Эти операции выполняются посредством функций JavaScript, определенных для обработки событий keyup и blur в поле для ввода.

Во-вторых, компонент выполняет Ajax-вызовы для событий change в списке значений – на это указывает тег JSF 2 <f:ajax>. При выборе пользователем значения из списка JSF выполняет Ajax-обращение к серверу и по возвращении вызова Ajax обновляет значение в текстовом поле.

Инкапсуляция составных компонентов в тег <div>

Составной компонент, приведенный в листинге 4, инкапсулирован в тег <div> с идентификатором клиента этого компонента. Такой подход позволяет другим компонентам ссылаться на компонент автозаполнения по его идентификатору клиента. Например, некий сторонний компонент в процессе выполнения Ajax-вызова может запустить один или несколько компонентов автозаполнения.

В-третьих, и для текстового поля, и для списка значений определяются методы обработки событий, которые отслеживают изменения значений этих объектов. Таким образом, при выполнении Ajax-вызовов в ответ на ввод новых символов в текстовом поле JSF активизирует на сервере обработчик событий текстового поля. Когда пользователь выбирает значение из предлагаемого списка, JSF выполняет Ajax-обращение к серверу и активизирует обработчик событий списка.

JavaScript код, используемый компонентом автозаполнения, показан в листинге 5.

Листинг 5. Код JavaScript
if (!com)
   var com = {}

if (!com.corejsf) {
   var focusLostTimeout
   com.corejsf = {
      errorHandler : function(data) {
         alert("Error occurred during Ajax call: " + data.description)
      },

      updateCompletionItems : function(input, event) {
         var keystrokeTimeout

         jsf.ajax.addOnError(com.corejsf.errorHandler)

         var ajaxRequest = function() {

            jsf.ajax.request(input, event, {
               render: com.corejsf.getListboxId(input),
               x: Element.cumulativeOffset(input)[0],
               y: Element.cumulativeOffset(input)[1]
                     + Element.getHeight(input)
            })
         }

         window.clearTimeout(keystrokeTimeout)
         keystrokeTimeout = window.setTimeout(ajaxRequest, 350)
      },

      inputLostFocus : function(input) {
         var hideListbox = function() {
            Element.hide(com.corejsf.getListboxId(input))
         }

         focusLostTimeout = window.setTimeout(hideListbox, 200)
      },

      getListboxId : function(input) {
         var clientId = new String(input.name)
         var lastIndex = clientId.lastIndexOf(':')
         return clientId.substring(0, lastIndex) + ':listbox'
      }
   }
}

Код JavaScript, приведенный в листинге 5, состоит из трех функций, помещенных мной в пространство имен com.corejsf. Я использовал отдельное пространство имен (которое технически является строковой константой JavaScript), чтобы предотвратить случайное (или намеренное) затирание какой-нибудь из моих функций.

Если не включить эти функции в отдельное пространство имен com.corejsf, кто-нибудь может реализовать свою собственную функцию updateCompletionItems, которая подменит мою реализацию. Кроме того, вполне возможно, что какая-нибудь из библиотек JavaScript тоже содержит в себе функцию updateCompletionItems. Однако мы можем с высокой вероятностью утверждать, что никто другой не разработал еще одну функцию с именем com.corejsf.updateCompletionItems (вообще-то можно было бы опустить com и ограничиться corejsf.updateCompletionItems, но такими упрощениями легко увлечься и утратить бдительность).

Итак, что же делают наши функции JavaScript? Функция updateCompletionItems() осуществляет Ajax-обращение к серверу путем вызова JSF функции jsf.ajax.request(). Задача этой функции - указать JSF, что по возвращении Ajax-вызова следует запустить компонент listbox. Кроме того, updateCompletionItems() передает функции jsf.ajax.request() два дополнительных параметра: координаты x и y левого верхнего угла списка значений. Функция jsf.ajax.request() преобразует эти параметры функции в параметры запроса, который будет отправлен вместе с Ajax-вызовом.

При потере фокуса текстовым полем JFS вызывает функцию inputLostFocus(). Эта функция попросту прячет список элементов автозаполнения, используя объект Element библиотеки Prototype.

Функциональность updateCompletionItems() и inputLostFocus() хранится во вспомогательных функциях; при этом они устанавливают тайм-аут на выполнение этих функций в 350 и 200 миллисекунд соответственно. Другими словами, каждая из функций должна выполнить определенное действие, но само действие откладывается на 350 или 200 миллисекунд. После нажатия клавиши в текстовом поле соответствующий символ отображается с задержкой, так что метод updateCompletionItems() генерирует Ajax-вызов не чаще чем раз в 350 миллисекунд. Основная идея использования подобного запаздывания состоит в том, чтобы пользователь, обладающий (необыкновенно!) высокой скоростью печати, не мог перегрузить сервер вызовами Ajax.

Функция inputLostFocus, вызываемая при потере фокуса текстовым полем, работает с запаздыванием в 200 миллисекунд. Подобная задержка необходима для того, чтобы по возвращении из Ajax-вызова текстовое поле было видимым и можно было скопировать его текущее значение.

И, наконец, функция getListBoxId(). Это вспомогательная функция, которая получает идентификатор клиента списка через идентификатор клиента текстового поля. Функция в состоянии проделать такую операцию, поскольку она работает в связке с компонентом autoComplete (см. листинг 4). Компонент autoComplete определяет input и listbox как идентификаторы компонентов текстового поля и списка значений соответственно, так что для того, чтобы получить идентификатор клиента списка, getListBoxId() просто отрезает input и добавляет listbox.

Код обработчика событий, который связывает все функции воедино, показан в листинге 6.

Листинг 6. Обработчик событий
package com.corejsf;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIInput;
import javax.faces.component.UISelectItems;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.inject.Named;

@Named
@SessionScoped
public class AutocompleteListener implements Serializable {
   private static String COMPLETION_ITEMS_ATTR = "corejsf.completionItems";
  
   public void valueChanged(ValueChangeEvent e) {
      UIInput input = (UIInput)e.getSource();
      UISelectOne listbox = (UISelectOne)input.findComponent("listbox");

      if (listbox != null) {
         UISelectItems items = (UISelectItems)listbox.getChildren().get(0);
         Map<String, Object> attrs = listbox.getAttributes();
         List<String> newItems = getNewItems((String)input.getValue(),
            getCompletionItems(listbox, items, attrs));

         items.setValue(newItems.toArray());
         setListboxStyle(newItems.size(), attrs);
      }
   }
  
   public void completionItemSelected(ValueChangeEvent e) {
     UISelectOne listbox = (UISelectOne)e.getSource();
     UIInput input = (UIInput)listbox.findComponent("input");
    
     if(input != null) {
        input.setValue(listbox.getValue());
     }
     Map<String, Object> attrs = listbox.getAttributes();
     attrs.put("style", "display: none");
   }
   
   private List<String> getNewItems(String inputValue, String[] completionItems) {
      List<String> newItems = new ArrayList<String>();
    
      for (String item : completionItems) {
         String s = item.substring(0, inputValue.length());
         if (s.equalsIgnoreCase(inputValue))
           newItems.add(item);
      }
    
      return newItems;
   }
  
   private void setListboxStyle(int rows, Map<String, Object> attrs) {
      if (rows > 0) {
         Map<String, String> reqParams = FacesContext.getCurrentInstance()
            .getExternalContext().getRequestParameterMap();
      
         attrs.put("style", "display: inline; position: absolute; left: "
             + reqParams.get("x") + "px;" + " top: " + reqParams.get("y") + "px");

         attrs.put("size", rows == 1 ? 2 : rows);
      }
      else
         attrs.put("style", "display: none;");
   }

   private String[] getCompletionItems(UISelectOne listbox,
      UISelectItems items, Map<String, Object> attrs) {
         Strings] completionItems = (String[])attrs.get(COMPLETION_ITEMS_ATTR);
    
         if (completionItems == null) {
            completionItems = (String[])items.getValue();
            attrs.put(COMPLETION_ITEMS_ATTR, completionItems);
         }
      return completionItems;
   }
}

В результате Ajax-вызова, сгенерированного в результате нажатия клавиши на клавиатуре, JSF активизирует метод valueChanged() обработчика событий. Этот метод создает новый набор элементов автозаполнения и присваивает параметрам списка значения нового набора. Кроме этого, valueChanged() устанавливает атрибут style списка для определения его видимости при возвращении Ajax-вызова.

Метод setListboxStyle(), приведенный в листинге 6, использует параметры x и y, значения которых я указываю в Ajax-вызове в листинге 5.

В результате Ajax-вызовов, сгенерированных в ответ на выбор значения из списка, JSF активизирует второй публичный метод обработчика событий, completionItemSelected(). Этот метод копирует выбранное значение из списка в текстовое поле и прячет список.

Обратите внимание на то, что метод valueChanged() сохраняет исходные значения для автозаполнения в качестве атрибута списка. Поскольку каждый компонент autoComplete содержит свой собственный список элементов автозаполнения, несколько компонентов autoComplete вполне способны мирно уживаться на одной и той же странице, не путаясь в своих списках.


Запуск примера с использованием GlassFish и Eclipse

Код, приведенный в этой серии статей, легче всего реализовать с использованием серверов приложений JEE 6, таких, например, как GlassFish или Resin. При определенных дополнительных усилиях можно обойтись и контейнером сервлетов (например, Tomcat). Однако, поскольку моя цель – научить вас полноценно использовать преимущества JSF 2 и JEE 6, а не объяснить, как решать вопросы конфигурации приложений, примеры данной статьи основаны на использовании сервера GlassFish v3.

Далее я покажу вам, как с помощью GlassFish v3 и Eclipse создать и запустить приложение, примеры кода которого мы разобрали выше. Предлагаемые инструкции также применимы ко всем остальным статьям этой серии (для реализации примеров я использую Eclipse версии 3.4.1, так что чем ближе версия используемого вами Eclipse к 3.4.1, тем проще вам будет выполнить все шаги).

На рисунке 5 показана структура каталогов кода, используемого в примерах этой статьи (скачать исходный код можно в разделе Загрузки). Дерево содержит каталог autoComplete с кодом приложения и пустой стандартный для Eclipse каталог workspace.

Рисунок 5. Исходный код примера, используемого в статье
Screen shot of directory structure

После того как вы скачали исходный код, можно переходить к запуску приложения. Для начала вам потребуется Eclipse-плагин GlassFish (см. рисунок 6), скачать который можно по ссылке https://glassfishplugins.dev.java.net.

Рисунок 6. Плагин GlassFish для Eclipse
Screen shot of GlassFish eclipse plug-in Web page

Скачайте плагин и установите его, следуя инструкции по установке. Теперь у вас есть все, что нужно для работы приложения.

Для загрузки кода в Eclipse создайте динамический веб-проект. Для этого откройте в меню File выберите пункт New. Если в списке проектов нет опции Dynamic Web project, выберите пункт Other, в предлагаемом списке выберите папку Web и в списке элементов щелкните на Dynamic Web Project (см. рисунок 7).

Рисунок 7. Создание Dynamic Web project
Screen shot of Dynamic Web project dialog

Далее нужно настроить конфигурацию нашего проекта. В первом окне мастера Dynamic Web Project укажите следующие настройки (см. рисунок 8):

  1. В разделе Project contents не отмечайте флажок Use default. В поле Directory введите (или выберите с помощью кнопки Browse…) каталог autoComplete с исходным кодом компонента.
  2. В разделе Target Runtime выберите GlassFish v3 Java EE 6.
  3. В разделе Dynamic Web Module version укажите 2.5.
  4. В разделе Configuration выберите Default Configuration for GlassFish v3 Java EE 6.
  5. В разделе EAR Membership оставьте неотмеченным флажок Add project to an EAR. В поле EAR Project Name: укажите autoCompleteEAR.
Рисунок 8. Настройка приложения, шаг 1
Screen shot of creating a Dynamic Web project

Нажмите Next. На следующем шаге укажите настройки конфигурации, как показано на рисунке 9, а именно:

  1. В поле Context Root введите autoComplete.
  2. В поле Content Directory укажите web.
  3. В поле Java Source Directory укажите src/java и оставьте неотмеченным флажок Generate deployment descriptor.
Рисунок 9. Настройка приложения, шаг 2
Screen shot of configuring a Web module

Теперь ваш проект autoComplete должен отображаться в панели Project Explorer Eclipse примерно так, как показано на рисунке 10:

Рисунок 10. Проект autoComplete
Screen shot of the autoComplete project visible in Eclipse's Project Explorer view

Выделите проект и щелкните на нем правой кнопкой мышки. В контекстном меню выберите опцию Run on Server (см. рисунок 11).

Рисунок 11. Опция Run on Server
Screen shot showing the menu item, Run on server, in Eclipse

В списке предлагаемых серверов диалога Run On Server выберите GlassFish v3 Java EE 6 (см. рисунок 12).

Рисунок 12. Выбор сервера GlassFish
Screen shot depicting GlassFish being selected in Run On Server

Нажмите Finish. Eclipse запустит GlassFish, на котором будет выполняться ваше приложение (см. рисунок 13).

Рисунок 13. Запуск приложения в Eclipse
Running in Eclipse

Заключение

С помощью JSF 2 можно легко создавать удобные в применении пользовательские компоненты с поддержкой Ajax. При этом для реализации Ajax-вызовов вам не придется разрабатывать отдельный Java-компонент или рендерер, объявлять этот Java-компонент или рендерер в XML или интегрировать в свое приложение сторонний код JavaScript. Благодаря использованию JSF 2 все, что вам нужно сделать, - это создать составной компонент с разметкой, практически идентичной любому JSF 2 facelet, и, может быть, добавить несколько строк кода JavaScript или Java – и готово! У вас есть прекрасный компонент, который сильно упростит ввод данных для пользователей вашего приложения.

В следующей статье серии JSF fu я расскажу о дополнительных аспектах пользовательских компонентов JSF с поддержкой Ajax, в частности, об использовании тега <f:ajax>, позволяющего вашему компоненту использовать вызовы Ajax, добавленные другими разработчиками.


Загрузка

ОписаниеИмяРазмер
Исходный код примера, используемого в статьеj-jsf2fu-0410-src.zip39 KБ

Ресурсы

Научиться

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

  • JSF:Загрузите JSF 2.0.

Обсудить

Комментарии

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=Технология Java
ArticleID=766667
ArticleTitle=JSF 2 fu: Компоненты с поддержкой Ajax
publish-date=10192011