К современным Web-приложениям предъявляются все более высокие требования. Они должны уметь работать с учетными данными пользователей, обеспечивать загрузку контента и потокового видео. Эти задачи требуют использования технологий, ускоряющих процесс разработки и в то же время обеспечивающих поддержку всех наиболее востребованных функций. Разработчики приложений RIA должны уметь правильно выбирать комплексы технологий, позволяющие наилучшим образом решать поставленные задачи.
Adobe Flex – это технология, работающая на стороне клиента и позволяющая разработчикам использовать богатый набор API-вызовов для создания графических пользовательских интерфейсов, вывода графики, воспроизведения мультимедиа-содержимого и подключения к Web-сервисам. Технология Java, применяемая на стороне сервера, обеспечивает такие возможности, как подключение к реляционным СУБД, многопоточная обработка запросов на обслуживание и оптимальное масштабирование в случаях увеличения нагрузки. Совместное использование этих двух технологий дает мощную техническую основу для создания RIA-приложений.
В этой статье будет показано, как написать простое, но мощное RIA-приложение, использующее технологию Flex на стороне клиента, технологию Java на стороне сервера и СУБД MySQL в качестве системы хранения данных.
В нашем примере приложения (см. раздел Загрузка) имеется функционально насыщенный пользовательский интерфейс, поддерживающий создание, чтение, обновление и удаление (функции CRUD – Create, Read, Update, Delete) информации о контакте через приложение Adobe Flash® (SWF). На рисунке 1 изображена трехуровневая Web-архитектура, в которой клиентская часть представлена SWF-файлом, встроенным в Web-страницу, серверная часть выполняется внутри контейнера Java-сервлета (в нашем случае это Apache Tomcat), а в качестве базы данных используется MySQL. Совместное использование этих трех технологий позволяет создать мощное распределенное приложение.
Рисунок 1. Приложение Contacts
Для обеспечения взаимодействия между Flash-приложением и контейнером Java-сервлета инфраструктура BlazeDS предоставляет в ваше распоряжение функцию удаленного взаимодействия с объектами – особую форму удаленного вызова процедур, позволяющую объектам Adobe ActionScript™ обращаться к объектам Java и наоборот. Взаимодействием между приложением Java-сервера и реляционной базой данных управляет ORM-инфраструктура Hibernate, которая позволяет преобразовывать объекты Java в код SQL и наоборот.
Сначала мы создадим Java-класс, содержащий всю информацию, необходимую для хранения данных о контактах. В нашем тестовом приложении реализована простая модель, содержащая базовую информацию. В объектах Contact используются следующие атрибуты и типы данных.
- String emailAddress
- String firstName
- long id
- String lastName
- String phoneNumber
- long serialVersionUID
+ Contact()
+ Contact(String first, String last, String email, String number)
+ String getEmailAddress()
+ String getFirstName()
+ long getId()
+ String getLastName()
+ String getPhoneNumber()
+ void setEmailAddress(String address)
+ void setFirstName(String first)
+ void setId(long newId)
+ void setLastName(String last)
+ void setPhoneNumber(String number)
+ StringtoString()
Java-класс Contact считается классом POJO, выступающим в роли бизнес-объекта; это означает, что в нем должны быть реализованы функции и методы конкретной бизнес-области. Данные внутри объектов класса Contact необходимо сохранять в базе данных. Решением этой задачи является использование инфраструктуры объектно-реляционного отображения (ORM), такой как Hibernate, которая выполняет всю основную работу по преобразованию объектов в записи таблиц БД и обратно. Если вы используете аннотации Java Persistence API (JPA), для реализации ORM требуется написать лишь незначительное количество кода. В листинге 1 представлена аннотация Java-класса Contact.
Листинг 1. Java-класс Contact
package bcit.contacts;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table(name="contact")
@NamedQueries( {
@NamedQuery(name = "contact.findAll", query = "from Contact"),
@NamedQuery(name = "contact.getById", query =
"select c from Contact c where c.id = :id")
} )
public class Contact {
private static final long serialVersionUID = 123456789L;
public Contact() {
firstName = "N/A";
lastName = "N/A";
emailAddress = "N/A";
phoneNumber = "N/A";
}
public Contact(String first, String last, String email, String number) {
firstName = first;
lastName = last;
emailAddress = email;
phoneNumber = number;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false, updatable=false)
private long id;
@Column(name = "lastName", nullable = false, unique = false)
private String lastName;
@Column(name = "firstName", nullable = false, unique = false)
private String firstName;
@Column(name = "emailAddress", nullable = false, unique = false)
private String emailAddress;
@Column(name = "phoneNumber", nullable = false, unique = false)
private String phoneNumber;
public void setPhoneNumber(String number) { phoneNumber = number; }
public String getPhoneNumber() { return phoneNumber; }
public String getEmailAddress() { return emailAddress; }
public void setEmailAddress(String address) { emailAddress = address; }
public String getFirstName() { return firstName; }
public void setFirstName(String first) { firstName = first; }
public String getLastName() { return lastName; }
public void setLastName(String last) { lastName = last; }
public long getId() { return id; }
public void setId(long newId) { id = newId; }
@Override
public String toString() {
return id + " " + firstName + " " + lastName + " " + emailAddress
+ " " + phoneNumber;
}
}
|
Начнем рассмотрение этого простого класса с используемых в нем аннотаций.
@Column: маркирует свойство в качестве столбца базы данных, позволяя задавать для него имя, определять уникальность и возможность хранить null-значения.@Entity: объявляет класс в качестве объекта entity bean; это означает, что данный класс является классом POJO, предназначенным для сохранения.@GeneratedValue: определяет метод генерации первичных ключей; доступны значенияAUTO,IDENTITY,SEQUENCEиTABLE@Id: определяет свойство в качестве уникального идентификатора (то есть первичного ключа) для каждого Java-объекта.@NamedQueries: хранит список именованных запросов.@NamedQuery: объявляет предопределенный запрос в качестве строковой константы; обратившись к ней впоследствии, можно вызвать запрос на исполнение.@Table: объявляет Java-класс в качестве таблицы базы данных.
Каждый раз, когда необходимо сохранить находящийся в памяти Java-объект, Hibernate преобразует информацию о его состоянии в SQL-оператор UPDATE. Аналогичным образом SQL-операторы с их возвращаемыми наборами данных используются для формирования Java-объектов. В результате этих операций все объекты могут сохраняться в базе данных в виде записей, а все записи могут быть извлечены из базы данных и преобразованы обратно в Java-объекты.
Аннотации указывают Hibernate, какие компоненты класса должны считаться сохраняемыми. Но это только часть картины.
Бизнес-сервис: связь с базой данных
Для обращений к библиотеке Hibernate с целью выполнения ORM-преобразований нам потребуется служебный класс. В листинге 2 представлен код класса ContactsService, выступающего в роли сервиса приложений.
Листинг 2. Класс ContactsService
public class ContactsService {
private static Logger logger = Logger.getLogger(ContactsService.class);
private static final String PERSISTENCE_UNIT = "contacts";
private static EntityManagerFactory emf = null;
static {
logger.info("LOADING CONTACTSSERVICE CLASS.");
emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
}
public ContactsService() {
super();
}
public void addContact(Contact c) {
if(c == null) {
return;
}
EntityManager em = emf.createEntityManager();
logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");
logger.info("ABOUT TO ADD CONTACT: fName: " + c.getFirstName()
+ ", lName: " + c.getLastName() + ", email:" + c.getEmailAddress()
+ ", phone: " + c.getPhoneNumber());
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.merge(c);
tx.commit();
} catch (Exception e) {
logger.error("CONTACT APP PERSISTING ERROR: " + e.getMessage());
tx.rollback();
} finally {
logger.info("CONTACT APP CLOSING ENTITY MANAGER.");
em.close();
}
}
public void editContact(Contact c) {
logger.info("CONTACT TO UPDATE: " + c);
addContact(c);
}
public void deleteContact(Long id) {
logger.info("ABOUT TO DELETE CONTACT");
EntityManager em = emf.createEntityManager();
logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");
Query contactByIdQuery = em.createNamedQuery("contact.getById");
contactByIdQuery.setParameter("id", id);
Contact c = (Contact) contactByIdQuery.getSingleResult();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.remove(c);
tx.commit();
} catch (Exception e) {
logger.error("CONTACT APP PERSISTING ERROR: " + e.getMessage());
tx.rollback();
} finally {
logger.info("CONTACT APP CLOSING ENTITY MANAGER.");
em.close();
}
}
public List<Contact> getContacts() {
logger.info("ABOUT TO RETRIEVE CONTACTS");
EntityManager em = emf.createEntityManager();
logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");
Query findAllContactsQuery =
em.createNamedQuery("contact.findAll");
List<Contact> contacts = findAllContactsQuery.getResultList();
if (contacts != null) {
logger.debug("CONTACT APP RETRIEVED: " + contacts.size()
+ " CONTACT(S)");
}
return contacts;
}
}
|
Каждый метод получает ссылку на класс EntityManager, который представляет собой хранящийся в памяти кэш. Кэширование - мощная технология, обеспечивающая эффективность работы, поскольку запись и получение информации из базы данных могут отнимать много ресурсов. С вашей стороны требуется лишь обеспечить фиксацию или откат (в случае необходимости) каждой транзакции для кэшированных данных.
В JPA кэш представлен классом EntityManager, и для его для обозначения используется термин контекст хранения. Каждый контекст хранения управляет набором сущностей, которые являются Java-объектами, объявленными при помощи аннотаций @Entity. Класс EntityManagerFactory представляет собой модуль хранения, отвечающий за настройку подключений к хранилищу данных (например, к реляционной БД), управление типами сущностей (то есть всеми классами указанного контекста, которые необходимо преобразовывать для размещения в хранилище данных) и, наконец, за предоставление доступа к экземплярам контекста хранения (то есть класса EntityManager).
В отличие от создания контекста хранения, создание модуля хранения может занять много времени. Настройка подключения к хранилищу данных, нахождение всех классов, объявленных как сущности, и настройка логики для привязки этих классов к сущностям хранилища данных требуют больших затрат. Поэтому создавать экземпляр класса EntityManagerFactory следует во время запуска приложения. Что касается контекста хранения – необходимо позаботиться о том, чтобы перед созданием каждого экземпляра EntityManager всегда уничтожался предыдущий экземпляр. Другое важное правило заключается в необходимости следовать модели entitymanager-per-request, которая группирует обращения к базе данных (например, запросы и операции обновления) таким образом, чтобы все они передавались одновременно. Такая модель позволяет использовать все преимущества механизма кэширования JPA.
Теперь перейдем к написанию клиентской части приложения.
Инфраструктура Flex позволяет создавать приложения, которые пользователи могут воспроизводить с помощью Adobe Flash Player. Flex состоит из следующих компонентов.
- Основанный на XML декларативный язык описания интерфейсов, известный как MXML
- Язык программирования ActionScript.
- Библиотеки времени выполнения для создания пользовательских интерфейсов, Web-соединений, а также для реализации многих других возможностей.
- Инструменты для компиляции приложений в SWF-файлы.
В клиентском приложении, рассматриваемом в этой статье, используется инфраструктура Flex версии 4. Прежде чем перейти к клиентскому приложению, важно понять, как создаются приложения Flex и как они существуют в форме исполняемых файлов внутри Flash Player.
Сначала вы можете создать приложение, используя комбинацию разметки MXML и кода ActionScript. Общая последовательность действий заключается в написании GUI-интерфейса (уровень представления) с использованием формата MXML и последующем написании кода ActionScript (бизнес-логика и обработка событий). Поскольку работа с MXML и ActionScript происходит в текстовом режиме, для создания Flash-приложений требуется только текстовый редактор и инструментарий Flex SDK.
После написания приложения Flex его код компилируется с помощью компилятора MXML. Компилятор MXML создает SWF-файлы, которые могут быть запущены в Web-браузере (с помощью плагина Flash Player).
Наконец, Flash-приложения выполняются внутри виртуальной машины ActionScript Virtual Machine 2 (AVM2) по принципу "временной линейки" (timeline). В соответствии с этим принципом выполнение программы разбивается на кадры, подобно кинофильму. На этапе компиляции Flash-приложения вы задаете для него требуемое количество кадров в секунду. Кроме того, выполнение приложений Flash Player разбивается на ряд следующих задач.
- События Flash Player, такие как таймер и события мыши.
- Пользовательский код.
- Логика предварительного рендеринга, на этапе которого Flash Player пытается определить необходимость обновления графического интерфейса пользователя вследствие изменения исходных значений.
- Пользовательский код, связанный с изменением исходных значений.
- Рендеринг Flash Player.
Если требуется выполнять рендеринг лишь нескольких кадров в секунду, можно выполнять больше пользовательского кода. Однако если требуемая частота кадров высока (например, 60 кадров в секунду), Flash Player может не справиться с обработкой большого объема пользовательского кода, поскольку для его выполнения может не хватить отведенного времени. Об этом важно помнить при написании приложений для Flash Player.
MXML – это мощный декларативный XML-формат, реализующий следующие возможности.
- Минимизация объема кода (в силу декларативной сущности формата XML), требуемого для написания графического интерфейса.
- Упрощение кода графического интерфейса благодаря четкому разделению логики представления и логики взаимодействия.
- Поддержка подхода к разработке ПО с использованием шаблонов проекта.
В листинге 3 представлен код MXML-класса Application.
Листинг 3. Класс ContactsApp
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:contact="bcit.contacts.*" creationComplete="initPage();"
layout="vertical" frameRate="30" pageTitle="Contacts Example"
horizontalAlign="center" verticalAlign="middle"
backgroundColor="#A9C0E7">
<mx:Style>
.mainBoxStyle {
borderStyle: solid;
paddingTop: 5px;
paddingBottom: 5px;
paddingLeft: 5px;
paddingRight: 5px;
}
.textMessages {
fontWeight: bold;
}
</mx:Style>
<mx:RemoteObject id="remotingService" showBusyCursor="false"
destination="contacts" fault="handleFault(event);"
result="handleResult(event);"/>
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.collections.ArrayCollection;
import bcit.contacts.dto.Contact;
[Bindable]
private var contacts:ArrayCollection = new ArrayCollection();
// For more on the Bindable metadata tag, see the devguide_flex3.pdf
// document, page 1249 (1257 in PDF page numbering)
[Bindable]
private var message:String = "Status: Ready";
private var contact:Contact;
public function setControlBarValid(valid:Boolean):void {
if(valid) {
// if the selected item is -1, then no item is selected but at
// the same time the fields are valid which means the user chose
// to add a contact, not update one
if(contactsDataGrid.selectedIndex == -1) {
createButton.enabled = valid;
} else {
editButton.enabled = valid;
}
} else {
// else nothing is valid
createButton.enabled = false;
editButton.enabled = false;
}
}
private function initPage():void {
editContactForm.setApp(this);
contact = new Contact();
getAllContacts();
resetPage();
}
private function createContact():void {
contact = editContactForm.getContact();
remotingService.addContact(contact);
message = "Status: Contact Added";
getAllContacts();
}
private function editContact():void {
var id:Number = contact.id;
contact = editContactForm.getContact();
contact.id = id;
remotingService.editContact(contact);
message = "Status: Contact Edited";
getAllContacts();
}
private function deleteContact():void {
if(contactsDataGrid.selectedItem != null) {
var c:Contact = contactsDataGrid.selectedItem as Contact;
// no sense in sending the whole contact - just send the id
// to cut down on bandwidth
remotingService.deleteContact(c.id);
message = "Status: Contact Deleted";
}
getAllContacts();
}
private function getAllContacts():void {
loadButton.enabled = false;
remotingService.getContacts();
loadButton.enabled = true;
resetPage();
}
private function populateFormWithContact():void {
contact = contactsDataGrid.selectedItem as Contact;
editContactForm.setContact(contact);
editButton.enabled = true;
deleteButton.enabled = true;
}
private function resetPage():void {
editContactForm.clearForm();
contact = new Contact();
createButton.enabled = false;
editButton.enabled = false;
deleteButton.enabled = false;
contactsDataGrid.selectedIndex = -1;
}
private function handleFault(e:FaultEvent):void {
message = "Status: Error"
+ "\nFault code: " + e.fault.faultCode
+ "\nFault detail: " + e.fault.faultDetail
+ "\nFault string: " + e.fault.faultString;
}
private function handleResult(e:ResultEvent):void {
// can get the results by accessing e.result property
//mx.controls.Alert.show(e.toString());
contacts = e.result as ArrayCollection;
var number:int = contacts.length;
//if(number == 1) {
// message = "Status: Retrieved 1 contact";
//} else {
// message = "Status: Retrieved " + contacts.length + " contacts";
//}
}
]]>
</mx:Script>
<mx:VBox styleName="mainBoxStyle">
<mx:Text id="titleText" text="Single click to select a contact"/>
<contact:ContactsDataGrid id="contactsDataGrid" dataProvider="{contacts}"
itemClick="populateFormWithContact();"
doubleClick="populateFormWithContact();"/>
<contact:EditContactForm id="editContactForm"/>
<mx:ControlBar horizontalAlign="center">
<mx:Button label="List" id="loadButton" click="getAllContacts()"
toolTip="Retrieve contacts from the server"/>
<mx:Button label="Add" id="createButton" click="createContact()"
toolTip="Create a new contact"/>
<mx:Button label="Update" id="editButton" click="editContact()"
toolTip="Edit a selected contact"/>
<mx:Button label="Delete" id="deleteButton" click="deleteContact()"
toolTip="Delete a selected contact"/>
<mx:Button label="Clear Form" id="clearButton" click="resetPage()"
toolTip="Clear the form"/>
</mx:ControlBar>
<mx:TextArea text="{message}" styleName="textMessages" wordWrap="true"
verticalScrollPolicy="auto" horizontalScrollPolicy="off" editable="false"
width="100%"/>
</mx:VBox>
</mx:Application>
|
Остановимся на рассмотрении наиболее важных моментов листинга 3 .
- Корневым элементом MXML-документа является подкласс класса
Application. - Элемент
mx:Styleпозволяет задать свойства CSS для локального оформления компонентов пользовательского интерфейса. Оформление можно задать с помощью локальных определений (как это сделано в листинге 3), ссылок на внешние таблицы стилей, указания стилей внутри компонентов, а также с помощью методаsetStyleязыка ActionScript. - Класс
RemoteObjectпредставляет собой объект HTTP-сервиса, выполняющий операции удаленного взаимодействия с сервером. - Элемент
mx:Scriptсодержит блоки кода ActionScript, заключенные в разделCDATA. - В коде присутствует только одна компоновка (то есть класс
VBox). - Каждый раз, когда в приложении объявляется компонент пользовательского интерфейса (например,
TextArea), генерируется переменная экземпляра, на которую впоследствии можно ссылаться с помощью атрибута компонентаid. - Привязка данных осуществляется с помощью фигурных скобок (например, атрибут
textэлементаTextAreaпривязан к переменной экземпляра языка ActionScriptmessage).
Пользовательский интерфейс определяется с помощью MXML, а язык ActionScript используется для обработки событий, привязки данных (через тег метаданных [Bindable]) и обращения к удаленным сервисам. Все методы в листинге 3 – createContact, editContact,
deleteContact и getAllContacts – обращаются к удаленным методам на стороне сервера. При вызове удаленных методов ActionScript можно использовать для обработки результатов (как успешных, так и неудачных) путем объявления функций обратного вызова. Функция handleResult в листинге 3 получает результат в качестве объекта Object и передает его объекту ArrayCollection. BlazeDS преобразует объект List в объект ArrayCollection на стороне сервера.
В листинге 4 представлен ActionScript-код класса Contact, который создается для представления объектов контакта на стороне Flash.
Листинг 4. ActionScript-класс Contact
package bcit.contacts.dto {
[RemoteClass(alias="bcit.contacts.Contact")]
public class Contact {
public function Contact() { id = -1; }
public var id:Number;
public var lastName:String;
public var firstName:String;
public var emailAddress:String;
public var phoneNumber:String;
public function toString():String {
return id + ", " + firstName + " " + lastName + " " + emailAddress
+ " " + phoneNumber;
}
}
}
|
Эти объекты ActionScript передаются на сторону сервера, где BlazeDS преобразует объекты ActionScript в объекты Java. ActionScript-класс Contact рассматривается как объект передачи данных (Data Transfer Object, DTO).
Приложение, рассматриваемое в этой статье, использует конфигурационные файлы, содержащие параметры сервера. Две важнейшие области конфигурирования – это Hibernate и BlazeDS.
Параметры инфраструктуры Hibernate можно настроить с помощью стандартного конфигурационного файла JPA persistence.xml, представленного в листинге 5.
Листинг 5. Конфигурационный файл persistence.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="contacts" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.default_schema" value="contacts" />
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/contacts" />
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="root"/>
</properties>
</persistence-unit>
</persistence>
|
Чтобы обеспечить доступ к данным файла persistence.xml в среде Hibernate, его необходимо поместить в папку Web-приложения WEB-INF/classes/META-INF. После того как файл будет помещен в указанную папку, он должен содержать следующую информацию.
- Диалект базы данных (к какой именно базе данных происходят обращения, поскольку разные базы данных могут иметь разные SQL-диалекты).
- Табличное пространство, определенное с помощью схемы по умолчанию.
- Драйвер, использующийся для подключения к базе данных
- URL-адрес базы данных.
- Объекты для автоматического обнаружения (например, аннотированные классы, XML-файлы сопоставлений Hibernate и так далее).
- Имя и пароль пользователя.
Остальные параметры могут влиять на работу Hibernate, но не являются обязательными.
Инфраструктура BlazeDS настраивается с помощью четырех конфигурационных файлов.
- messaging-config.xml: файл настройки схемы обмена сообщениями "издатель-подписчик".
- proxy-config.xml: файл настройки параметров прокси для HTTP- и Web-сервисов.
- remoting-config.xml: файл настройки параметров сервисов удаленного взаимодействия, таких как приложение, рассматриваемое в этой статье.
- services-config.xml: конфигурационный файл верхнего уровня, содержащий ссылки на все остальные файлы, а также настройки безопасности, параметры каналов и журналирования.
В листинге 6 показано содержимое файла services-config.xml. Обратите внимание на то, что в нашем приложении используется только один файл – remoting-config.xml, поскольку мы работаем только с сервисом удаленного взаимодействия BlazeDS.
Листинг 6. Конфигурационный файл services-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="remoting-config.xml" />
<service-include file-path="messaging-config.xml" />
<service-include file-path="proxy-config.xml" />
<default-channels>
<channel ref="contacts-amf"/>
</default-channels>
</services>
<channels>
<channel-definition id="contacts-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8080/contacts/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>false</polling-enabled>
</properties>
</channel-definition>
</channels>
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Error">
<properties>
<prefix>[BlazeDS] </prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
</filters>
</target>
</logging>
</services-config>
|
Конфигурационный файл services-config.xml ссылается на другие конфигурационные файлы (которые должны существовать), а также настраивает систему журналирования BlazeDS и несколько каналов. Канал – это абстракция протокола, используемого для взаимодействия клиента с сервером. В приложении этой статьи используется стандартный протокол AMF без опроса. Опрос означает, что клиенты постоянно взаимодействуют с сервером с целью убедиться, что соединение не разорвано. В нашем приложении этого не требуется.
С помощью конечной точки канала задается URL-адрес сервера. Для успешной компиляции проекта всегда должна быть указана конечная точка; клиентское Flash-приложение использует ее в качестве жестко заданного значения, определяющего сервер, к которому необходимо подключаться. На практике URL-адрес конечной точки можно задать непосредственно в коде MXML или ActionScript.
Наконец, в конфигурационном файле remoting-config.xml (листинг 7) указывается класс адаптера, необходимого для обработки операций удаленного взаимодействия, а также классы, отвечающие на удаленные вызовы (в нашем случае классом, отвечающим на удаленные запросы, является класс bcit.contacts.ContactsService).
Листинг 7. Конфигурационный файл remoting-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object" default="true"
class="flex.messaging.services.remoting.adapters.JavaAdapter"/>
</adapters>
<default-channels>
<channel ref="contacts-amf"/>
</default-channels>
<destination id="contacts">
<properties>
<source>bcit.contacts.ContactsService</source>
<!--<scope>application</scope>-->
</properties>
</destination>
</service>
|
В этой статье было продемонстрировано, как написать Web-приложение, работающее на стороне Java-сервера под управлением Tomcat и отвечающее на запросы для получения контактной информации. Вы также узнали, как с помощью MXML и ActionScript написать Flex-приложение, работающее на стороне клиента. В качестве хранилища данных мы использовали MySQL, а преобразование Java-объектов в SQL-запросы осуществлялось с помощью ORM-инфраструктуры Hibernate. Наконец, инфраструктура BlazeDS позволяет Flash-приложениям осуществлять удаленные вызовы процедур и получать удаленный доступ к Web-приложениям, запущенным на стороне Java-сервера.
| Имя | Размер | Метод загрузки |
|---|---|---|
| JEE-BlazeDS-Flex-contacts.zip | 7 МБ | HTTP |
Другие файлы для загрузки
Заметка
- В zip-архиве содержится весь исходный код (Java, ActionScript 3, MXML) рассмотренного проекта, build-файл Ant для генерации WAR, конфигурационные файлы, а также сторонние библиотеки (в виде JAR-файлов), которые были использованы в этой статье.
- Для работы рассмотренного в этой статье приложения требуется СУБД с открытым исходным кодом.
- Java-инструментарий для компоновки проекта.
- Для компиляции исходного Java-кода необходимо использовать набор средств разработки Java SDK (JDK) версии 6.
- Для компиляции исходного кода MXML и ActionScript необходимо использовать набор средств разработки Flex 4 SDK.
- Контейнер сервлетов, разработанный компанией Apache Software Foundation и представляющий собой серверную среду для выполнения Web-приложений Java.
- Инфраструктура Adobe для связывания технологии Flex с платформой Java Platform, Enterprise Edition (Java EE). Это программное обеспечение уже включено в состав загружаемого zip-архива проекта, и его не нужно загружать отдельно.
- Разработанная компанией Red Hat ORM-инфраструктура, предназначенная для поддержки контейнеров Java EE Middleware. Это программное обеспечение уже включено в состав загружаемого zip-архива проекта, и его не нужно загружать отдельно.
-
Оригинал статьи: Create Flex 4 and Java Web applications (EN).
-
Узнайте больше о принципах JPA (EN) на Web-сайте Apache Software Foundation.
-
Научитесь работать с сущностями, прочитав обучающее руководство по Java EE Управление сущностями (EN).
-
Руководство пользователя Hibernate EntityManager (EN) – получите всю необходимую информацию для работы с объектом инфраструктуры Hibernate
EntityManager. -
Понимание компонентов и жизненного цикла инфраструктуры Flex 3 (Джеймс Поланко и Аарон Педерсен, DevelopmentArc) (EN) – узнайте, как повысить эффективность работы с Flex.
-
Обновленные правила "Elastic Racetrack" для Flash 9 и AVM2 (Шон Кристманн) (EN) – узнайте больше о правилах оптимизации фреймов внутри Flash Player.
-
Узнайте больше о явных преобразованиях объектов ActionScript и Java (EN) из руководства Adobe LiveCycle®
Data Services Developer's Guide.
-
Создание декларативного языка описания пользовательского интерфейса на базе XML (Аррон Фергюсон, developerWorks, сентябрь 2009 г.) (EN) – узнайте больше о декларативном описании пользовательских интерфейсов на XML.
-
Создание компонентов Flex (Сандип Малик, developerWorks, июль 2009 г.) (EN) – узнайте о создании новой функциональности Flex с чистого листа.
-
Возможности Flex 4 для создания программного обеспечения как услуги (Дэн Орландо, developerWorks, июль 2009 г.) (EN) – узнайте, как использовать Flex 4, чтобы улучшить взаимодействие пользователей с RIA-приложениями.
Аррон Фергюсон (Arron Ferguson) в течение 12 лет преподавал программирование в технологическом институте Британской Колумбии. Его профессиональные интересы и опыт охватывают такие области, как Java, XML, Web-технологии, анимация (2D и 3D), и создание объектов цифровой мультимедиа. Он также имеет опыт работы независимым техническим редактором и рецензентом, а также является автором книги "Создание систем управления контентом в Java" (Charles River Media, 2006 г.). Наконец, Аррон является горячим сторонником Linux и программного обеспечения с открытым кодом.