1

advertisement
1
Содержание:
Введение .........................................................................................................................................3
Постановка задачи .........................................................................................................................4
1. AJAX — современный подход к разработке веб-приложений .............................................5
1.1. Определение понятия «веб-приложение» ........................................................................5
1.2. Введение в AJAX ................................................................................................................7
1.3. Сравнение моделей классического DHTML веб-приложения с AJAX вебприложением ..............................................................................................................................8
2. GWT — инструмент создания AJAX веб-приложений .......................................................12
2.1. Введение в GWT ...............................................................................................................12
2.2. GWT-компилятор .............................................................................................................14
2.3. Структура GWT-приложений..........................................................................................15
2.4. Режимы запуска GWT-приложений ...............................................................................17
2.5. Асинхронные вызовы процедур для обмена данными с сервером..............................17
2.6. Графические компоненты GWT ......................................................................................18
2.7. Дополнительная библиотека виджетов GWT-Ext .........................................................20
3. Разработка графического интерфейса веб-приложения с использованием компонентов
GWT ..............................................................................................................................................21
3.1. Проектирование графического веб-интерфейса ............................................................23
3.2. Сценарии работы пользователя с веб-интерфейсом .....................................................26
3.3. Разработка графического интерфейса веб-приложения ...............................................32
3.3.1. Разбиение окна веб-приложения на области, обозначенные при проектировании
интерфейса ...........................................................................................................................35
3.3.2. Интернационализация разрабатываемого веб-интерфейса ...................................36
3.3.3. Разработка панели инструментов ............................................................................38
3.3.4. Разработка центральной панели с закладками .......................................................40
3.3.5. Разработка сервиса для работы с декларациями ....................................................42
3.3.6. Разработка панели отображения новых деклараций ..............................................45
3.3.7. Разработка окна для создания новой декларации ..................................................47
3.3.8. Описание остальных разработанных классов .........................................................49
Заключение...................................................................................................................................50
Список литературы ......................................................................................................................50
Приложения .................................................................................................................................51
Приложение 1. Список GWT компонентов ..........................................................................51
Приложение 2. Список GWT-Ext компонентов....................................................................54
Приложение 3. Исходные коды программы .........................................................................56
Приложение 4. Результат разработки веб-интерфейса ........................................................78
2
Введение
Одной из самых распространенных служб сети Интернет является World Wide Web
(WWW, Web, Всемирная паутина) — самая мощная информационная система,
связывающая между собой миллионы веб-страниц, размещенных на серверах по всему
миру. Такая популярность сети Интернет послужила сильным толчком в развитии вебтехнологий.
Веб-приложение – приложение, основанное на клиент-серверной архитектуре, в
котором в роли клиента выступает веб-браузер, а в роли сервера — веб-сервер. Одним из
достоинств такого рода приложений является мобильность клиента, что позволяет
пользователю получить работоспособное приложение независимо от установленной
операционной системы, а разработчику – возможность внесения изменений в приложение
только на сервере без установки дополнительного программного обеспечения у клиентов.
На ранних этапах развития веб-технологий одним из основных недостатков вебприложения считалось то, что на сервере были сосредоточены и бизнес-логика
приложения, и функциональность графического интерфейса. Это приводило к передаче
большого объема данных от сервера к клиенту и тому, что вся вычислительная нагрузка
приходилась на сервер, а вычислительная мощность компьютера-клиента была почти не
задействована. Устранение именно этого недостатка являлось одной из приоритетных
задач в развитии веб-технологий.
Так в 1995 году были успешно разработаны три новые веб-технологии:

специалисты компании Netscape создали механизм управления страницами
на клиентской стороне, разработав язык программирования JavaScript.

компанией Macromedia был выпущен продукт под названием Flash, с
помощью которого можно было создавать интерактивные веб-приложения.

компанией Sun Microsystems был выпущен Java Applet - прикладная
программа на языке Java в форме байт-кода, которая может выполняться
веб-браузером с использованием виртуальной Java-машины.
При
использовании
этих
веб-технологий
функциональность
графического
интерфейса приложения частично (для Flash – полностью) реализуется на стороне
компьютера-клиента, что позволяет снизить объем передаваемых данных и существенно
уменьшить нагрузку на веб-сервер. Но если веб-браузеры постепенно начали
поддерживать язык JavaScript, то для использования технологий Flash и Java Applet
пользователям необходимо устанавливать дополнительное программное обеспечение.
Ещё одним недостатком Flash и Java Applet технологий является то, что с их помощью
нельзя разработать удачное с точки зрения удобства использования веб-приложение,
3
отображающее большой объём текстовой информации; да и процесс разработки вебприложений на Flash весьма ресурсоемкий и дорогостоящий. Поэтому веб-приложения,
разработанные с помощью данных технологий, встречаются гораздо реже, чем вебприложения, разработанные с использованием языка JavaScript. JavaScript в данный
момент полностью занимает нишу веб-браузерных языков.
18 февраля 2005 Джесси Джеймс Гарретт (Jesse James Garrett) в своей статье
«Новый подход к веб-приложениям» предложил использовать новый подход к разработке
графического интерфейса веб-приложения. Данный подход позволял существенно
уменьшить объём передаваемых данных от сервера к клиенту, что сделало вебприложение более быстрым и удобным. Джесси Джеймс Гарретт назвал данный подход
AJAX (от англ. Asynchronous Javascript and XML — «асинхронный JavaScript и XML»).
В настоящее время существует несколько Java-инструментов разработки AJAX
приложений: Icefaces, RichFaces и Google Web Toolkit. Все три инструмента
предоставляют разработчику легкий путь к созданию и развертыванию современных вебприложений.
Постановка задачи
Перед автором данной работы была поставлена цель: разработать графический
интерфейс веб-приложения с использованием компонентов Google Web Toolkit. В
качестве веб-приложения было предложено использовать портал таможенного декларанта.
Для достижения этой цели перед автором были поставлены следующие задачи:
1. Провести исследование возможностей инструмента разработки AJAX вебприложений Google Web Toolkit.
2. На
основе
существующих
интерфейсом осуществить
сценариев
работы
выбор необходимых
пользователя
для
с
веб-
веб-приложения
графических компонентов.
3. Разработать графический интерфейс веб-портала таможенного декларанта.
4
1. AJAX — современный подход к разработке веб-приложений
1.1. Определение понятия «веб-приложение»
Термин «веб-приложение» неразрывно связан с таким понятием, как «клиентсерверная архитектура». Клиент-серверная архитектура — сетевая архитектура, в
которой устройства являются либо клиентами, либо серверами [6].
Клиент — это аппаратный или программный компонент вычислительной системы,
посылающий запросы серверу, используя определённый протокол. Клиент может
запрашивать с сервера какие-либо данные, манипулировать данными непосредственно на
сервере, запускать на сервере новые процессы и т. п. [1]
Различают два типа клиентов: «тонкий» и «толстый». «Тонкий» клиент переносит
все задачи по обработке информации на сервер, а «толстый», напротив, производит
обработку информации независимо от сервера, используя последний в основном лишь для
хранения данных.
Сервер (англ. server, от англ. to serve — служить) — аппаратный или программный
компонент вычислительной системы, выполняющий сервисные функции по запросу
клиента, предоставляя ему доступ к определённым ресурсам [1].
Рассмотрев
понятие
«клиент-серверная
архитектура»,
можно
перейти
к
определению понятия «веб-приложение».
Веб-приложение — приложение, основанное на клиент-серверной архитектуре, в
котором клиентом выступает браузер, а сервером — веб-сервер [2]. При этом вебприложение может выступать в качестве клиента других служб, например, базы данных
или другого веб-приложения, расположенного на другом сервере.
Веб-приложения являются основой для построения динамических веб-сайтов и вебпорталов. Веб-сайт (англ. website, от web — паутина и site — «место») — это одна или
совокупность веб-страниц, доступных в Интернет через протоколы HTTP/HTTPS [6].
Страницы сайта объединены общим корневым адресом, а также обычно темой,
логической структурой, оформлением и/или авторством. Если веб-страницами сайта
является неизменяемый набор html-файлов, то такой сайт называется статическим и, как
правило, представляет малый интерес для профессиональных разработчиков. Если вебстраницы сайта генерируются веб-приложением, то такой сайт называется динамическим.
Разновидностью динамических веб-сайтов являются веб-порталы. Веб-портал (от англ.
portal «главный вход; ворота») — веб-сайт, предоставляющий пользователю различные
интерактивные сервисы (например, почта, поиск, информация о погоде), работающие в
рамках
одного веб-сайта. Различают
горизонтальные и вертикальные порталы.
Горизонтальным называется портал, не зависящий от корпоративной информационной
5
системы предприятия. Вертикальным порталом называется веб-сайт, интегрированный в
корпоративную информационную систему (КИС) компании. Интеграция может быть
осуществлена на уровне входа на портал или на более низких уровнях, как например,
интеграция интернет-магазина с системой бухгалтерии компании [6]. Таким образом,
построение динамических веб-сайтов и веб-порталов – это, прежде всего, создание вебприложения.
Веб-сервер — программа, запускаемая на подключённом к сети компьютере и
использующая протоколы HTTP/HTTPS для передачи данных. В простейшем виде такая
программа
получает
по
сети
HTTP-запрос
на
определённый
ресурс,
находит
соответствующий файл на локальном жёстком диске и отправляет его по сети
запросившему компьютеру.
Более
сложные
веб-серверы
способны
динамически
распределять ресурсы в ответ на HTTP-запрос. HTTP (от англ. HyperText Transfer Protocol
— «протокол передачи гипертекста») — сетевой протокол прикладного уровня передачи
данных, в первую очередь, в виде текстовых сообщений. HTTPS — расширение протокола
HTTP, поддерживающее шифрование. Данные, передаваемые по протоколу HTTP,
«упаковываются»
в
криптографический
протокол
SSL
или
TLS,
тем
самым
обеспечивается защита этих данных.
Браузер (из англ. Web browser) — это программное обеспечение, позволяющее
просматривать веб-страницы, т.е. гипертекстовые ресурсы Всемирной паутины, обычно
написанные на языке HTML [6]. Браузер обычно входит в состав операционной системы.
Этот факт позволяет утверждать, что веб-приложения являются межплатформенными.
Браузер относится к категории «тонких» клиентов.
Программное обеспечение в современном мире становится все сложнее и
приобретает все больше функций, то коммерческие компании и государственные
организации стремятся автоматизировать процессы разработки и поддержки программных
приложений. При этом, однако, разработка таких приложений, их внедрение и поддержка
становятся все дороже. Тем не менее, есть фактор, который помогает значительно снизить
расходы
—
широчайшее
распространение
Интернет.
Если
разрабатываемое
клиент – серверное приложение использует для связи между клиентом и сервером базовые
протоколы Интернет (TCP/IP и HTTP) и предоставляет пользовательский интерфейс с
помощью HTML, который можно просматривать в любом браузере, то практически
каждый его потенциальный пользователь не имеет технических препятствий для
обращения к этому приложению. Также не нужно распространять специальные
клиентские компоненты, ставить клиентам специальное оборудование, не нужно тратить
много времени и средств на обучение пользователей работе со специфическим
6
интерфейсом, настройке связи с серверами и т.д. Интернет предоставляет готовую
инфраструктуру для создания крупномасштабных программных систем, в рамках которых
десятки тысяч компонентов могли бы работать совместно и миллионы пользователей
могли бы пользоваться их услугами. Поэтому вполне логично, что веб-приложения стали
одним из самых востребованных видов программного обеспечения. И этот факт не мог не
отразиться на Всемирной паутине. Если раньше веб-приложения базировались на
гипертексте и гиперссылках, то сейчас веб-приложения становятся все ближе к
настольным (от англ. desktop) приложениям. Данная тенденция с нарастающей
прогрессией охватывает Интернет и уже сегодня можно говорить о наступлении эры вебприложений нового типа, "обогащенных" интернет-приложений или RIA (Rich Internet
Application). Статические страницы веб-приложений старого типа предоставляют
информацию пользователю и имеют весьма скудные возможности, в сравнении с
настольными приложениями, для организации взаимодействия пользователя с этой
информацией.
Сегодня реализация "обогащенных" интернет-приложений возможна посредством
AJAX, Adobe Flex, Windows Presentation Foundation, Flash, Java-апплетов, Java и
некоторых декларативных языков, таких как XUL, MXML. Из всех перечисленных
инструментов широчайшую популярность приобрели лишь AJAX и Flash – в первую
очередь, благодаря их доступности. Причем, если создание приложений целиком во Flash
весьма ресурсоемкий и дорогостоящий процесс, то разработка с применением AJAX едва
ли занимает больше времени, чем разработка классических веб-приложений старого типа.
В большинстве современных проектов Flash используется лишь по мере необходимости.
1.2. Введение в AJAX
AJAX (от англ. Asynchronous Javascript and XML — «асинхронный JavaScript и
XML») — это подход к построению интерактивных пользовательских интерфейсов вебприложений, заключающийся в «фоновом» обмене данными браузера с веб-сервером [1].
В результате при обновлении данных веб-страница не перезагружается полностью, и вебприложения становятся более быстрыми и удобными.
В рамках AJAX собраны давно известные веб-технологии, и их совместное
использование позволило получить новые результаты. AJAX включает [2]:

Стандартизованное представление с использованием XHTML (Extensible
Hypertext Markup Language — расширяемый язык разметки гипертекста) и
CSS (Cascading Style Sheets — каскадные таблицы стилей); CSS
предоставляет возможность определять стили элементов Web-страницы.
7

Динамическое отображение и взаимодействие при помощи DOM (Document
Object Model — объектная модель документов). DOM представляет
структуру Web-страницы в виде набора объектов, которые можно
обрабатывать средствами JavaScript. Это дает возможность изменять
внешний вид графического интерфейса веб-приложения в процессе работы.

Управление и обмен данными между браузером и веб-сервером через XML
(eXtensible Markup Language — расширяемый язык разметки). XML —
текстовый формат, предназначенный для хранения структурированных
данных
(взамен
существующих
файлов
баз
данных),
для
обмена
информацией между программами.

Асинхронное получение данных от веб-сервера с использованием объекта
класса XMLHttpRequest. Объект XMLHttpRequest позволяет программисту
получать данные с Web-сервера в фоновом режиме.

Язык JavaScript, с помощью которого реализуются вышеперечисленные
пункты.
1.3. Сравнение моделей классического DHTML веб-приложения с AJAX
веб-приложением
Сравним модели классического DHTML веб-приложения и AJAX веб-приложения.
Dynamic HTML или DHTML — это способ создания интерактивного вебприложения, используя сочетание статичного языка разметки HTML, встраиваемого (и
выполняемого на стороне клиента) скриптового языка JavaScript, CSS (каскадных таблиц
стилей) и DOM (объектной модели документа) [6]. Можно заметить, что все
вышеперечисленные веб-технологии используются также и в AJAX. DHTML позволяет
создавать на базе веб-страниц интерфейсы с достаточно большими интерактивными
возможностями, но любые изменения внешнего вида страницы реализуются лишь путем
повторной загрузки всего документа.
Модель классического DHTML веб-приложения действует следующим образом:
большинство действий пользователя отправляют обратно на веб-сервер HTTP-запрос.
Веб-сервер производит необходимую обработку - получает данные, обрабатывает числа,
взаимодействует с различными унаследованными системами и затем выдаёт HTMLстраницу клиенту (рис. 1). Эта модель заимствована из первоначального применения веб
как гипертекстовой среды. У данной модели есть два весомых недостатка:
8

Не достигается хорошего взаимодействия с пользователем. В то время
пока сервер обрабатывает результаты, пользователю приходится ждать
(рис. 2).

Избыточность загружаемых данных. Веб-сервер выдаёт результат в виде
готовой HTML-страницы. Если требуется обновить лишь небольшую часть
веб-страницы, то нет необходимости повторно загружать HTML-данные,
которые не подверглись изменению.
Рис.1 Модель классического DHTML веб-приложения
Рис. 2 Взаимодействие пользователя с классическим DHTML веб-приложением
(синхронное)
9
Рассмотрим теперь модель AJAX веб-приложения (рис. 3). Приложение AJAX
исключает взаимодействие, при котором пользователю необходимо ждать пока сервер
обработает данные и выдаст результат. Это достигается путём введения механизма AJAX
как промежуточного слоя между пользователем и сервером. Вместо того, чтобы загружать
страницу в начале пользовательской сессии, браузер загружает механизм AJAX,
написанный на JavaScript и обычно спрятанный в скрытый фрейм. Этот механизм
отвечает за формирование пользовательского интерфейса и взаимодействие с сервером.
Механизм AJAX позволяет производить взаимодействие с пользователем асинхронно, то
есть независимо от взаимодействия с сервером. Таким образом, пользователю больше не
нужно наблюдать пустое окно браузера и курсор в виде песочных часов в ожидании
действий сервера (рис. 4).
Каждое действие пользователя, которое производит HTTP-запрос, теперь вместо
этого принимает форму вызова одной из JavaScript-функции механизма AJAX. Каждый
ответ на действие пользователя, не требующее обращения к серверу, например, простая
проверка данных, редактирование данных в памяти, и даже некоторая навигация,
выполняется механизмом самостоятельно. Если же для ответа требуется информация с
сервера, например, загрузка дополнительного интерфейсного кода, передача данных для
обработки или получение новых данных, то механизм AJAX производит необходимые
запросы асинхронно, обычно при помощи XML, не прерывая взаимодействия
пользователя с приложением.
Рис.3 Модель AJAX веб-приложения
10
Рис. 4 Взаимодействие пользователя с AJAX веб-приложением (асинхронное)
Основные достоинства AJAX:
 Экономия трафика. Использование AJAX позволяет значительно сократить
трафик при работе с веб-приложением благодаря тому, что часто вместо загрузки
всей страницы достаточно загрузить только небольшую изменившуюся часть.

Уменьшение нагрузки на сервер. AJAX позволяет несколько снизить нагрузку на
сервер благодаря тому, что сервер теперь не генерирует HTML-страницы «на
лету», вместо сервера это делает клиентский JavaScript код.

Ускорение реакции графического интерфейса. Поскольку нужно загрузить
только изменившуюся часть, то пользователь видит результат своих действий
быстрее.

Асинхронное взаимодействие с сервером. Взаимодействие с пользователем не
прерывается при обращении браузера к веб-серверу.
Основные недостатки AJAX:

Интеграция
со
стандартными
инструментами
браузера.
Динамически
создаваемые страницы не регистрируются браузером в истории посещения
страниц, поэтому не работает кнопка «Назад» предоставляющая пользователям
возможность вернуться к просмотренным ранее страницам. Также невозможно
сохранить закладку на желаемый материал.

Динамически загружаемое содержание недоступно поисковым системам.
Поисковые машины не могут выполнять JavaScript код, поэтому не могут
регистрировать веб-контент сайта.
11

Старые методы учета статистики сайтов становятся неактуальными. Многие
сервисы статистики ведут учёт просмотров новых страниц веб-приложения. Для
веб-приложений, страницы которых широко используют AJAX, такая статистика
теряет актуальность.
Таким образом, AJAX приложение отличается от аналогичного DHTML приложения
экономичностью с точки зрения трафика; дружественным, эргономичным и удобным
интерфейсом; скоростью реакции интерфейса и уменьшенной нагрузкой на сервер.
2. GWT — инструмент создания AJAX веб-приложений
2.1. Введение в GWT
Google Web Toolkit (GWT) — свободный Java фреймворк, который позволяет вебразработчикам создавать AJAX-приложения на основе Java. Фреймворк — каркас
программной системы (или подсистемы), включающий вспомогательные программы,
библиотеки кода, язык сценариев и другое ПО, облегчающее разработку и объединение
разных компонентов большого программного проекта за счёт использования единого API
(Application Programming Interface) [6].
Первая версия GWT была выпущена компанией Google в мае 2006 года. Именно
эта компания сделала AJAX популярным после использования его в сервисах Gmail,
Google Maps и Google Suggest.
GWT позволяет писать AJAX веб-приложения на языке программирования Java,
используя при этом все его объектно-ориентированные возможности. Это, несомненно,
является огромным плюсом, так как JavaScript, в отличие от Java, не полностью
соответствует концепциям объектно-ориентированного программирования [5]. Да и
людей, пишущих на Java, гораздо больше, чем тех, кто пишет программы на JavaScript.
Основные недостатки JavaScript:
1)
Неполное
соответствие
концепциям
объектно-ориентированного
программирования. В частности, отсутствие механизма наследования и инкапсуляции.
2)
Невозможность
создания
сложных
GUI
компонентов,
т.е.
отсутствие
масштабирования. Нельзя создать новый GUI компонент, используя старый, просто
переопределив некоторую функциональность старого компонента. Таким образом, для
реализации нового компонента приходится дублировать код старого.
3) Требуется большое количество времени на отладку приложения для корректной
работы в разных браузерах.
12
Использование GWT-фреймворка устраняет эти недостатки. Создание вебприложения с помощью GWT очень похоже на создание обычного Java Swingприложения. В GWT используются такие же, как и в Swing компоненты (в GWT
компоненты называются виджетами): Panel – аналог JPanel в Swing, Button – аналог
JButton в Swing, TextField – аналог JTextField в Swing и т.д [4].
Любое AJAX приложение базируется на языке JavaScript, а не Java. Поэтому, в
GWT предусмотрен специальный компилятор, транслирующий Java-код в эквивалентный
JavaScript-код. Таким образом, программист может написать полностью функциональное
AJAX веб-приложение, даже не зная языков HTML и JavaScript.
На сегодняшний день не существует аналогов GWT-фреймворка, обладающих
такой же функциональностью.
Основные особенности Google Web Toolkit [7]:

Динамические графические компоненты (виджеты) с возможностью
повторного использования. Возможность создавать новые виджеты,
переопределяя и дополняя функциональность старых.

Простой механизм связи с сервером. Обмен данными с сервером
происходит посредством вызова асинхронного метода. Подробнее о
механизме связи с сервером будет рассказано ниже.

Возможность регистрации браузером истории посещения вебприложения. GWT даёт возможность сделать веб-приложение более
удобным, добавляя состояния открытых окон и панелей в историю
посещения, при этом, нажимая в браузере на кнопку «Назад», можно
вернутся к предыдущему состоянию.

Отладка веб-приложения ничем не отличается от отладки обычного
Java-приложения.
Хотя
GWT-приложение
и
компилируется
в
JavaScript, существует возможность его отладки, используя все
современные возможности Java-отладчика.

Кроссбраузерность. GWT-приложения одинаково отображаются и
выполняются во всех распространенных браузерах - Internet Explorer,
Firefox, Safari и Opera.

Поддержка JUnit. JUnit – фреймворк для тестирования Java модулей.
Поддержка тестирования отдельных модулей и асинхронных вызовов
процедур.

Интернационализация. Лёгкость создания
и адаптации GWT-
приложений к языковым и культурным особенностям других стран.
13

Использование JavaScript. Возможность вставки JavaScript прямо в
Java-код, используя JavaScript Native Interface (JSNI).

Весь код кроме GWT-компилятора и GWT-шелла (о GWT-шелле
будет сказано ниже) является открытым и распространяется под
лицензией Apache 2.0.
GWT-фреймворк используется только для построения GUI веб-приложения, а вся
бизнес-логика (т.е. совокупность правил, принципов, зависимостей, поведения объектов
предметной области системы) разрабатывается при помощи других Java EE 5 (Java
Platform, Enterprise Edition — набор спецификаций и соответствующей документации для
языка Java, описывающей архитектуру серверной платформы для задач средних и
крупных предприятий) технологий.
2.2. GWT-компилятор
«Сердцем» GWT, конечно же, является компилятор, который переводит
разработанное Java-приложение в эквивалентное приложение на JavaScript. При этом
компилятор осуществляет оптимизацию JavaScript-кода. Получившийся JavaScript-код
имеет меньший размер, чем аналогичный код, написанный программистом на JavaScript
вручную, поэтому требуется меньше времени для его загрузки на клиент. Также,
получившийся код можно считать «чёрным ящиком», т.к. его практически невозможно
понять. Существуют некоторые ограничения на исходный клиентский Java-код
программы, связанные с тем, что язык JavaScript является менее функциональным, чем
Java, и не все возможности языка Java можно «перевести» в JavaScript. Ниже приведён
список данных ограничений:

GWT-компилятор может компилировать исходный код, написанный на
языке Java версии не выше 1.4. Фактически, это означает отсутствие
шаблонов и некоторых конструкций языка, например цикла for each.
Разработчики GWT работают над этой проблемой, и в следующей версии
фреймворка будет поддержка Java версии 1.5

Отсутствие поддержки многопоточности. Так как язык JavaScript не
поддерживает многопоточность, то нельзя использовать такие методы, как
Object.wait(), Object.notify() и Object.notifyAll().

Стандартные
очень
java-пакеты
громоздкие
и
используют
функциональность, недопустимую в веб-браузерах (например, доступ к
файловой системе пользователя). Поэтому GWT-компилятор поддерживает
лишь два стандартных пакета: java.lang (оболочки простых типов,
14
математические функции, исключительные ситуации) и java.util (работа с
коллекциями, датами, календарями, случайными числами).

Отсутствие
поддержки
утверждений
(assertions).
GWT-компилятор
понимает Java-код, который использует конструкцию assert <expression>, но
не учитывает её.
2.3. Структура GWT-приложений
GWT-приложения оформлены в виде модулей (module). Каждый модуль – это
функционально законченное GWT-приложение, обладающее собственным файлом
конфигурации [7].
Расположение Java-классов в каждом модуле должно подчиняться определённой
структуре. В GWT-модуле, как минимум, должно быть три пакета:

Пакет, в котором находится исходный клиентский Java-код. Этот код после
компиляции его в JavaScript будет выполняться браузером. Важно заметить,
что данный код не должен выходить за рамки перечисленных выше
ограничений, предъявляемых к исходному коду для GWT-компилятора.
Обычно данный пакет называется client.

Пакет, в котором находится исходный серверный Java-код. Этот код
обрабатывает асинхронные HTTP-запросы, поступающие от клиента. На
исходный код этого пакета не накладывается никаких ограничений. Обычно
данный пакет называется server.

Пакет, в котором находятся ресурсы, используемые разрабатываемым вебприложением (картинки, CSS-стили и т.д.). Содержимое этого пакета
копируется без каких-либо изменений на веб-сервер. Обычно данный пакет
называется public.
Все вышеперечисленные пакеты могут включать в себя любое количество
подпакетов. Сам GWT-модуль может быть расположен в любом месте проекта, что
позволяет легко совмещать GWT-модули с другими Java EE 5 модулями.
Файл конфигурации GWT-модуля – это XML файл, имеющий название вида
ModuleName.gwt.xml, где ModuleName – название GWT-модуля. Этот файл располагается
в том же пакете, что и пакеты client, server и public. Конфигурационный файл содержит
следующие настраиваемые параметры [7]:

<entry-point class="classname"/>. Указывается квалифицированное имя
класса, реализующего интерфейс com.google.gwt.core.client.EntryPoint, в
котором переопределяется единственный метод onModuleLoad(). Данный
15
метод вызывается автоматически при загрузке модуля. Ещё одним условием
для такого класса является наличие конструктора, вызываемого без
параметров. Можно указать несколько классов или не указывать ни одного.
При указании нескольких классов метод onModuleLoad() вызывается для
всех созданных экземпляров этих классов.

<source path="path"/>. Указываются пакеты, в которых находится
клиентский Java-код. При отсутствии данного параметра, по умолчанию,
считается, что используется один пакет с названием client.

<public path="path"/>. Указываются пакеты, в которых находятся ресурсы,
используемые разрабатываемым веб-приложением. При отсутствии данного
параметра, по умолчанию, считается, что используется один пакет с
названием public.

<inherits name="logical-module-name"/>. Указывается название GWTмодуля,
от
которого
будет
унаследован
разрабатываемый
модуль.
Наследование в данном случае означает копирование всех настроек
конфигурационного файла модуля-родителя в разрабатываемый модуль.
Количество унаследованных модулей неограниченно.

<servlet
path="url-path"
class="classname"/>.
Указывается
квалифицированное имя класса-сервлета, обрабатывающего асинхронные
HTTP-запросы клиента по заданному URL. Количество используемых
сервлетов неограниченно.

<script src="js-url"/>. Данный параметр автоматически подключает в
HTML-страницу модуля дополнительный JavaScript-файл, расположение
которого задаётся параметром js-url. Подключение происходит до вызова
метода onModuleLoad() аналогично простой вставке в HTML-код тега
<script
type="text/javascript"
src=”js-url”/>.
Количество
подключаемых
файлов неограниченно и происходит в том порядке, который был указан в
конфигурационном файле.

<stylesheet src="css-url"/>. Данный параметр автоматически подключает в
HTML-страницу модуля каскадную таблицу стилей, расположение которой
задаётся параметром css-url. Подключение происходит аналогично простой
вставке в HTML-код тега <link rel="stylesheet" href="css-url">. Количество
подключаемых файлов неограниченно и происходит в том порядке, который
был указан в конфигурационном файле.
16
Загрузка модуля может происходить либо при обращении к HTML-странице
модуля, либо при наследовании его другими GWT-модулями. На HTML-странице модуля
происходит построение GUI веб-приложения с использованием AJAX. GWT-модуль не
может иметь более одной такой веб-страницы, имя которой должно совпадать с названием
GWT-модуля.
2.4. Режимы запуска GWT-приложений
Существуют 2 режима запуска GWT-приложения [7]:

Режим отладки. В режиме отладки приложение запускается как Java байткод на виртуальной Java-машине в специальном окне, называемым
GWT-шеллом (от англ. shell – оболочка). GWT-шелл представляет собой
специально разработанный браузер, который отображает веб-страницу не на
основе HTML-разметки, а на основе Java-кода.
Именно поэтому и
существует возможность полноценной отладки приложения как обычного
Java-приложения. При запуске GWT-приложения в данном режиме
компиляции в JavaScript-код не происходит.

Режим запуска приложения на веб-сервере. В этом режиме приложение
при помощи GWT-компилятора переводится в JavaScript и загружается на
веб-сервер. В этом режиме отладка недоступна.
2.5. Асинхронные вызовы процедур для обмена данными с сервером
GWT-приложения могут обращаться к серверу при помощи вызова асинхронных
методов. Такие методы не прерывают дальнейшее выполнение программы, выполняются
на сервере, а после своего завершения вызывают на клиенте специальную процедуру,
называемую callback. Такой механизм вызова процедур называется удалённым вызовом
процедур (от англ. Remote Procedure Call, RPC) [6].
Т.к. вызывающая и вызываемая
процедуры выполняются на разных машинах, то они имеют разные адресные
пространства, и это создает проблемы при передаче параметров и результатов, особенно
если машины не идентичны. Так как RPC не может рассчитывать на разделяемую память,
то это означает, что параметры RPC не должны содержать указателей на ячейки
нестековой памяти и что значения параметров должны копироваться с одного компьютера
на другой. Для копирования параметров процедуры и результата выполнения через сеть
выполняется их сериализация. Сериализация — процесс перевода какой-либо структуры
данных в последовательность битов. Обратной к операции сериализации является
17
операция десериализации — восстановление начального состояния структуры данных из
битовой последовательности.
RPC реализован в Google Web Toolkit таким образом, что разработчику не нужно
вручную заниматься сериализацией и десериализацией объектов. Эту функцию
выполняют специальные прокси-объекты, которые создаются клиентским JavaScriptкодом автоматически при вызове асинхронного метода. Для того, чтобы передать объект
по протоколу HTTP, класс объекта должен быть сериализуемым (т.е. реализовывать
интерфейс java.io.Serializable или
com.google.gwt.user.client.rpc.IsSerializable). Список
типов данных, которые могут быть использованы для обмена данными между клиентом и
сервером в GWT-приложении:

Примитивные типы: char, byte, short, int, long, boolean, float или double.

String, Date, классы-обёртки примитивных типов (Character, Byte, Short,
Integer,
Long, Boolean, Float или Double).

Массивы сериализуемых типов любой сложности.

Пользовательские классы. Пользовательский класс является сериализуемым, если:

реализует интерфейс java.io.Serializable или com.google.gwt.user.client.rpc.
IsSerializable


все члены-данные класса являются сериализуемыми

имеется конструктор класса, вызываемый без параметров
Классы, имеющие хотя бы один сериализуемый супер-класс.
Важно отметить, что RPC-механизм, реализованный в GWT, поддерживает
полиморфизм.
Серверный код, выполняющийся по запросу клиента, в терминологии RPC
называется сервисом, поэтому вызов удалённой процедуры иногда называют вызовом
соответствующего сервиса.
2.6. Графические компоненты GWT
Основной упор разработчиков GWT направлен на лёгкость освоения фреймворка.
Графические компоненты, используемые в GWT, являются тому подтверждением.
Построение графического интерфейса с использованием GWT очень похоже на создание
графического интерфейса с применением широкоизвестной Java-технологии Swing,
поэтому фреймворк делает создание функционально богатого AJAX-интерфейса едва ли
не более легким, чем построение традиционного графического Java-интерфейса.
Графические компоненты, используемые в GWT, называются виджетами. GWT
предоставляет разработчику обширный набор виджетов: кнопки, списки, текстовые поля,
18
деревья, таблицы, панели, всплывающие окна – всё то, что есть у обычных настольных
приложений. Полный список виджетов GWT приведён в приложении 1. При этом хочется
отметить наличие таких интересных виджетов, как панель с закладками (TabPanel) и
текстовое
поле
с
автоподстановкой
значений
по
первым
введённым
буквам
(SuggestBox).
Все
виджеты,
как
и
в
технологии
Swing,
поддерживают
добавление
прослушивателей событий:
Button b = new Button("Click Me");
b.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
//выполнить какое-либо действие по нажатию кнопки
}
});
К каждому виджету при помощи метода setStyleName() может быть применён
собственный CSS-стиль, что придаст создаваемому веб-приложению индивидуальность.
При отсутствии нужного виджета разработчик может создать свой на основе
имеющихся виджетов.
Подробнее о методах использования конкретных виджетов будет рассказано в
пятой главе данной работы.
Как и в Swing,
в GWT существуют контейнеры, в которые можно добавлять
виджеты. Такие контейнеры называются панелями. В панели можно добавлять виджеты, а
также другие панели. При добавлении виджетов на панель их можно располагать
различным образом, например, по горизонтали или по вертикали. Способ расположения
виджетов в панели называется компоновкой (от англ. layout). В GWT существуют
следующие виды компоновок виджетов [7]:

Горизонтальная - HorizontalLayout. Все виджеты растягиваются по высоте
панели и располагаются друг за другом по горизонтали.

Вертикальная - VerticalLayout. Все виджеты растягиваются по ширине
панели и располагаются друг за другом по вертикали.

Плавающая - FlowLayout. Все виджеты располагаются друг за другом по
горизонтали, при этом виджеты не растягиваются. Если виджеты не
вмещаются в ширину панели, то они переносятся на следующую строку.

Граничная – BorderLayout. В этом случае виджеты располагаются
относительно центра панели: выше центра, ниже центра, левее центра,
19
правее центра, в центре. Все виджеты в данном случае растягиваются до
заполнения всей площади панели.

Заполняющая – FitLayout. В панель с такой компоновкой виджетов можно
добавить лишь один виджет, который будет растянут по всей площади
панели.
Таким образом, создание веб-интерфейса на GWT намного быстрее и комфортнее,
чем при использовании других Java EE 5 веб-технологий, в которых разработчику нужно
работать с HTML-кодом. GWT-виджеты одинаково функционируют и отображаются во
всех популярных веб-браузерах: Internet Explorer, Firefox, Safari и Opera. При
использовании других Java EE 5 веб-технологий много времени уходит именно на
поддержку кроссбраузерности.
2.7. Дополнительная библиотека виджетов GWT-Ext
Хотя GWT и содержит достаточно большой набор виджетов, зачастую разработчики
не ограничиваются только ими. Так, после выхода GWT группа разработчиков создала на
основе GWT и ExtJS (ExtJS – JavaScript-библиотека для построения «обогащённых»
интернет приложений) свою бесплатную библиотеку виджетов. В неё были добавлены
новые виджеты, а также расширена функциональность старых. Эта библиотека называется
GWT-Ext. В неё вошли такие виджеты как [8]:

GridPanel - таблица с возможностью сортировки и фильтрования записей.

TreePanel - дерево с поддержкой технологии drag'n'drop

Menu - меню с поддержкой пиктограмм

Toolbar - панель инструментов

Различные диаграммы - BarChart, ColumnChart, LineChart, PieChart

Географические карты - GoogleMap, YahooMap, MicrosoftMap, OpenStreetMap

ColorPalette - виджет, позволяющий выбирать цвет

DatePicker - виджет, позволяющий выбирать дату

Tooltip - всплывающая подсказка
Полный набор виджетов GWT-Ext приведён в приложении 2.
GWT-Ext также позволяет реализовывать различные визуальные эффекты:
затемнение, сворачивание/разворачивание, передвижение.
Таким образом, используя GWT и GWT-Ext виджеты, можно построить такой
пользовательский интерфейс, который не будет отличаться от интерфейса обычного
настольного приложения.
20
3. Разработка графического интерфейса веб-приложения с
использованием компонентов GWT
В настоящее время проводится кардинальная модернизация таможенной службы
Российской Федерации, осуществляются меры по приведению её в соответствие
растущему объему и многообразию внешнеэкономической деятельности, адаптации к
нормам, принятым в международной практике таможенного дела.
Одним из рациональных, экономически целесообразных путей решения этой
задачи
является
проведение
комплекса
мероприятий,
направленных
на
совершенствование процедур таможенного оформления, повышение эффективности
таможенного контроля и оперативного управления деятельностью таможенных органов за
счет применения новых информационных технологий, создания перспективных и
развития существующих технических средств и программного обеспечения.
В ОАО “Научно-инженерный центр Санкт-Петербургского электротехнического
университета”, где работает автор данной работы, в своё время был разработан
программный продукт, который позволил перейти от бумажной технологии таможенного
оформления
к
электронной.
Система
электронного
декларирования
позволила
существенно повысить скорость оформления и передачи на таможенный пост
электронных таможенных документов.
Важную роль в ускорении
внедрения электронного оформления таможенных
документов сыграл тот факт, что пользовательский интерфейс был оформлен в виде вебпортала, построенного на основе DHTML веб-приложения, т.е. пользователям не нужно
было устанавливать дополнительное клиентское ПО, а разработчики могли очень быстро
вносить изменения в систему.
Подача таможенных деклараций, автоматически
заполняемых на основе сопроводительных документов, производилась на веб-странице.
Но этот программный продукт
устарел, стал неконкурентоспособным, у
пользователей возникали неудобства в его использовании вследствие частого обновления
веб-страниц, а также открытия нескольких окон браузера, и поэтому было решено
разработать новый программный продукт, отличающийся от старого экономичностью с
точки зрения трафика, дружественным пользовательским интерфейсом и более высокой
скоростью реакции интерфейса.
Перед автором данной работы была поставлена задача разработать новый
конкурентоспособный графический веб-интерфейс с использованием компонентов Google
Web Toolkit.
21
Разрабатываемый продукт предназначен для:
1) автоматизации процесса подготовки документов для подачи их в
таможенные органы;
2) предоставления пользователю удобных средств по созданию и контролю
документов;
3) предоставления пользователю возможности диалога с таможенными
органами;
4) автоматизации учета информации о прохождении документа в таможенных
органах;
5) хранения и быстрого поиска документов.
Бизнес-требования:

Соответствие стандартам таможенного законодательства

Подача декларации в таможенный орган
Функциональные требования:

Возможность
формирования,
редактирования,
удаления
и
отправки
декларации в таможенный орган

Возможность создания, редактирования, загрузки с локального диска на
сервер, выгрузки с сервера на локальный диск, удаления, добавления к
декларации электронных документов

Оповещение декларанта при наступлении событий, которые требуют какихлибо
действий
от
декларанта
или
о
которых
он
должен
быть
проинформирован

Возможность поиска нужного документа и декларации
Нефункциональные требования:

Минимизация скорости реакции интерфейса

Возможность быстрого освоения интерфейса

Наличие дружественного интерфейса

Возможность использования приложения во всех наиболее популярных
браузерах: Internet Explorer, Firefox, Safari и Opera
22
3.1. Проектирование графического веб-интерфейса
При проектировании веб-интерфейса должны быть учтены все предъявляемые к
нему требования [3].
Основные проектные решения:
С учётом того, что должна быть достигнута высокая скорость реакции интерфейса
и разрабатываемый портал ориентирован на заполнение различных форм, было принято
решение использовать веб-технологии и фреймворки, поддерживающие AJAX, а не Flash.
Исходя из того, что компания уже имеет большой опыт разработки веб-приложений на
языке Java, было принято решение использовать именно этот язык для разработки.
Существует несколько
Java веб-технологий, поддерживающих AJAX: Icefaces,
RichFaces и GWT. Все три фреймворка предоставляют разработчику легкий путь к
созданию и развертыванию «обогащенных» Интернет приложений. Выбор был сделан в
пользу GWT по ряду причин:

И в IceFaces и в RichFaces события обрабатываются (например, нажатие на
клавишу) на сервере, что приводит к увеличению нагрузки на сервер и сеть. В
GWT события обрабатываются на клиенте, поэтому уменьшается трафик и
равномерно распределяется нагрузка между сервером и клиентом.

И в IceFaces и в RichFaces графический интерфейс строится с помощью HTML, а не
Java. Это приводит к дополнительным потерям времени на обеспечение
совместимости с различными браузерами, что является одним из бизнестребований к веб-интерфейсу.

Возможность
создания
собственных
повторно
используемых
графических
компонентов.
Для выполнения нефункционального требования «Дружественный интерфейс
пользователя» было решено построить интерфейс по своему стилю напоминающий
обычное офисное приложение, которые используются повседневно. Для построения
такого интерфейса было принято решение использовать дополнительную библиотеку
виджетов GWT-Ext, содержащую меню, панели инструментов, таблицы и множество
других «офисных» компонентов. Для того, чтобы пользователь мог быстро переключаться
между различными открытыми документами и декларациями, было решено использовать
такой элемент, как панель с закладками. Каждый новый документ или декларация
будут открываться не в новом окне браузера, как это было раньше, а на новой вкладке
панели.
23
Так как GWT-фреймворк содержит виджеты, которые одинаково функционируют и
отображаются во всех популярных браузерах, то требование кроссбраузерности
выполняется автоматически.
Таким образом, используя GWT, можно с минимальными затратами разработать
полностью соответствующее всем требованиям приложение.
Проектируемый веб-интерфейс было решено разбить на области, отвечающие за
логическую структуру отображения информации. Получившийся результат представлен
ниже на рис.5
Рис. 5. Разбиение пользовательского веб-интерфейса на логические области
В области 0 было решено расположить панель инструментов. На этой панели
инструментов должны располагаться кнопки вызова наиболее используемых операций и
функций, текстовое поле для быстрого поиска нужного документа или декларации, а
также значок статуса соединения с сервером. Все значки должны быть оснащены
подписями
к
ним,
а
также
всплывающими
подсказками,
объясняющими
их
функциональность. Примерный вид данной области показан на рис. 6.
Рис.6. Панель инструментов разрабатываемого портала
Область 1 – информационная. В этой области должна отображаться информация о
новых декларациях (область 1a) и событиях (область 1b), которые требуют каких-либо
действий от декларанта или о которых он должен быть проинформирован. Примерный
24
вид данной области в уменьшенном масштабе показан на рис. 7.
Рис.7. Информационная область разрабатываемого портала
Область 2 – основная. В этой области декларант проводит больше всего времени.
Здесь формируются, редактируются и отправляются декларации в таможенный орган,
производится работа с документами - создание, редактирование, копирование и удаление
документов. Так как декларант обычно работает сразу с несколькими открытыми
документами и декларациями, то было принято решение оформить данную область в виде
панели с закладками, что исключит открытия одновременно нескольких окон браузера.
Примерный вид данной области в уменьшенном масштабе показан на рис. 8.
Рис.8. Основная область разрабатываемого портала
Размер областей 1 и 2 нефиксированный. Декларант при необходимости может
изменить соотношение пропорций. По умолчанию, размер области 1 достаточен для того,
чтобы прочитать информацию. Таким образом, мы достигаем максимальную загрузку
информационной области.
Цветовое решение веб-интерфейса не насыщено яркими цветами, а выполнено в
оттенках серого цвета. Серый цвет не отвлекает во время работы, поэтому декларанту
будет намного приятнее работать в портале с таким цветовым оформлением.
Теперь, когда создан прототип графического интерфейса, можно переходить к его
разработке, но для этого нужно определить сценарии использования данного интерфейса.
25
3.2. Сценарии работы пользователя с веб-интерфейсом
В процессе разработки веб-интерфейса необходимо использовать сценарий работы
пользователя в портале декларанта. Сценарий позволяет отследить, какие действия
доступны пользователю на каждом шаге при выполнении различных функций.
Рассмотрим несколько основных сценариев (табл. 1).
Формирование декларации (рис. 9):
Рис. 9 Диаграмма деятельности (activity diagram) – «Формирование декларации»
Процесс формирования декларации состоит из следующих этапов:
- создание набора базовых документов (ГТД, ДТС, КТС, опись, карточка
транспортного средства);
- заполнение сформированных документов;
- формирование набора дополнительных документов (регистрационных,
коммерческих, транспортных, сертификатов, таможенных, других документов);
- заполнение документов.
На данном этапе пользователю должна быть доступна следующая информация:
- список всех деклараций;
- папки для хранения документов;
- список открытых деклараций;
- результаты поиска;
26
- информация о выбранной декларации (номер, название, статус, комментарий,
список документов);
- поиск документов.
Операции, разрешенные на данном этапе для декларации:
- добавить документ;
- загрузить комплект;
- выгрузить документы;
- удалить документы;
- отправить декларацию.
Табл. 1.1. Сценарий пользователя
действия пользователя
1.
реакция веб-интерфейса
нажатие на кнопку «Создать
открытие в области 2 окна для
декларацию» в области 0
формирования набора документов с
приглашением для ввода названия
декларации, комментария к декларации и
выбором документов для добавления в
декларацию (необходимость добавления
ДТС, КТС, карточки транспортного
средства)
2.
ввод имени декларации
3.
ввод комментария
4.
выбор необходимых документов для
выделение выбранных документов
декларации
5.
нажатие на кнопку «Создать»
в области 1 появляется запись для данной
декларации в разделе «Новые», в области 2
открывается окно: в заголовке - декларация
№ <номер> (<имя>), со списком основных
операций, доступных на данном шаге,
описанием введенного ранее комментария и
списком сформированных на первом шаге
документов
Добавить документы:
На данном этапе пользователю должна быть доступна следующая информация:
- выбор вариантов добавления документа (операции для выполнения);
27
- тип документа;
- имя документа;
- строка описи.
Операции, разрешенные на данном этапе:
- создать;
- загрузить;
- создать по шаблону;
- поиск;
- ввод имени документа;
- выбор / заполнение строки описи (появляется опционально, по умолчанию
открыта на просмотр);
- редактирование документа (появляется опционально);
- просмотр документа (появляется опционально);
- сохранение документа как шаблона.
Табл. 1.2.Сценарий пользователя
действия пользователя
1.
2.
реакция веб-интерфейса
нажатие на кнопку «Добавить
открытие окна со списком доступных
документы» в списке доступных
действий на данном этапе + предложением
операций декларации
заполнить имя создаваемого документа
выбор необходимого действия (Создать,
выполнение данного действия,
Загрузить, Найти, Создать по шаблону),
отображение типа документа, отображение
нажатием на соответствующую кнопку:
имени документа с возможностью его
«Новый», «Загрузить», «Создать по
изменения, открытие возможности
шаблону», «Найти»
редактирования и просмотра документа,
открытие возможности редактирования
строки описи или выбора уже
существующей строки
3.
ввод / корректировка имени документа
4.
нажатие кнопки «Редактировать»
открывается редактор документа
5.
Внесение необходимых данных
заполнение соответствующих полей
6.
нажать кнопку «Сохранить»
сохранение информации
7.
Закрытие редактора
закрывается окно редактора, происходит
автоматический перенос сведений из
28
действия пользователя
реакция веб-интерфейса
соответствующих полей документа в
строку описи
8.
редактирование строки описи
9.
нажатие «Завершить»
закрытие окна создания, переход к списку
документов декларации, Сохранение
сведений из строки Описи, заполненных
пользователем, в xml документе,
добавление документа в список документов
декларации.
Альтернативные сценарии:
Табл. 1.3.Отсутствие необходимости редактирования документа
действия пользователя
реакция веб-интерфейса
4. Нажатие на кнопку «Просмотр»
открытие окна просмотра документов
5. закрытие окна просмотра
закрывается окно просмотра документа
6. внесение данных в строку описи
7. Нажатие «Завершить»
закрытие окна создания, переход к списку
документов декларации, сохранение
сведений из строки описи, заполненных
пользователем, в xml документе.
Табл. 1.4. Выбор необходимой строки описи
действия пользователя
реакция веб-интерфейса
8. нажатие на кнопку «Выбор строки
в области 2 открывается окно со списком
описи»
уже существующих строк в описи и
отображаются данные, содержащиеся в
этой строке.
9. выбор соответствующей строки описи
подсветка выбранной строки описи
10. Нажатие кнопки «Выбрать»
закрытие окна выбора строк, переход к
окну информации о создаваемом
документе, перенос сведений
содержащихся в выбранной строке описи в
строку для этого документа
29
действия пользователя
реакция веб-интерфейса
11. редактирование выбранной строки
12. Нажатие «Завершить»
закрытие окна создания, переход к списку
документов декларации, Сохранение
сведений из строки описи, заполненных
пользователем, в xml документе.
Табл. 1.5. Сохранение документа как шаблона
действия пользователя
8. Нажатие на кнопку «Сохранить как
шаблон»
реакция веб-интерфейса
открытие окна с приглашением к вводу
имени сохраняемого шаблона и пути для
сохранения с корнем в папке шаблоны (с
учетом, что в папке шаблоны у
пользователя может быть своя иерархия)
9. ввод имени сохраняемого шаблона
10. выбор директории для сохранения
шаблона
11. нажатие кнопки «Выполнить»
закрывается окно для задания имени и пути
для сохранения шаблона, документ
копируется в соответствующую папку с
заданным именем, открывается окно
Добавления документов.
Табл. 1.6. Одновременное открытие документа при завершении
действия пользователя
9.
реакция веб-интерфейса
выбор опции «Открыть после
выделение выбранной опции (например,
завершения»
галочкой)
10. Нажатие «Завершить»
закрытие окна создания, переход к списку
документов декларации, Сохранение
сведений из строки описи, заполненных
пользователем, в xml документе,
добавление документа в список документов
декларации.
30
Создать документ:
На данном этапе должна быть доступна следующая информация:
- типы документов, разделенные по классам.
Операции, разрешенные на данном этапе:
- выбрать тип документа.
Табл. 1.7. Сценарий пользователя
действия пользователя
1. нажатие на кнопку «Новый» в списке
доступных операций
реакция веб-интерфейса
открытие окна с раскрывающимся списком
категорий документов
2. выбор типа документа для создания
3. нажатие на кнопку «Создать»
закрывается окно со списком типов
документов,
Загрузить документ:
На данном этапе должна быть доступна следующая информация:
- обзор директорий на локальном компьютере пользователя.
Операции, разрешенные на данном этапе:
- выбор директории на локальном компьютере;
- загрузка документа.
Табл. 1.8. Сценарий пользователя
действия пользователя
1. нажатие на кнопку «Загрузить» в
списке доступных операций
реакция веб-интерфейса
открытие окна для выбора директории на
локальном компьютере пользователя
2. выбор пути к документам для загрузки
3. нажатие «Загрузить»
закрывается окно выбора директории,
соответствующие данные из загруженного
документа переносятся в строку описи.
Альтернативные сценарии:
31
Табл. 1.9. Ошибки при загрузке документа
действия пользователя
реакция веб-интерфейса
выводится уведомление об ошибке загрузки
4.
документа, описание ошибки и возможные
причины устранения
3.3. Разработка графического интерфейса веб-приложения
В настоящее время существует большое количество программного обеспечения,
как облегчающего разработку приложений, так и программ, без которых работа вебприложения будет невозможна (например, веб-сервер). Поэтому, перед началом
разработки нужно выбрать используемое ПО.
Выбор интегрированной среды разработки:
Интегрированная среда разработки программного обеспечения (англ. IDE,
Integrated development environment) — система программных средств, используемая
программистами для разработки программного обеспечения. Обычно среда разработки
включает в себя текстовый редактор, компилятор и/или интерпретатор, средства
автоматизации сборки и отладчик. Иногда также содержит систему управления версиями
и разнообразные инструменты для упрощения конструирования графического интерфейса
пользователя. Современные популярные среды для разработки Java-приложений:
IntellijIDEA, Eclipse, JBuilder 2007. Выбор был сделан в пользу Eclipse потому, что:
1. Eclipse – бесплатная среда разработки, в отличие от IDEA и JBuilder.
2. По функциональным возможностям Eclipse не уступает платным IDE:
возможность завершения кода налету, возможность рефакторинга кода,
встроенный клиент системы управления версиями (CVS и SVN) и многое
другое.
Выбор веб-сервера:
Наиболее проверенные и распространенные веб-серверы, используемые для
развертывания веб-приложений на платформе Java EE 5 – это Apache Tomcat, BEA
WebLogic, IBM WebSphere и JBoss. Оптимальным выбором из этого программного
обеспечения является Apache Tomcat. Этот контейнер сервлетов имеет открытый код и
распространяется со свободной лицензией, т.е. его можно использовать любым
32
юридическим лицом, коммерческим и некоммерческим. Tomcat прост в настройке, не
требует установки (достаточно простого копирования на жесткий диск) и готов к работе
сразу после копирования. Также имеется большое количество исчерпывающей
документации по Apache Tomcat, в отличие от других веб-серверов.
Выбор системы контроля версий:
Система контроля версий (от англ. Version Control System или Revision Control
System) — программное обеспечение для облегчения работы с изменяющейся
информацией. Система версионного контроля позволяет хранить несколько версий одного
и того же документа, при необходимости, возвращаться к более ранним версиям,
определять, кто и когда сделал то или иное изменение и многое другое. Такие системы
наиболее широко применяются при разработке программного обеспечения, для хранения
исходных кодов разрабатываемой программы.
Наиболее популярные системы версионного контроля на сегодняшний день – это
Microsoft Visual SourceSafe (VSS), Subversion (SVN), Concurrent Versions System (CVS) и
Rational ClearCase. Выбор был сделан в пользу Subversion, т.к. это свободная система,
имеющая широкий функционал, русскоязычную документацию, поддерживающая работу
с проектом через Интернет. К тому же данная система контроля версий поддерживается
средой разработки Eclipse.
Итак, список программного обеспечения, необходимого при разработке:
- Java Development Kit 1.6.0_06
- Apache Tomcat 6
- Eclipse 3
- Плагин к Eclipse для поддержки GWT - Cypal Studio
- GWT 1.4.61
- GWT-Ext 2.0.3
- Subversion 1.4.2
После того, как были выбраны программы и средства, используемые при
разработке, можно приступить непосредственно к ней.
Для начала в Eclipse через меню File->New создадим новый Dynamic Web Project с
названием Declarant4Web. В создавшемся проекте в папку src добавим новый пакет
ru.spb.nicetu. Щелкнув правой кнопкой по папке nicetu и выбрав команду меню
New->GWT Module, создадим новый GWT модуль с названием DeclarantAPS. В
результате получим структуру каталогов веб-приложения, показанную на рис.10.
33
Рис.10. Структура каталогов разрабатываемого веб-приложения
Далее в папку lib копируем библиотеки gwt-ext.jar и gwt-servlet.jar. Первая
библиотека нужна для поддержки GWT-Ext виджетов, вторая отвечает за асинхронные
вызовы процедур клиентом. Также в папку public следует скопировать всё содержимое
библиотеки ExtJS, необходимой для работы GWT-Ext виджетов.
Краткое описание папок разрабатываемого веб-приложения:
1. WEB-INF. Данная папка содержит откомпилированные программные
модули, а также различные файлы настроек приложения (web.xml). Доступ в
эту папку со стороны веб-браузера запрещён.
2. WEB-INF/classes. В этой папке хранятся откомпилированные в Java байткод программные модули.
3. WEB-INF/lib. В этой папке содержатся дополнительные библиотеки,
используемые веб-приложением в процессе работы.
4. META-INF.
Содержит
метаданные
для
создаваемого
приложения
(manifest.mf), а также файл конфигурации приложения на веб-сервере
(context.xml).
5. src. В этой папке хранятся исходные коды Java-классов.
6. client, public, server. Смысл данных папок был пояснён в главе 4.4. данной
работы
Теперь
нужно
определить,
какие
GWT-модули
будет
использовать
разрабатываемое приложение, и на основе этого отредактировать файл конфигурации
DeclarantAPS.gwt.xml
GWT-модуля
DeclarantAPS,
автоматически
сформированный
Eclipse при создании модуля. Два обязательных модуля, которые должны наследоваться
любыми GWT-приложениями - com.google.gwt.user.User и com.google.gwt.core.Core. Так
как приложение будет использовать библиотеку виджетов GWT-Ext, то нужно
добавить модуль com.gwtext.GwtExt. Также приложение будет интернациональным
(подробнее об интернационализации GWT-приложения написано ниже), поэтому следует
34
использовать модуль com.google.gwt.i18n.I18N. Файл конфигурации разрабатываемого
GWT-приложения на данный момент должен выглядеть следующим образом:
<module>
<inherits name='com.google.gwt.user.User'/>
<inherits name="com.gwtext.GwtExt"/>
<inherits name="com.google.gwt.core.Core"/>
<inherits name="com.google.gwt.i18n.I18N"/>
<entry-point class=' ru.spb.nicetu.declarantAPS.client.DeclarantAPS '/>
</module>
Метод onModuleLoad() класса DeclarantAPS, сгенерированного Eclipse при
создании GWT-модуля, будет выполняться первым при загрузке приложения в веббраузере.
После настройки приложения перейдём к написанию кода и построению
графического интерфейса.
Рассмотрим основные моменты разработки.
3.3.1.
Разбиение
окна
веб-приложения
на
области,
обозначенные
при
проектировании интерфейса
Для разбиения окна веб приложения на области воспользуемся возможностью
граничной компоновки виджетов (BorderLayout). Такая компоновка располагает виджеты
относительно центра панели: выше центра, ниже центра, левее центра, правее центра, в
центре. Все виджеты в данном случае растягиваются до заполнения всей площади панели.
Соответственно область 0 расположим выше центра (северное направление), область 1
расположим левее центра (западное направление), а область 2 расположим по
центру. Для чего определим 4 панели: главную, северную, западную и центральную, где
главная панель – корневая панель, содержащая все другие панели и виджеты приложения.
Panel mainPanel=new Panel();
Panel northPanel=new Panel();
Panel westPanel=new Panel();
Panel centerPanel=new Panel();
Для того, чтобы главной панели установить граничную компоновку виджетов,
нужно вызвать метод setLayout():
mainPanel.setLayout(new BorderLayout());
Затем, нужно создать параметры для граничной компоновки такие, как ширина
области, высота области, возможность растягивания области и др.
35
BorderLayoutData westLayoutData = new BorderLayoutData(RegionPosition.WEST);
westLayoutData.setSplit(true); //возможность растягивания области 1
westLayoutData.setMinSize(90);//минимальный размер области 1 (в пикселях)
westLayoutData.setMaxSize(300); //максимальный размер области 1 (в пикселях)
BorderLayoutData centerLayoutData = new BorderLayoutData(RegionPosition.CENTER);
BorderLayoutData northLayoutData = new BorderLayoutData(RegionPosition.NORTH);
northLayoutData.setSplit(false);//запрещение растягивания области 0
Теперь всё готово для размещения областей в главной панели. Для этого
воспользуемся методов add(), имеющегося у любого контейнера виджетов.
mainPanel.add(northPanel,northLayoutData);
mainPanel.add(centerPanel,centerLayoutData);
mainPanel.add(westPanel,westLayoutData);
Для того, чтобы указать, какая панель в приложении является корневой, нужно
создать объект класса Viewport, передав в качестве параметра конструктора корневую
панель.
Viewport viewport = new Viewport(mainPanel);
Так как разбиение окна браузера на области должно происходить при загрузке
приложения, то весь вышеприведенный код следует вставить в метод onModuleLoad()
класса DeclarantAPS.
Исходный код данного класса приведён в приложении 3.
Запустим приложение в режиме отладки (команда Run->Run as…->GWT
Application) и посмотрим результат. Окно приложения разбилось на 3 области, но они
пока пустые.
3.3.2. Интернационализация разрабатываемого веб-интерфейса
Иногда бывает необходимо разработать программный продукт для нескольких
стран с учётом особенностей их культуры и языка. Такой процесс адаптации продукта
к языковым и культурным особенностям страны, отличной от той, в которой
разрабатывался продукт, называется интернационализацией. В английском языке для
слова «internationalization» принято сокращение «i18n». При этом число 18 означает
количество пропущенных между «i» и «n» букв [6].
Исправление исходного кода продукта под особенности каждой страны очень
ресурсоёмкий
процесс,
поэтому
таким
подходом
пользуются
очень
редко.
В
GWT-фреймворке для реализации интернационализации используются специальные
файлы, в которых записаны на разных языках строковые константы приложения. Такой
36
файл содержит записи вида ключ/значение, где ключ — строка, используемая в исходном
коде приложения, а значение — перевод ключа на конкретный язык. Каждый отдельный
файл отвечает за языковые настройки одной конкретной страны. Названия таких файлов
должны отличаются только окончанием. Например: constants_ru.txt, constants_en.txt
В случае разработки веб-интерфейса для таможенного декларанта использование
интернационализации поможет в будущем легко перевести интерфейс портала на другой
язык.
Для интернационализации приложения с помощью GWT-фреймворка нужно
выполнить следующие действия:

Унаследовать
разрабатываемым
GWT-модулем
специальный
GWT-модуль
com.google.gwt.i18n.I18N. Для этого в конфигурационный файл разрабатываемого
модуля следует добавить строку <inherits name="com.google.gwt.i18n.I18N"/>

Разработать файлы, хранящие перевод строковых констант на языки других стран.
Например, Constants.properties, Constants_en.properties. Причём, если название
файла
не
содержит
суффикса
страны,
то
считается,
что
этот
файл
используется приложением по умолчанию. Пример содержания разрабатываемых
файлов:

Constants.properties (язык по умолчанию):
menuCreate = Создать декларацию
addButton = Добавить

Constants_en.properties (английский язык):
menuCreate = Create declaration
addButton = Add

В том же пакете, где находятся файлы с константами, создать интерфейс с таким
же именем, как и название файлов (без суффикса страны). Данный интерфейс
должен наследовать класс com.google.gwt.i18n.client.ConstantsWithLookup. Внутри
интерфейса должны быть перечислены методы, возвращающие тип String и
названия которых соответствуют ключам, используемым в файлах констант.
С помощью таких методов в дальнейшем можно будет обращаться к
константам.
Например:
public interface Constants extends ConstantsWithLookup {
String menuCreate ();
String addButton ();
}
37

Для использования интернациональных констант нужно с помощью статического
метода create() класса com.google.gwt.core.client.GWT создать экземпляр класса,
реализующего построенный в п.3 интерфейс Constants.
Constants myConstants = (Constants) GWT.create(Constants.class);
Вызов метода этого класса возвратит языковую константу:
MessageBox.alert(myConstants.menuCreate());
Язык, на котором возвращается константа, зависит от так называемой локали (от
англ. locale), использующейся в данный момент. Локаль — набор параметров, включая
набор символов, язык пользователя, страну, часовой пояс, а также другие предустановки,
которые пользователь ожидает видеть в пользовательском интерфейсе. По умолчанию,
модуль com.google.gwt.i18n.I18N использует одну локаль, называемую default. Этой
локали соответствует файл с константами, название которого не имеет суффикса страны.
Для использования другой локали следует передать её название в параметре URL вебприложения. Например,
http://www.example.org/myapp.html?locale=en. В этом случае,
метод myConstants.menuCreate()
возвратит
не
«Создать
декларацию»,
а
«Create
declaration».
3.3.3. Разработка панели инструментов
Для создания панели инструментов в GWT-Ext существует специальная панель,
называемая Toolbar. Основные методы данной панели:

void
addButton(ToolbarButton button)
- добавление обычной кнопки в
панель инструментов.

void
addButton(ToolbarMenuButton button) - добавление кнопки-меню в
панель инструментов. Нажатие на такую кнопку приводит к открытию
меню.

void addField(Field field) - добавление текстовых полей или раскрывающихся
списков (комбобоксов) в панель инструментов.

void
addFill() – данный метод добавляет пустое пространство в панель
инструментов таким образом, что все добавленные в панель после вызова
данного метода компоненты будут выровнены по правому краю.

void
addSeparator() - добавляет разделитель в виде вертикальной полосы.
Создадим новый класс ToolbarAPS, который наследует класс Toolbar. В
конструкторе класса создадим и добавим необходимые кнопки и одно текстовое поле для
быстрого поиска документов и деклараций:
// Кнопка "Создать декларацию"
38
ToolbarButton createButton = new ToolbarButton(constants.menuCreate());
addButton(createButton);
……………..
// Текстовое поле для поиска
searchtext=new TextField();
addField(searchtext);
Метод
constants.menuCreate()
возвращает
интернациональную
строку
соответствующую текущей локали. Эта строка является текстом, отображающимся на
кнопке. Для придания большей информативности кнопкам панели инструментов
разместим на них также и картинки. Для этого воспользуемся методом setIconCls(String
icoCls), где параметр icoCls является CSS-классом, в котором указан путь к картинке. CSSклассы добавляются в файле DeclarantAPS.css, созданным Eclipse автоматически при
создании GWT-модуля. Пример CSS-класса, описывающего картинку:
.decl_new-icon {
background-image: url(images/decl_new.gif );
}
Для отображения этой картинки на кнопке вызовем метод:
createButton.setIconCls("decl_new-icon");
Теперь нужно обеспечить обработку действий декларанта при нажатии на кнопки
панели инструментов и при нажатии клавиши «Enter» в текстовом поле. Для этого
воспользуемся методами addListener() для кнопки и addKeyListener() для текстового поля,
добавляющими прослушиватель событий к виджету.
createButton.addListener(new ButtonListenerAdapter() {
public void onClick(Button button, EventObject eventObject) {
//CreateDeclarationWindow
–
класс
окна создания
декларации,
//разрабатываемый ниже
CreateDeclarationWindow window=new Window();window.show();
}
});
searchtext.addKeyListener(13, new KeyListener() {//13 – ASCII код клавиши «Enter»
public void onKey(int i, EventObject eventObject) {
openSearch(searchtext.getText());
searchtext.setValue(""); //очищаем текстовое поле
}
});
39
Исходный код класса ToolbarAPS приведён в приложении 3.
После того, как мы создали панель инструментов, её нужно разместить в области 0.
Для этого в методе onModuleLoad класса DeclarantAPS добавляем следующий код:
/*
Устанавливаем панели заполняющий вид компоновки виджетов. Это означает, что
в данную панель будет добавлен только один виджет, который заполнит собой всю
площадь панели.
/*
northPanel.setLayout(new FitLayout());
//добавляем панель инструментов в область 0
northPanel.add(new ToolbarAPS());
3.3.4. Разработка центральной панели с закладками
Для создания панели с закладками в GWT-Ext существует специальная панель,
называемая TabPanel. Основные методы данной панели:

void
activate(int tabIndex) – активировать закладку по индексу

void
activate(java.lang.String tabID) – активировать закладку по её ID

Panel getActiveTab() - возвращает текущую активную панель

Panel getItem(java.lang.String id) – возвращает закладку по её ID

boolean hasItem(java.lang.String id) - проверяет, имеет ли панель закладку с
указанным идентификатором.

void
setActiveTab(int activeTab) - устанавливает индекс закладки, которая
должна быть активирована при создании панели.

void
setEnableTabScroll(boolean
enableTabScroll)
–
устанавливает
возможность прокрутки закладок, если они не помещаются в панель.

void
setResizeTabs(boolean resizeTabs) – устанавливает автоматическое
уменьшение ширины закладок, если они не помещаются в панель.

void
setTabWidth(int tabWidth) – устанавливает ширину закладки в
пикселях.
Создадим новый класс TabPanelAPS, который наследует класс TabPanel. В
конструкторе класса установим необходимые параметры для создаваемой панели:
setResizeTabs(true);
setTabWidth(120);
setActiveTab(0);
40
Во время работы разработки приложения нам будет нужен доступ к этой панели,
например, для добавления новой вкладки. Осуществить такой доступ в GWT-модуле
можно путём присвоения определённого ID к панели. По умолчанию, ID к виджетам
генерируются GWT-автоматически.
Добавим в класс статическое поле panelID:
public static final String panelID="apsTabPanel";
Добавим в конструктор присвоение ID:
setId(panelID);
Теперь из любого места программы можно получить экземпляр созданной панели.
Для этого нужно воспользоваться статическим методом getCmp() класса Ext:
(TabPanelAPS) Ext.getCmp(TabPanelAPS.panelID);
Для того, чтобы в разрабатываемую панель добавить новую закладку, нужно учесть
тот факт, что данная закладка уже может быть добавлена в панель. В этом случае нужно
просто активировать имеющуюся закладку. Создадим метод, который автоматически
проверяет этот факт и при необходимости активирует имеющуюся закладку:
public void addTab(Panel newTab){
if (tabPanel.hasItem(newTab.getId())) {
tabPanel.scrollToTab(newTab, true);
tabPanel.activate(newTab.getId());
} else {
tabPanel.add(newTab);
}
}
Исходный код класса TabPanelAPS приведён в приложении 3.
После того, как мы создали панель, её нужно разместить в области 2. Для этого в
методе onModuleLoad класса DeclarantAPS добавляем следующий код:
/*
Устанавливаем панели заполняющий вид компоновки виджетов. Это означает, что
в данную панель будет добавлен только один виджет, который заполнит собой всю
площадь панели.
/*
centerPanel.setLayout(new FitLayout());
//добавляем панель инструментов в область 2
centerPanel.add(new TabPanelAPS ());
41
3.3.5. Разработка сервиса для работы с декларациями
Для создания сервиса нужно:
1. Сформировать интерфейс, определяющий выполняемые сервисом функции.
Данный
интерфейс
должен
наследовать
интерфейс
com.google.gwt.user.client.rpc.RemoteService.
Пример интерфейса:
public interface DeclarationService extends RemoteService {
/**
* Создание новой декларации
* параметры: comments – комментарии к декларации
*
isDts,
isKts,
isTransportCards,
isPredDecl
–
параметры,
*определяющие, нужно ли к создаваемой декларации прикрепить
*документы: ДТС, КТС, карточку транспортного средства, список
*компонентов,
а
также
является
ли
создаваемая
декларация
*предварительной
/*
public void createNewDecl(String comments,
boolean isDts, boolean isKts,
boolean isTransportCards,
boolean isComponentList,
boolean isPredDecl );
//Возвращает
массив
последних
деклараций.
limit
–
число,
//определяющее количество возвращенных деклараций
String[] getListOfAllSds(int limit );
//Удаляет декларацию по её ID
void removeDeclaration(String declarationId);
}
2. Так как вызываемые методы асинхронны, то необходим еще один
интерфейс, методы которого не возвращают значения (т.е. возвращают тип
void) и на вход получают дополнительный параметр — ссылку на callback
процедуру. Данный интерфейс должен находиться в том же пакете, что и
первый интерфейс, а также иметь такое же имя с добавлением суффикса
“Async”.
Пример асинхронного интерфейса:
interface DeclarationServiceAsync {
42
void createNewDecl(String comments,
boolean isDts, boolean isKts,
boolean isTransportCards,
boolean isComponentList,
boolean isPredDecl, AsyncCallback callback);
void getListOfAllSds(int limit, AsyncCallback callback);
void removeDeclaration(String declarationId, AsyncCallback callback);
}
3. Сформировать класс, реализующий функции сервиса на стороне сервера.
Данный класс должен наследовать класс com.google.gwt.user.server.rpc.
RemoteServiceServlet, отвечающий за десериализацию приходящих и
сериализацию исходящих объектов. Данный класс является сервлетом,
поэтому
необходимо
также
добавить
информацию
о
сервлете
в
конфигурационный файл модуля и в дескриптор развёртывания вебприложения (файл web.xml). Код, написанный в данном классе, выполняется
на сервере, поэтому на него не накладывается никаких ограничений с точки
зрения поддержки GWT-компилятором.
Пример реализации сервиса:
public class DeclarationServiceImpl extends RemoteServiceServlet implements
DeclarationService{
public void createNewDecl(String comments,
boolean isDts, boolean isKts,
boolean isTransportCards,
boolean isComponentList,
boolean isPredDecl ){
EdeclarationQuery query = new EdeclarationQuery();
query.createNewDecl(comments,
isDts,
isKts,
isComponentList, isPredDecl)
}
String[] getListOfAllDecl(int limit ){
EdeclarationQuery query = new EdeclarationQuery();
return query.getListOfAllDecl(limit );
}
void removeDeclaration(String declarationId){
EdeclarationQuery query = new EdeclarationQuery();
43
isTransportCards,
query.removeDeclaration (declarationId);
}
}
В данном коде класс EdeclarationQuery выполняет различные запросы на выборку и
сохранение в базу данных.
Таким образом, чтобы сформировать сервис, нужно создать 2 интерфейса и 1 класс.
Eclipse позволяют создавать сервисы очень быстро. Для этого нужно щелкнуть правой
кнопкой по пакету, в котором предполагается создавать сервис, выбрать команду меню
New-> New GWT Service и ввести название сервиса. Eclipse автоматически создаст 3
файла: DeclarationService.java, DeclarationServiceAsync.java и DeclarationServiceImpl.
Сам вызов асинхронных процедур происходит в следующей последовательности:
4. Получить экземпляр класса, реализующего асинхронный интерфейс.
DeclarationServiceAsync
declService
=
(DeclarationServiceAsync)
GWT.create(DeclarationService.class);
5. Указать URL, на котором выполняется созданный сервис. Этот URL должен
совпадать с тем, который был прописан в пункте 3.
ServiceDefTarget endpoint = (ServiceDefTarget) declService;
String moduleRelativeURL = GWT.getModuleBaseURL()+"declarationService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
6. Создать объект, реализующий интерфейс com.google.gwt.user.client.rpc.
AsyncCallback. После завершения выполнения асинхронной процедуры
сервис
передаст
управление
одному
из
методов
созданного
объекта: onSuccess() или onFailure(). Первый выполняется при успешном
завершении
асинхронной
возникновении
процедуры,
исключительной
второй,
ситуации
во
соответственно,
время
асинхронной процедуры.
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
MessageBox.alert(“Успешно: ”+ (String[])result[0]);
}
public void onFailure(Throwable caught) {
MessageBox.alert(“Неудачно”);
}
};
44
при
выполнения
Объект result в методе onSuccess() является возвращаемым значением
асинхронного метода. Объект caught в методе onFailure() содержит
информацию о возникшей исключительной ситуации.
7. Произвести вызов асинхронной процедуры.
declService.getListOfAllDecl(3, callback);
При удачном выполнении на сервере данной процедуры через некоторое время
появится окно с текстом «Успешно: Декларация 1, Дата создания 21.05.2008».
3.3.6. Разработка панели отображения новых деклараций
Так как список новых деклараций хранится на сервере в базе данных, то клиент не
может напрямую обратится к ним. Поэтому воспользуемся разработанным выше сервисом
DeclarationService. Данные, полученные от сервиса разместим в таблице. В GWT-Ext есть
специальный виджет GridPanel, реализующий таблицу с возможностью фильтрования и
сортировки данных. Основные методы класса GridPanel:

void
addGridListener(GridListener listener) – добавление прослушивателя событий
для ячеек таблицы.

void hideColumn(int colIndex) – скрыть колонку по её индексу

void
reconfigure(Store store, ColumnModel columnModel) – устанавливаются новые
хранилище данных store и модель отображения колонок. Класс Store - хранит
исходные данные для таблицы, а класс ColumnModel содержит данные о колонках:
названия колонок, количество колонок, возможность сортировки по колонке и др.

void
setDisableSelection(boolean disableSelection) – запретить выделение строк в
таблице

void
setEnableDragDrop(boolean enableDragDrop) – разрешить перетаскивание
ячеек таблицы технологией drag’n’drop

void
setHideColumnHeader(boolean hideColumnHeader) – скрывает заголовок
таблицы, т.е. названия колонок.

void
setStore(Store store) – устанавливает ссылку на хранилище исходных данных
для таблицы
Создадим новый класс DeclPanel, который наследует класс GridPanel. В
конструкторе класса установим необходимые параметры для создаваемой таблицы.
Создадим модель отображения колонок. В разрабатываемой таблице предполагается лишь
одна колонка, отображающая комментарий к декларации и дату её создания.
ColumnModel columnModel = new ColumnModel(new ColumnConfig[]{
// «Declaration» – название колонки, 180 – ширина колонки в пикселях
45
new ColumnConfig("Declaration", 180);
});
setColumnModel(columnModel);
Скроем заголовок таблицы, т.к. он не нужен:
setHideColumnHeader(true);
Теперь нужно загрузить исходные данные для таблицы с сервера. Воспользуемся
разработанным сервисом для работы с декларациями. Для чего сделаем разрабатываемый
класс, реализующим интерфейс AsyncCallback и вызовем метод getListOfAllDecl() сервиса
DeclarationService:
DeclarationServiceAsync
declService
=
(DeclarationServiceAsync)
GWT.create(DeclarationService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) declService;
String moduleRelativeURL = GWT.getModuleBaseURL()+"declarationService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
//10 – количество загружаемых деклараций. Таким запросом, мы получим
//список, состоящий из 10 последних созданных деклараций.
declService.getListOfAllDecl(10, this);
После вызова асинхронного метода, следует реализовать обработку callbackметодов: onSuccess() и onFailure().
public void onFailure(Throwable throwable){
GWT.log("Ошибка выборки списка новых деклараций", throwable);
}
public void onSuccess (Object obj){
//Проверяем пришедший объект на null
if (obj!=null){
//Создаём объект Store – хранилище исходных данных для таблицы
Store store = new Store ((String[])obj);
setStore(store);
}
}
Теперь таблица загружает и отображает данные о последних декларациях.
Осталось добавить созданную панель в область 1. Для этого в методе onModuleLoad
класса DeclarantAPS добавляем следующий код:
46
/*Устанавливаем панели заполняющий вид компоновки виджетов. Это означает,
что в данную панель будет добавлен только один виджет, который заполнит собой
всю площадь панели.
/*
westPanel.setLayout(new FitLayout());
//добавляем панель инструментов в область 1
westPanel.add(new DeclPanel());
3.3.7. Разработка окна для создания новой декларации
Для реализации всплывающего окна в GWT-Ext существует виджет Window.
Основные методы класса Window:

void
close() - закрытие окна, а также уничтожение объекта окна.

void
hide() - спрятать окно, не уничтожая объект.

void
maximize() , void
restore() - базовые операции
minimize() , void
с окном – развернуть, свернуть, восстановить

void
setActive() – активировать окно.

void
setClosable(boolean closable) – метод, указывающий нужно ли
отображать кнопку «“X” – закрыть» у окна.

void
setCloseAction(Window.CloseAction
closeAction)
–
определяет
действие при нажатии на кнопку «Закрыть»: уничтожение объекта окна,
либо просто скрытие без уничтожения объекта.

void
setModal(boolean
modal)
–
устанавливает,
является
ли
окно
модальным.

void
setResizable(boolean resizable) – устанавливает возможность изменять
размер окна.

void
show() – показывает окно.

void
setTitle() – устанавливает заголовок окна.

void setWidth(int width), void setHeight(int height) – устанавливают ширину и
высоту окна.
Создадим новый класс CreateDeclarationWindow, который наследует класс Window.
В конструкторе класса установим необходимые параметры для создаваемой панели:
setClosable(true);
setResizable(false);
setModal(true);
setWidth(400);
47
setHeight(350);
setTitle(constants.menuCreate());
В данное окно нужно добавить текстовое поле для ввода комментария к
декларации и несколько чекбоксов, определяющих, нужно ли к создаваемой декларации
прикрепить документы ДТС, КТС, карточку транспортного средства, список компонент, а
также, является ли создаваемая декларация предварительной. Все виджеты должны
следовать друг за другом по вертикали, поэтому у окна следует установить вертикальную
компоновку виджетов.
setLayout(new VerticalLayout(15)); //15 – расстояние в пикселях между виджетами
по вертикали.
Создадим и добавим в окно необходимые виджеты:
TextArea comment = new TextArea(constants.sdsCreateComment())
Checkbox dtsCheck = new Checkbox(constants.sdsCreateDts());
Checkbox ktsCheck = new Checkbox(constants.sdsCreateKts());
Checkbox cardsCheck = new Checkbox(constants.sdsCreateCards());
Сheckbox componentCheck = new Checkbox(constants.sdsCreateComponent());
Checkbox predDeclCheck = new Checkbox(constants.sdsCreatePreddecl());
В параметрах конструкторов указаны заголовки, которые будут иметь виджеты.
add(comment);add(dtsCheck);
add(ktsCheck);add(cardsCheck);
add(componentCheck);add(predDeclCheck);
К интерфейсу разрабатываемого окна осталось добавить 2 кнопки: «Создать» и
«Отмена». Для этого создадим их и добавим к окну.
Button buttonCreate=new Button(constants.buttonCreate());
Button buttonCancel=new Button(constants.buttonCancel());
addButton(buttonCreate); addButton(buttonCancel);
Теперь осталось добавить действия, которые будут происходить при нажатии на
кнопки «Создать» и «Отмена». Для этого добавим к кнопкам прослушиватель событий:
buttonCancel.addListener(new ButtonListenerAdapter(){
public void onClick(Button button, EventObject e) {
close(); //закрываем окно
}});
buttonCreate.addListener(new ButtonListenerAdapter(){
public void onClick(Button button, EventObject e) {
//вызываем асинхронный метод создания декларации
48
DeclarationServiceAsync
declService
=
(DeclarationServiceAsync)
GWT.create(DeclarationService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) declService;
String moduleRelativeURL = GWT.getModuleBaseURL()+"declarationService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
declService.createNewDecl(comment.getValueAsString(),dtsCheck.isChecked(),
ktsCheck.isChecked(),cardsCheck.isChecked(),componentCheck.isChecked(),
predDeclCheck.isChecked, this);
}
});
Так как в этом классе был использован вызов сервиса, то класс должен
реализовывать интерфейс AsyncCallback.
Теперь осталось дождаться результата выполнения сервиса и при успешном
выполнении закрыть окно.
public void onFailure(Throwable throwable){
GWT.log("Ошибка при создании декларации", throwable);
}
public void onSuccess (Object obj){
close();
}
Мною были рассмотрены все основные моменты разработки веб-интерфейса.
3.3.8. Описание остальных разработанных классов
DocumentTab – панель, выполняющая функции работы с документами: создание,
копирование, удаление, переимование документов и др.
DocumentService – сервис, предназначенный для работы с документами.
SearchTab – панель, отображающая результаты быстрого поиска по документам и
декларациям. Поиск производится по значению текстового поля, расположенного в
панели инструментов.
MessagePanel – панель, отображающая в области 1b, количество новых полученных
сообщений.
MessageService – сервис, предназначенный для работы с сообщениями.
Результат разработки графического веб-интерфейса для портала таможенного
декларанта приведён в приложении 4 (рис. 1, рис. 2, рис. 3)
49
Заключение
В результате выполнения данной работы был разработан интерфейс вебприложения для таможенного декларанта, отвечающий поставленным требованиям.
Для реализации интерфейса веб-приложения среди имеющихся на рынке средств
разработки был выбран фреймворк Google Web Toolkit, который позволяет разрабатывать
«обогащенные» веб-приложения на основе технологии AJAX на базе платформы
Java EE 5. Выбранные технологии дают достаточно простую и эффективную реализацию
интерфейса веб-приложения для таможенного декларанта. Для разработчика – это
простота разработки, т.к. отсутствует прямая работа с HTML, что существенно сокращает
время разработки. Для конечного пользователя – это программный продукт с
интерфейсом, приближенным к настольному приложению, что должно упростить
внедрение этого продукта.
В процессе разработки программного обеспечения были проанализированы
функциональные
требования
к
интерфейсу
портала
декларанта
и
выбраны
соответствующие графические компоненты. В дополнение к этому были описаны методы
создания веб-приложения с использованием фреймворка Google Web Toolkit.
Следует отметить, что применение передовых технологий позволило разработать
востребованный в условиях современного рынка программный продукт.
Список литературы
1. Дейв Крейн, Эрик Паскарелло. Ajax в действии. – М. : Издательский дом
"Вильямc", 2006.
2. Закас Н., Мак-Пик Д., Фосетт Д. Ajax для профессионалов – СПб.: Символ-Плюс,
2007
3. Тидвелл Д. Разработка пользовательских интерфейсов – СПб.: Питер, 2007
4. Ноутон П., Шилдт Г. Java 2 – СПб.: БХВ-Петербург, 2001
5. Флэнаган Д. JavaScript. Подробное руководство, 4-е издание – СПб.: СимволПлюс, 2004
Интернет-ресурсы:
6. http://ru.wikipedia.org/wiki - свободная Интернет-энциклопедия
7. http://code.google.com/webtoolkit/ - сайт разработчиков GWT
8. http://www.gwt-ext.com/ - сайт разработчиков GWT-Ext
50
Приложения
Приложение 1. Список GWT компонентов
Таблица 1. Список GWT компонентов
Button
RadioButton
PushButton
ToggleButton
CheckBox
TextBox
PasswordTextBox
TextArea
Hyperlink
ListBox
MenuBar
Tree
51
Table
TabBar
DialogBox
PopupPanel
StackPanel
HorizontalPanel
VerticalPanel
FlowPanel
52
VerticalSplitPanel
HorizontalSplitPanel
DockPanel
TabPanel
RichTextArea
DisclosurePanel
SuggestBox
53
Приложение 2. Список GWT-Ext компонентов
Таблица 1. Список GWT-Ext компонентов
TreePanel
Buttons
Panels
ProgressDialog
Window
Combobox
54
Toolbars & Menus
Grid
FormPanel
TabPanel
DataView
ColorPicker
DatePicker
Tooltips
55
Charts
Maps
Приложение 3. Исходные коды программы
Класс DeclarantAPS:
public class DeclarantAPS implements EntryPoint {
public void onModuleLoad() {
MyConstants constants = (MyConstants) GWT.create(MyConstants.class);
Panel mainPanel=new Panel();
Panel northPanel=new Panel();
Panel westPanel=new Panel();
Panel centerPanel=new Panel();
mainPanel.setLayout(new BorderLayout());
BorderLayoutData westLayoutData = new BorderLayoutData(RegionPosition.WEST);
westLayoutData.setSplit(true);
westLayoutData.setMinSize(90);
westLayoutData.setMaxSize(300);
BorderLayoutData centerLayoutData = new BorderLayoutData(RegionPosition.CENTER);
BorderLayoutData northLayoutData = new BorderLayoutData(RegionPosition.NORTH);
northLayoutData.setSplit(false);
northPanel.setLayout(new FitLayout());
northPanel.add(new ToolbarAPS());
centerPanel.setLayout(new FitLayout());
centerPanel.add(new TabPanelAPS ());
westPanel.setLayout(new FitLayout());
westPanel.add(new DeclPanel());
mainPanel.add(northPanel,northLayoutData);
mainPanel.add(centerPanel,centerLayoutData);
mainPanel.add(westPanel,westLayoutData);
56
Viewport viewport = new Viewport(mainPanel);
}
}
Класс ToolbarAPS:
public class ToolbarAPS extends Toolbar {
public final Image iconConnected=new Image("images/status/connect.gif");
public final Image iconDisconnected=new Image("images/status/disconnect.gif");
private TextField searchtext;
public ToolbarAPS() {
super();
Menu menu = new Menu();
menu.setShadow(true);
menu.setMinWidth(10);
MyConstants constants = (MyConstants) GWT.create(MyConstants.class);
// Меню "Создать декларацию"
ToolbarButton createButton = new ToolbarButton(constants.menuCreate());
createButton.addListener(new ButtonListenerAdapter() {
public void onClick(Button button, EventObject eventObject) {
new CreateDeclarationWindow().show();
}
});
createButton.setIconCls("decl_new-icon");
addButton(createButton);
// Меню "Папки"
ToolbarButton foldersButton=new ToolbarButton(constants.menuFolders());
foldersButton.addListener(new ButtonListenerAdapter() {
public void onClick(Button button, EventObject eventObject) {
(TabPanelAPS) Ext.getCmp(TabPanelAPS.panelID).addTab(new DocumentTab ());
}
});
foldersButton.setIconCls("folder-icon");
addButton(foldersButton);
57
// Меню "Архивы"
ToolbarButton archiveButton=new ToolbarButton(constants.menuArchive());
archiveButton.addListener(new ButtonListenerAdapter() {
public void onClick(Button button, EventObject eventObject) {
(TabPanelAPS) Ext.getCmp(TabPanelAPS.panelID).addTab (new ArchiveTab());
//}
}
});
archiveButton.setIconCls("archive-icon");
addButton(archiveButton);
addSeparator();
addFill();
// Текстовое поле для поиска
searchtext=new TextField();
searchtext.addKeyListener(13, new KeyListener() {
public void onKey(int i, EventObject eventObject) {
openSearch(searchtext.getText());
searchtext.setValue("");
}
});
addField(searchtext);
// Меню "Поиск"
ToolbarButton find= new ToolbarButton(constants.menuFind());
find.setIconCls("search-icon");
find.addListener(new ButtonListenerAdapter(){
public void onClick(Button button, EventObject e) {
openSearch(searchtext.getText());
searchtext.setValue("");
}
});
addButton(find);
}
58
public void openSearch(String text) {
(TabPanelAPS) Ext.getCmp(TabPanelAPS.panelID).addTab (new SearchTab(text));
}
}
Класс TabPanelAPS:
public class TabPanelAPS extends TabPanel {
public static final String panelID="apsTabPanel";
public TabPanelAPS(){
setResizeTabs(true);
setTabWidth(120);
setActiveTab(0);
setId(panelID);
}
public void addTab(Panel newTab){
if (tabPanel.hasItem(newTab.getId())) {
tabPanel.scrollToTab(newTab, true);
tabPanel.activate(newTab.getId());
} else {
tabPanel.add(newTab);
}
}
}
Класс DeclPanel:
public class DeclPanel extends Panel implements AsyncCallback{
public DeclPanel (){
ColumnModel columnModel = new ColumnModel(new ColumnConfig[]{
new ColumnConfig("Declaration", 180);
}
setColumnModel(columnModel);
setHideColumnHeader(true);
59
DeclarationServiceAsync
declService
=
(DeclarationServiceAsync)
GWT.create(DeclarationService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) declService;
String moduleRelativeURL = GWT.getModuleBaseURL()+"declarationService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
declService.getListOfAllDecl(10, this);
}
public void onFailure(Throwable throwable){
GWT.log("Ошибка выборки списка новых деклараций", throwable);
}
public void onSuccess (Object obj){
if (obj!=null){
Store store = new Store ((String[])obj);
setStore(store);
}
}
}
Класс CreateDeclarationWindow:
public class CreateDeclarationWindow extends Window implements AsyncCallback{
private TextArea comment ;
private Checkbox dtsCheck;
private Checkbox ktsCheck;
private Checkbox cardsCheck;
private Сheckbox componentCheck ;
private Checkbox predDeclCheck;
public CreateDeclarationWindow (){
setClosable(true);
setResizable(false);
setModal(true);
setWidth(400);
setHeight(350);
MyConstants constants = (MyConstants) GWT.create(MyConstants.class);
60
setTitle(constants.menuCreate());
comment = new TextArea(constants.sdsCreateComment())
dtsCheck = new Checkbox(constants.sdsCreateDts());
ktsCheck = new Checkbox(constants.sdsCreateKts());
cardsCheck = new Checkbox(constants.sdsCreateCards());
componentCheck = new Checkbox(constants.sdsCreateComponent());
predDeclCheck = new Checkbox(constants.sdsCreatePreddecl());
setLayout(new VerticalLayout(15));
add(comment);
add(dtsCheck);
add(ktsCheck);
add(cardsCheck);
add(componentCheck);
add(predDeclCheck);
Button buttonCreate=new Button(constants.buttonCreate());
Button buttonCancel=new Button(constants.buttonCancel());
addButton(buttonCreate);
addButton(buttonCancel);
buttonCancel.addListener(new ButtonListenerAdapter(){
public void onClick(Button button, EventObject e) {
close(); //закрываем окно
}
});
buttonCreate.addListener(new ButtonListenerAdapter(){
public void onClick(Button button, EventObject e) {
createNewDecl(){
}
});
}
public void close(){
super.close();
}
61
public void createNewDecl(){
DeclarationServiceAsync
declService
=
(DeclarationServiceAsync)
GWT.create(DeclarationService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) declService;
String moduleRelativeURL = GWT.getModuleBaseURL()+"declarationService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
declService.createNewDecl(comment.getValueAsString(),dtsCheck.isChecked(),
ktsCheck.isChecked(),cardsCheck.isChecked(),componentCheck.isChecked(),
predDeclCheck.isChecked, this);
}
public void onFailure(Throwable throwable){
GWT.log("Ошибка при создании декларации", throwable);
}
public void onSuccess (Object obj){
close();
}
}
Класс DocumentTab:
public class DocumentTab extends Panel {
private MyConstants constants = (MyConstants) GWT.create(MyConstants.class);
private Menu folderMenu = new Menu();
private Menu docMenu = new Menu();
private Toolbar docTool = new Toolbar();
// параметры копирования/вырезания/вставки папки
private boolean cutFolderFlag = false;
private TreeNode copyNode = null;
// параметры копирования/вырезания/вставки документа
private boolean cutDocFlag = false;
private Record copyRow = null;
private TreeNode rowFromFolder = null;
public DocumentTab () {
super(null);
setId("documentTab");
62
setTitle(constants.foldersTabname());
setClosable(true);
setIconCls("folder-icon");
// контекстное меню для папок
Item
createFolderItem
=
new
Item(constants.foldersMenuCreate(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
createFolder();
}
});
Item
deleteFolderItem
=
new
Item(constants.foldersMenuDelete(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
deleteFolder();
}
});
Item
copyFolderItem
=
new
Item(constants.foldersMenuCopy(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
cutFolderFlag = false;
copyFolder();
}
});
Item
cutFolderItem
=
new
Item(constants.foldersMenuCut(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
cutFolderFlag = true;
copyFolder();
}
});
Item
pastFolderItem
=
new
Item(constants.foldersMenuPast(),
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
pastFolder();
}
63
new
});
Item
renameFolderItem
=
new
Item(constants.foldersMenuRename(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
renameFolder();
}
});
folderMenu.addItem(createFolderItem);
folderMenu.addItem(deleteFolderItem);
folderMenu.addItem(copyFolderItem);
folderMenu.addItem(cutFolderItem);
folderMenu.addItem(pastFolderItem);
folderMenu.addItem(renameFolderItem);
// контекстное меню для документов
Item
createDocItem
=
new
Item(constants.foldersMenuCreate(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
createDocFunction();
}
});
Item
deleteDocItem
=
new
Item(constants.foldersMenuDelete(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
deleteDocFunction();
}
});
Item
copyDocItem
=
new
Item(constants.foldersMenuCopy(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
cutDocFlag = false;
copyDocFunction();
}
});
Item
editDocItem
=
new
Item(constants.foldersMenuEdit(),
BaseItemListenerAdapter() {
64
new
public void onClick(BaseItem baseItem, EventObject eventObject) {
editDocFunction();
}
});
Item
previewDocItem
=
new
Item(constants.foldersMenuPreview(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
viewDocFunction();
}
});
Item cutDocItem = new Item(constants.foldersMenuCut(), new BaseItemListenerAdapter()
{
public void onClick(BaseItem baseItem, EventObject eventObject) {
cutDocFlag = true;
copyDocFunction();
}
});
Item
pastDocItem
=
new
Item(constants.foldersMenuPast(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
pastDocFunction();
}
});
Item
renameDocItem
=
new
Item(constants.foldersMenuRename(),
new
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
renameDocFunction();
}
});
Item
puttoarchiveDocItem
=
new
Item(constants.foldersMemuPuttoarchive(),
BaseItemListenerAdapter() {
public void onClick(BaseItem baseItem, EventObject eventObject) {
putToArchive();
}
});
65
new
docMenu.addItem(createDocItem);
docMenu.addItem(deleteDocItem);
docMenu.addSeparator();
docMenu.addItem(copyDocItem);
docMenu.addItem(cutDocItem);
docMenu.addItem(pastDocItem);
docMenu.addSeparator();
docMenu.addItem(previewDocItem);
docMenu.addItem(editDocItem);
docMenu.addSeparator();
docMenu.addItem(renameDocItem);
docMenu.addItem(puttoarchiveDocItem);
// список операций с документами
docTool.setId("folderDocToolbar");
// создание документа
ToolbarButton createDoc = new ToolbarButton(constants.foldersMenuCreate(), new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
createDocFunction();
}
});
// удаление документа
ToolbarButton deleteDoc = new ToolbarButton(constants.foldersMenuDelete(), new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
deleteDocFunction();
}
});
// копирование документа
ToolbarButton
copyDoc
=
new
ToolbarButton(constants.foldersMenuCopy(),
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
cutDocFlag = false;
copyDocFunction();
}
66
new
});
// вырезать документ
ToolbarButton
cutDoc
=
new
ToolbarButton(constants.foldersMenuCut(),
new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
cutDocFlag = true;
copyDocFunction();
}
});
// вставка документа
ToolbarButton
pastDoc
=
new
ToolbarButton(constants.foldersMenuPast(),
new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
pastDocFunction();
}
});
// просмотр документа
ToolbarButton previewDoc = new ToolbarButton(constants.foldersMenuPreview(), new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
viewDocFunction();
}
});
// редактирование документа
ToolbarButton
editDoc
=
new
ToolbarButton(constants.foldersMenuEdit(),
new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
editDocFunction();
}
});
// переименование документа
ToolbarButton renameDoc = new ToolbarButton(constants.foldersMenuRename(), new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
renameDocFunction();
67
}
});
// поместить документ в архив
ToolbarButton puttoarchiveDoc = new ToolbarButton(constants.buttonPuttoarchive(), new
ButtonListenerAdapter() {
public void onClick(Button button, EventObject e) {
putToArchive();
}
});
// добавление иконок к кнопкам
createDoc.setIconCls("document_new-icon");
createDoc.setId("createDocButton");
deleteDoc.setIconCls("document_delete-icon");
deleteDoc.setId("deleteDocButton");
copyDoc.setIconCls("aps-copy-icon");
copyDoc.setId("copyDocButton");
cutDoc.setIconCls("aps-cut-icon");
cutDoc.setId("cutDocButton");
pastDoc.setIconCls("aps-past-icon");
pastDoc.setId("pastDocButton");
renameDoc.setIconCls("aps-rename-icon");
renameDoc.setId("renameDocButton");
editDoc.setIconCls("document_edit-icon");
editDoc.setId("editDocButton");
previewDoc.setIconCls("document_view-icon");
previewDoc.setId("previewDocButton");
puttoarchiveDoc.setIconCls("aps-put-to-archive-icon");
puttoarchiveDoc.setId("puttoarchiveDocButton");
// добавление кнопок на тулбар
docTool.addButton(createDoc);
docTool.addSeparator();
docTool.addButton(deleteDoc);
docTool.addSeparator();
docTool.addButton(copyDoc);
docTool.addSeparator();
68
docTool.addButton(cutDoc);
docTool.addSeparator();
docTool.addButton(pastDoc);
docTool.addSeparator();
docTool.addButton(previewDoc);
docTool.addSeparator();
docTool.addButton(editDoc);
docTool.addSeparator();
docTool.addButton(renameDoc);
docTool.addSeparator();
docTool.addButton(puttoarchiveDoc);
rightPanel.setTopToolbar(docTool);
getFoldersList();
}
public void updateDocumentList() {
getDocs(getSelectedNode());
}
protected void onNodeContextMenu(TreeNode treeNode, EventObject eventObject) {
super.onNodeContextMenu(treeNode, eventObject);
treeNode.select();
pathText.setText(constants.foldersPath()+": "+treeNode.getAttribute("fullpath"));
folderMenu.showAt(eventObject.getXY());
if(treeNode.getAttribute("id").equalsIgnoreCase("0")) {
hideDocPanel();
}
else {
getDocs(treeNode);
}
}
protected
void
onRecordContextMenu(GridPanel
gridPanel,
eventObject) {
super.onRecordContextMenu(gridPanel, row, eventObject);
gridPanel.getSelectionModel().selectRow(row);
eventObject.stopEvent();
docMenu.showAt(eventObject.getXY());
69
int
row,
EventObject
}
protected void hideDocPanel() {
super.hideDocPanel();
(Ext.getCmp("createDocButton")).setDisabled(false);
(Ext.getCmp("deleteDocButton")).setDisabled(true);
(Ext.getCmp("copyDocButton")).setDisabled(true);
(Ext.getCmp("cutDocButton")).setDisabled(true);
(Ext.getCmp("pastDocButton")).setDisabled(false);
(Ext.getCmp("editDocButton")).setDisabled(true);
(Ext.getCmp("previewDocButton")).setDisabled(true);
(Ext.getCmp("renameDocButton")).setDisabled(true);
(Ext.getCmp("puttoarchiveDocButton")).setDisabled(true);
}
protected void showDocPanel() {
super.showDocPanel();
(Ext.getCmp("createDocButton")).setDisabled(false);
(Ext.getCmp("deleteDocButton")).setDisabled(false);
(Ext.getCmp("copyDocButton")).setDisabled(false);
(Ext.getCmp("editDocButton")).setDisabled(false);
(Ext.getCmp("previewDocButton")).setDisabled(false);
(Ext.getCmp("copyDocButton")).setDisabled(false);
(Ext.getCmp("cutDocButton")).setDisabled(false);
(Ext.getCmp("pastDocButton")).setDisabled(false);
(Ext.getCmp("renameDocButton")).setDisabled(false);
(Ext.getCmp("puttoarchiveDocButton")).setDisabled(false);
}
// создание папки
void createFolder() {
CreateFolder createPopup = new CreateFolder(getSelectedNode());
createPopup.show();
}
// удаление папки
void deleteFolder() {
final TreeNode folder = getSelectedNode();
if(!root.isSelected()) {
70
if(folder.getChildNodes().length > 0) {
MessageBox.alert(constants.foldersErrorTitle(), constants.foldersErrorDelete());
return;
}
// подтверждение
new YesNoPopup(constants.foldersPopupDeleteTitle(),
constants.foldersPopupDeletefolderMessage()+" \""+folder.getText()+"\"?",
new YesNoPopupCallback() {
public void onYes() {
// удаление папки в базе
FoldersService.App.getInstance().deleteFolder(folder.getAttribute("id"),
new AsyncCallback() {
public void onFailure(Throwable throwable) {
CommonServices.errorMessage(throwable);
}
public void onSuccess(Object o) {
TreeNode deleteNode = getSelectedNode();
TreeNode parent = (TreeNode)deleteNode.getParentNode();
treePanel.getSelectionModel().select(parent);
parent.removeChild(deleteNode);
pathText.setText(constants.foldersPath()+":
"+parent.getAttribute("fullpath"));
if(parent.getAttribute("id").equalsIgnoreCase("0")) {
hideDocPanel();
}
else {
getDocs(parent);
}
}
});
}
public void onNo() {
}
});
}
71
}
// копирование папки
void copyFolder() {
TreeNode node = getSelectedNode();
if(node != null && !root.isSelected()) {
if(node.getChildNodes().length > 0)
MessageBox.alert(constants.foldersErrorTitle(), constants.foldersErrorCopy());
else {
copyNode = node;
}
}
}
// переименование папки
void renameFolder() {
TreeNode node = getSelectedNode();
if(node != null && !root.isSelected()) {
RenameFolder renameFolder = new RenameFolder(node);
renameFolder.show();
}
}
// вставка папки
void pastFolder() {
final TreeNode node = getSelectedNode();
final TreeNode tmpNode = copyNode;
if(node != null && copyNode != null) {
if(!cutFolderFlag) {
FoldersService.App.getInstance().copyFolder(copyNode.getAttribute("id"),
node.getAttribute("id"), node.getAttribute("fullpath")+"/"+copyNode.getText(),
new AsyncCallback() {
public void onFailure(Throwable throwable) {
MessageBox.alert(constants.foldersErrorTitle(),
constants.foldersErrorCreate());
}
public void onSuccess(Object o) {
TreeNode newFolder = new TreeNode(tmpNode.getText());
72
newFolder.setAttribute("id", tmpNode.getAttribute("id"));
newFolder.setAttribute("parent_id", node.getAttribute("parent_id"));
newFolder.setAttribute("fullpath",
node.getAttribute("fullpath")+"/"+tmpNode.getText());
node.appendChild(newFolder);
node.expand();
}});
}
else {
FoldersService.App.getInstance().moveFolder(copyNode.getAttribute("id"),
node.getAttribute("id"), node.getAttribute("fullpath")+"/"+copyNode.getText(),
new AsyncCallback() {
public void onFailure(Throwable throwable) {
MessageBox.alert(constants.foldersErrorTitle(),
constants.foldersErrorCreate());
}
public void onSuccess(Object o) {
TreeNode parent = (TreeNode)tmpNode.getParentNode();
TreeNode newFolder = tmpNode.cloneNode();
parent.removeChild(tmpNode);
newFolder.setAttribute("parent_id", node.getAttribute("id"));
newFolder.setAttribute("fullpath",
node.getAttribute("fullpath")+"/"+tmpNode.getText());
node.appendChild(newFolder);
node.expand();
treePanel.getSelectionModel().select(parent);
pathText.setText(constants.foldersPath()+":
"+parent.getAttribute("fullpath"));
if(parent.getAttribute("id").equalsIgnoreCase("0")) {
hideDocPanel();
}
else {
getDocs(parent);
}
}
73
}); }
}
copyNode = null;
cutFolderFlag = false;
}
// создание документа
void createDocFunction() {
final TreeNode node = getSelectedNode();
final String folderId = node.getAttribute("id");
if(!node.getAttribute("id").equalsIgnoreCase("0")) {
new CreateDocument(new CreateDocumentCallback() {
public void onOk(String docType, String docName) {
new
DocumentManager().createDocument(folderId,
docType,
docName,
Document.FOLDER);
getDocs(node);
}
public void onCancel() {
}
});}
}
// уделение документа
void deleteDocFunction() {
final Record doc = getSelectedRecord();
final TreeNode node = getSelectedNode();
if(node != null && doc != null) {
// подтверждение
new YesNoPopup(constants.foldersPopupDeleteTitle(),
constants.foldersPopupDeletedocumentMessage()+"
\""+doc.getAsString("name")+"\"?",
new YesNoPopupCallback() {
public void onYes() {
// удаление документа в базе
DocumentService.App.getInstance().deleteDocument(node.getAttribute("id"),
doc.getAsString("id"), Document.FOLDER,
new AsyncCallback() {
74
public void onFailure(Throwable throwable) {
CommonServices.errorMessage(throwable);
}
public void onSuccess(Object o) {
getDocs(node);
}
});
}
public void onNo() {
}
}); }
}
// копирование/перемещение документа
void copyDocFunction() {
Record doc = getSelectedRecord();
TreeNode node = getSelectedNode();
if(doc != null) {
if(!cutDocFlag)
copyRow = doc;
else {
if(doc.getAsString("locked").equalsIgnoreCase("true"))
MessageBox.alert(constants.foldersErrorTitle(), constants.foldersErrorCutdoc());
else {
copyRow = doc;
rowFromFolder = node;
}
}
}
}
// встава документа
void pastDocFunction() {
TreeNode node = getSelectedNode();
if(copyRow != null && node != null) {
if(!cutDocFlag) {
FoldersService.App.getInstance().copyDocument(copyRow.getAsString("id"),
75
node.getAttribute("id"), new AsyncCallback() {
public void onFailure(Throwable throwable) {
CommonServices.errorMessage(throwable);
}
public void onSuccess(Object o) {
getDocs(getSelectedNode());
}
});
}
else {
FoldersService.App.getInstance().moveDocument(copyRow.getAsString("id"),
node.getAttribute("id"), rowFromFolder.getAttribute("id"),
new AsyncCallback() {
public void onFailure(Throwable throwable) {
CommonServices.errorMessage(throwable);
}
public void onSuccess(Object o) {
getDocs(getSelectedNode());
}
});
}
}
copyRow = null;
rowFromFolder = null;
cutDocFlag = false;
}
// переименование папки
void renameDocFunction() {
Record doc = getSelectedRecord();
if(doc != null) {
RenameDocument renameFolder = new RenameDocument(doc);
renameFolder.show();
}
}
// редактирование документа
76
void editDocFunction() {
RowSelectionModel selectionModel = gridPanel.getSelectionModel();
Record doc = selectionModel.getSelected();
if(doc != null) {
NativeMethods.openDoc(doc.getAsString("id"), doc.getAsString("type"));
}
}
// просмотр документа
void viewDocFunction() {
Record doc = getSelectedRecord();
if(doc != null) {
NativeMethods.viewDoc(doc.getAsString("id"), doc.getAsString("type"));
}
}
void putToArchive() {
DocumentService.App.getInstance().isArchiveDocument(getSelectedRecord().getAsString("id"),
new AsyncCallback() {
public void onFailure(Throwable throwable) {
MessageBox.alert("Error", throwable.getMessage());
}
public void onSuccess(Object o) {
Boolean result = (Boolean)o;
if(result != null) {
if(result.booleanValue())
MessageBox.alert(constants.foldersErrorTitle(),
constants.foldersErrorPuttoarchive());
else
new AddDocumentToArchive(getSelectedRecord().getAsString("id")).show();
}
}
});
}
}
77
Приложение 4. Результат разработки веб-интерфейса
Рис.1 Результат быстрого поиска
78
Рис.2 Окно работы с документами
79
Рис.3 Окно создания новой декларации
80
Download