(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Интеграция XForms и Google Web Toolkit: Часть 3. Используем GWT для создания элементов XForms (исходники)

Майкл Галпин

Введение

В данной статье, мы немного переделаем приложение, созданное в предыдущей части. Как вы помните, приложение позволяет управлять списком исполнителей и их альбомами, и в смысле функциональности, мы ничего менять не будем. Мы лишь поменяем реализацию путем смешивания GWT и XForms на одной странице. Вы увидите насколько просто начать использовать GWT на уже существующей Web-странице. Вы сможете динамически загружать данные на страницу, используя вызовы Ajax через GWT, а затем также динамически создавать модель XForms через интерфейс JSNI, поддерживаемый GWT. Все это позволит упростить нашу страницу. Более того, в целях дальнейшего упрощения даже элементы управления XForms можно будет создать через GWT JSNI. Кроме этого, дополнительным преимуществом использования GWT на страницах XForms является уменьшение размера страниц, что ускоряет их загрузку и отображение в браузере.

Предварительные требования

В данной статье используется GWT версии 1.4 и подключаемый модуль Mozilla XForms версии 0.8. Модуль Mozilla XForms работает с любым браузером на основе Mozilla, например, Firefox или Seamonkey. Использование GWT предполагает определенные знания Java, а так же Web-технологий, таких как HTML и CSS. Кроме этого, в статье широко используется JavaScript. Наконец, поскольку технология XForms разработана в соответствии с парадигмой MVC (Model-View-Control), желательно понимание принципов MVC. В то же время опыт использования GWT или XForms хотя и будет полезным, но не является обязательным.

Динамические страницы XForms?

До этого момента мы использовали XForms для отображения данных, хранящихся в модели внутри страницы. Модель загружалась динамически через скриптлет на JSP, который запрашивал и фильтровал данные, а также записывал их на страницу в виде XML. Теперь же мы сделаем саму XForms-страницу еще более динамической, а именно: вместо записи экземпляров данных внутрь страницы, мы будем асинхронно запрашивать их с сервера, а затем добавлять внутрь существующей модели на странице. Ajax-вызовы будут делаться с помощью GWT, а последующее изменение модели XForms - через JSNI.

Использование GWT на странице XForms

Теперь мы возьмем нашу страницу, отображающую альбомы с помощью XForms, и начнем использовать на ней GWT. Первый вопрос заключается в том, как применить GWT к уже существующей странице. На самом деле, это очень просто. Все, что требуется - это добавить на страницу ссылку на JavaScript-библиотеку, созданную компилятором GWT при преобразовании вашего кода на Java в JavaScript. Подобная библиотека создается одна на каждый модуль. Иными словами, надо просто добавить строчку, как показано в листинге 1.

Листинг 1. Использование GWT на странице для показа альбомов.

                
<xhtml:script language="text/javascript" 
src="org.developerworks.rockstar.RockStarMain.nocache.js"></xhtml:script>

Зачастую разработчики удивляются простоте добавления GWT к существующим страницам. Эта легкость была одной из задач при создании GWT. Несмотря на то, что большинство примеров использования GWT демонстрируют "свежие" приложения, т.е. изначально написанные на GWT, унаследованные (legacy) проекты встречаются на практике ничуть не реже, и от GWT изначально требовалось быть полезной в обоих случаях. Не забывайте, что весь код на GWT - это по сути JavaScript, так что интеграция и должна быть простой. Теперь, после добавления GWT к странице, можно начинать писать GWT-код, а точнее - Java-код, который будет скомпилирован в JavaScript.

Загрузка альбомов через Ajax: используем JSNI для управления данными XForms

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

Создание удаленного сервиса

Для начала создадим интерфейс сервиса, как показано в листинге 2.

Листинг 2. Интерфейс AlbumService

                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface AlbumService extends RemoteService{
     public Album[] getAlbumsForArtist(int artistId);
     public void addAlbum(Album newAlbum);
}

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

Listing 3. Асинхронная версия интерфейса сервиса

                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface AlbumServiceAsync {
     public void getAlbumsForArtist(int artistId, AsyncCallback callback);
     public void addAlbum(Album newAlbum, AsyncCallback callback);
}

И наконец, надо создать серверную реализацию сервиса для обработки клиентских вызовов через HTTP. Реализация должна наследовать стандартный GWT-класс RemoteServiceServlet, как показано в листинге 4.

Листинг 4. Реализация AlbumService

                
package org.developerworks.rockstar.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.developerworks.rockstar.client.Album;
import org.developerworks.rockstar.client.AlbumService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class AlbumServiceImpl extends RemoteServiceServlet implements AlbumService {

     private static final long serialVersionUID = -2706402745094297460L;
     private Map<Integer,List<Album>> albumCache;
     private AlbumDao dao;
     
     public AlbumServiceImpl(){
          this.dao = new AlbumFileDao();
          List<Album> allAlbums = this.dao.getAllAlbums();
          // initialize cache
          int size = allAlbums.size();
          this.albumCache = new HashMap<Integer, List<Album>>(size);
          for (Album album : allAlbums){
               int artistId = album.getArtistId();
               List<Album> albums = this.albumCache.get(artistId);
               if (albums == null){
                    albums = new ArrayList<Album>();
                    this.albumCache.put(artistId, albums);
               }
               albums.add(album);
          }
     }

     public void addAlbum(Album newAlbum) {
          int artistId = newAlbum.getArtistId();
          List<Album> albums = this.albumCache.get(artistId);
          if (albums == null){
               albums = new ArrayList<Album>();
               this.albumCache.put(artistId, albums);
          }
          albums.add(newAlbum);
          List<Album> all = this.getAllAlbums();
          this.dao.saveAlbums(all);
     }

     public Album[] getAlbumsForArtist(int artistId) {
          List<Album> albums = this.albumCache.get(artistId);
          if (albums == null){
               return null;
          }
          Album[] array = new Album[albums.size()];
          array = albums.toArray(array);
          return array;
     }
     
     private List<Album> getAllAlbums(){
          List<Album> allAlbums = new ArrayList<Album>();
          for (int artistId : this.albumCache.keySet()){
               List<Album> albums = this.albumCache.get(artistId);
               allAlbums.addAll(albums);
          }
          return allAlbums;
     }

}

Как и ранее, мы использовали объект доступа к данным (Data Access Object - DAO) для абстрагирования от особенностей физической организации данных, таких, как доступ к файловой системе, разбор XML и т.д. В будущем это позволит легко заменить нашу упрощенную реализацию, работающую с файлами XML, на более распространенный вариант, использующий базу данных. Теперь можно начинать вызывать новый сервис через GWT.

Вызов удаленного сервиса через GWT

Весь код, находящийся в пакете org.developerworks.rockstar.client, будет скомпилирован в JavaScript и доступен на любой странице, как показано в листинге 1. Таким образом, надо просто создать Java-класс для дальнейшего использования на странице альбомов. Исходный код класса показан в листинге 5.

Листинг 5. Класс AlbumLib

                
package org.developerworks.rockstar.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;

public class AlbumLib {
     public void loadAlbums(int artistId){
          AlbumServiceAsync albumService = this.getAlbumService();
          AsyncCallback callback = new AsyncCallback(){

               public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
               }

               public void onSuccess(Object result) {
                    Album[] albums = (Album[]) result;
                    for (int i=0;i<albums.length;i++){
                         addAlbumToModel(albums[i]);
                    }
                    refreshXformsModel();
               }
               
          };
          albumService.getAlbumsForArtist(artistId, callback);
     }
     
     private AlbumServiceAsync getAlbumService(){
          AlbumServiceAsync albumService = (AlbumServiceAsync) 
		             GWT.create(AlbumService.class);
          ServiceDefTarget endpoint = (ServiceDefTarget) albumService;
          String moduleRelativeUrl = GWT.getModuleBaseURL() + "albumService";
          endpoint.setServiceEntryPoint(moduleRelativeUrl);
          return albumService;
     }
     
     private native void addAlbumToModel(Album album)/*-{
          var model = $doc.getElementById("albums");
          var instance = model.getInstanceDocument("albumData");
          var dataElement = instance.getElementsByTagName("Data")[0];
          // create the new album node
          var newAlbumElement = instance.createElement("Album");
          var titleElement = instance.createElment("Title");
          titleElement.appendChild(instance.createTextNode(album.getTitle()));
          newAlbumElement.appendChild(titleElement);
          var yearElement = instance.createElement("Year");
          yearElement.appendChild(instance.createTextNode(album.getYear()));
          newAlbumElement.appendChild(yearElement);
          dataElement.appendChild(newAlbumElement);
     }-*/;
     
     private native void refreshXformsModel()/*-{
          var model = $doc.getElementById("albums");
          model.rebuild();
          model.recalculate();
          model.refresh();
     }-*/;
}

В этом классе много интересного. Во-первых, он предоставляет два метода для удаленного вызова ранее созданного сервиса AlbumService, аналогично тому, как в предыдущей части вызывался сервис ArtistService. Как и ранее, для обработки ответов сервиса на асинхронные запросы, используются функции обратного вызова. В данном случае, они вызывают два других метода - addAlbumToModel() и refreshXformsModel().

Последние являются собственными (native) методами JavaScript, как и те, что вы видели в примерах в первой части серии.

Метод addAlbumToModel() работает непосредственно c объектами в JavaScript, представляющими модель XForms, позволяя таким образом получить доступ к экземплярам данных в XML. В первой статье мы делали похожие вещи, но через JavaScript, используя методы вроде document.getElementById(...). Теперь же мы работаем через GWT, поэтому необходимо использовать переменную $doc для обращения к объекту документа, который неявно определен в JavaScript. Получив ссылку на этот объект, можно вызывать стандартные методы DOM для добавления элементов типа Album в XML-документ. Таким образом, метод addAlbumToModel() вызывается в цикле, по разу на каждый добавляемый альбом, полученный с сервера. После добавления всех альбомов вызывается метод refreshXformsModel(). Аналогично предыдущему, это собственный метод, имеющий доступ к модели данных XForms и использующий ее API для обновления элементов управления, привязанных к модели.

Все что осталось сделать - это убедиться, что метод loadAlbums вызывается при загрузке страницы. Для этого надо чуть изменить страницу Albums.jsp, как показано в листинге 6.

Листинг 6. Вызов GWT JavaScript из JSP

                
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:ev="http://www.w3.org/2001/xml-events" 
xmlns:xforms="http://www.w3.org/2002/xforms" 
     xmlns:xhtml="http://www.w3.org/1999/xhtml" 
	 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xhtml:head>
        <xhtml:title>Albums</xhtml:title>
        <xhtml:script language="text/javascript"
		 src="org.developerworks.rockstar.RockStarMain.nocache.js">
		 </xhtml:script>
        <xforms:model id="albums" xmlns="http://www.w3.org/1999/xhtml" 
		xmlns:xforms="http://www.w3.org/2002/xforms">
            <xforms:instance id="albumData" xmlns=""/>
        </xforms:model>
    </xhtml:head>
    <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
         <xhtml:div id="albumList">
              <xforms:repeat id="repeatItem" 
			  nodeset="instance('albumData')/Data/Album"
			  xmlns="http://www.w3.org/1999/xhtml" 
			  xmlns:xforms="http://www.w3.org/2002/xforms">
                   <xhtml:div>
                        <xforms:output ref="Title"
                         xmlns="http://ww.w3.org/1999/xhtml" 
xmlns:xforms="http://www.w3.org/2002/xforms">
                             <xforms:label 
 xmlns:xforms="http://www.w3.org/2002/
							 xforms">Title:</xforms:label>
                        </xforms:output>
                        <xforms:output ref="Year"
                         xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms">
                             <xforms:label 
xmlns:xforms="http://www.w3.org/2002/
							 xforms">Year:</xforms:label>
                        </xforms:output>
                   </xhtml:div>
              </xforms:repeat>
         </xhtml:div>
    </xhtml:body>
</xhtml:html>

Как видите, достаточно просто вызвать GWT-метод после окончания загрузки страницы. К тому же этот метод позволил нам избавиться от большей части ранее использовавшегося скриптлета, оставив только крошечный фрагмент для передачи параметра artistId. Большая часть оставшегося на странице кода служит исключительно для создания элементов интерфейса. Далее посмотрим, как и их можно создавать программно через GWT.

Создание элементов управления XForms через интерфейс JSNI в GWT

Вы уже видели, как получить доступ к модели XForms и ее данным, используя GWT и JSNI. Теперь мы сделаем следующий шаг и начнем использовать GWT и JSNI для динамического создания элементов управления XForms. Первым делом заменим элемент xforms:repeat на фрагмент кода на JavaScript, показанный в листинге 7.

Листинг 7. Динамическое создание элементов управления XForms через интерфейс JSNI в GWT

                
private native void createControls()/*-{
    var xfNs = "http://www.w3.org/2002/xforms";
     // get the container div
    var container = $doc.getElementById("albumList");
    
    var repeater = $doc.createElementNS(xfNs,"xforms:repeat");
    repeater.setAttribute("id", "repeatItem");
    repeater.setAttribute("nodeset", "instance('albumData')/Data/Album");
         
    var titleOut = $doc.createElementNS(xfNs, "xforms:output");
    titleOut.setAttribute("ref", "Title");
    var titleLabel = $doc.createElementNS(xfNs, "xforms:label");
    titleLabel.appendChild($doc.createTextNode("Title:"));
    titleOut.appendChild(titleLabel);
    repeater.appendChild(titleOut);
         
    var yearOut = $doc.createElementNS(xfNs, "xforms:output");
    yearOut.setAttribute("ref", "Year");
    var yearLabel = $doc.createElementNS(xfNs, "xforms:label");
    yearLabel.appendChild($doc.createTextNode("Year:"));
    yearOut.appendChild(yearLabel);
    repeater.appendChild(yearOut);
    
    container.appendChild(repeater);
}-*/;

Как и ранее, создание элементов управления XForms сводится к простой работе с DOM через собственные методы JavaScript. Теперь мы можем просто добавить код создания элементов UI в метод loadAlbums(), вызываемый при загрузке страницы. Таким образом, сначала будут созданы элементы интерфейса, а затем вызван метод для загрузки альбомов. После этого будут созданы экземпляры данных XForms на основе полученных альбомов, и, наконец, модель XForms будет обновлена для показа новых данных пользователю. В листинге 8 показано насколько простой стала наша JSP.

Листинг 8. Упрощенный вариант JSP (без элементов управления XForms)

                
    <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
         <xhtml:div id="albumList">
         </xhtml:div>
    </xhtml:body>
	

Теперь JSP-страница на XForms выглядит практически так же, как и страница для показа списка исполнителей, которая была написана ранее с использованием GWT. Весь пользовательский интерфейс создается программно через собственные методы JavaScript в Java-классах, а данные по-прежнему запрашиваются через Ajax.

Заключение

В третьей части мы взяли нашу JSP-страницу, использующую скриптлет для размещения данных, и упростили ее, избавившись от скриптлета и используя GWT. Сами данные асинхронно запрашиваются с сервера через Ajax. Экземпляры данных в модели XForms создаются динамически с помощью интерфейса JSNI в GWT. И, наконец, даже элементы управления XForms для показа данных об альбомах теперь генерируются динамически через JSNI. В четвертой части серии мы покажем, как использовать элементы XForms для асинхронных Ajax-запросов к GWT-сервисам по требованию пользователя.

Файлы для загрузки


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 24.08.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Quest Software. TOAD Xpert Edition
erwin Data Modeler Workgroup Edition r9.7 - Product plus 1 Year Enterprise Maintenance Commercial
Microsoft Office для дома и учебы 2019 (лицензия ESD)
IBM Domino Enterprise Server Processor Value Unit (PVU) License + SW Subscription & Support 12 Months
The BAT! Home- 1 компьютер
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
CASE-технологии
СУБД Oracle "с нуля"
Новые материалы
Программирование на Visual Basic/Visual Studio и ASP/ASP.NET
Мастерская программиста
Компьютерная библиотека: книги, статьи, полезные ссылки
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100