跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

创建 Flex 4 和 Java Web 应用程序

发现对象远程调用

Arron Ferguson, 大学讲师, IBM  
Arron Ferguson 的照片
Arron Ferguson 担任了 12 年大学讲师,在 British Columbia Institute of Technology 讲授软件工程。他的经验和兴趣包括 Java 技术、XML、Web 技术、2D 和 3D 动画、数字媒体创作。他还是一位自由技术编辑和评论家,出版了一本图书:Creating Content Management Systems in Java(Charles River Media,2006 年)。Arron 还热衷于支持 Linux 和其他开源技术。

简介: Rich Internet Applications (RIAs) 经常使用不同的捆绑技术。选择正确的技术组合可以加速开发时间,为用户提供完整、丰富的 Internet 体验。探究如何使用服务器端的 Java™ EE 平台、客户端的 Adobe® Flex™ 平台,以及实现永久存储的 MySQL® 数据库服务器。

发布日期: 2010 年 11 月 22 日
级别: 中级 原创语言: 英文
访问情况 : 9966 次浏览
评论: 


当前对 Web 技术的要求在不断增加。它们必须能够管理用户帐户、上传内容和流媒体格式。这个要求需要 RIA 开发人员探寻这样的技术,即能精简开发流程同时提供广受追捧的功能。开发人员面对的难题就是,如何选择合适的技术集合来提供这些服务。

常用缩略词

  • AMF:动作消息格式
  • API:应用程序编程接口
  • CSS:层叠样式表
  • GUI:图形用户界面
  • HTTP:超文本传输协议
  • JAR: Java 档案文件
  • POJO:简单 Java 对象
  • RIA:富互联网应用程序
  • RPC:远程过程调用
  • SDK:软件开发工具包
  • SQL:结构化查询语言
  • UI:用户界面
  • WAR:Web 档案
  • XML:可扩展标记语言

Adobe Flex 是一个客户端技术,它为开发人员提供丰富的 API 集合来创建 GUI、绘制图形、播放和流放媒体、连接到 Web 服务。在服务器端,Java 技术提供的功能包括关系型数据库管理系统(RDBM)的连接、服务请求的多线程处理以及随需求增加而进行的最佳伸缩。将这两种技术结合使用可提供一个满足 RIA 应用程序需求的强大的技术堆栈。

本文展示如何编写一个简单而强大的 RIA,能使用客户端的 Flex、服务器端 Java 技术以及后端数据库的 MySQL。

样例应用程序

样例应用程序(来自下面的 下载 部分)提供一个丰富的 UI,支持通过 Adobe Flash® (SWF) 应用程序创建、读取、更新和删除(CRUD) 联系信息。这个三层的 Web 架构如 图 1 所示,其中客户端由嵌入在一个 Web 页面中的 SWF 文件表示,服务器应用程序在一个 Java servlet 容器(本例中为 Apache Tomcat)内运行,且数据库是 MySQL。这三层共同创建一个功能分布式应用程序。


图 1. Contacts 应用程序
该图显示上面描述的功能分布式应用程序

对于 Flash 应用程序与 Java servlet 容器之间的通信,Adobe BlazeDS 框架提供对象远程调用 — 即一种允许 Adobe ActionScript™ 对象与 Java 对象相互调用的 PRC 形式。Java 服务器应用程序与关系数据库之间的通信由 Hibernate Object Relational Mapping (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)
+ String toString()

注释业务对象

Java Contact 类被看作是一个充当业务对象的 POJO(简单 Java 对象),这意味着它代表业务领域特征和行为。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将属性标记为数据库内的一个列,可含有列名,不管它是否唯一且是否可为空
  • @Entity将类作为一个实体 bean 声明,表明它是一个要留存的 POJO
  • @GeneratedValue指定生成主键的策略;包括 AUTOIDENTITYSEQUENCETABLE
  • @Id指明属性为每个 Java 对象的唯一标识符(即主键)
  • @NamedQueries列出一组命名查询
  • @NamedQuery将预定义查询声明为一个字符串常量,以供执行时引用。
  • @Table将 Java 类指定为数据库内的一个表

每次需要留存一个内存中的 Java 对象时,Hibernate 将任何 Java 对象的状态信息转换为一个 SQL 更新。同样地,带结果集的 SQL 语句用于填充 Java 对象。因此,可将所有对象保存为数据库内的记录,且可检索所有记录并将其转换回 Java 对象。

注释告知 Hibernate 一个类中的哪些内容可以考虑留存。但它们只是类的一部分。

业务服务:数据库连接

执行 ORM 时需要有一个服务类来执行对 Hibernate 的调用。清单 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 中,缓存的既定术语是持久化上下文(persistence context),且它由 EntityManager 类表示。每个持久化上下文管理一组实体,这些实体是标有 @Entity 注释的 Java 对象。EntityManagerFactory 类表示一个 持久化单元(persistence unit),它负责配置到数据存储(例如,关系数据库)的连接、管理实体类型(即给定上下文内需要映射到数据存储的所有类),并最后提供持久化上下文的实例(即一个 EntityManager)。

试用 DB2 Express 9 数据库服务器免费版

DB2 Express-C 被设计为可在几分钟内启动并运行,它易于使用和嵌入,包含自管理功能,且嵌入了 DB2 for Linux®,UNIX® and Windows® 的所有核心功能,比如 pureXML™。DB2 Express-C 像其他 DB2 Express 版本一样提供相同的核心数据服务器基础功能,且提供一个坚实的基础来构建和部署使用 C/C++、Java、.NET®、PHP、Ruby on Rails、Python 和其他编程语言开发的应用程序。

尽管创建一个持久化上下文的过程很省时,但创建一个持久化单元的过程却很费时。建立到数据存储的连接、查找标注为实体的所有类、配置持久化逻辑以将这些类绑定到数据存储中的实体,整个过程不可能快速完成。因此,您需要在应用程序启动时创建一个 EntityManagerFactory 实例。对于持久化上下文,要务必确保在销毁掉一个 EntityManager 之后再创建另一个。另一个要遵循的重要规则就是 entitymanager-per-request 模式。该模式将数据库调用(例如,请求和更新)组合起来,这样就可以将它们一次性发送出去。这样做可以确保充分利用 JPA 的缓存机制。

下一个需求就是客户端。


应用程序:客户端层

Flex 框架允许您创建可在 Adobe Flash Player 中播放的应用程序。Flex 包括:

  • 称为 MXML 的一个声明性 XML UI 语言
  • ActionScript 编程语言
  • 用于创建 UI、Web 连接和许多其他特性的运行时库
  • 用于将应用程序编译为 SWF 文件的开发工具

本文引用的客户端应用程序使用 Flex 第 4 版。在探讨客户端应用程序之前,要了解如何创建 Flex 应用程序,以及它们如何在 Flash Player 中作为可执行程序存在,这很重要。

首先,您可以使用 MXML 标记和 ActionScript 代码创建应用程序。常用的工作流是使用 MXML 格式创建 GUI 的主要部分(呈现),然后使用 ActionScript 代码执行事件处理和业务逻辑。由于 MXML 和 ActionScript 都是基于文本的,创建 Flash 应用程序只需要一个标准文本编辑器和 Flex SDK。

其次,编写完 Flex 应用程序之后,使用 MXML 编译器编译代码。然后 MXML 编译器创建可在 Web 浏览器内运行(通过 Flash Player 浏览器插件)的 SWF 文件。

最后,Flash 应用程序在使用时间轴范例的 ActionScript Virtual Machine 2 (AVM2) 中运行。该范例将执行动作分成帧 — 就像电影一样。您在编译时指定 Flash 应用程序中的每秒帧数。此外,Flash Player 将执行动作分成以下已排序的任务:

  • Flash Player 事件,比如计时器和鼠标事件
  • 用户代码
  • 预渲染逻辑,其中 Flash Player 试图确定是否因数据值变更而更新 GUI
  • 与数据值变更相关的用户代码
  • Flash Player 渲染

如果要渲染的每秒帧数很少,那么就可以执行大部分用户代码。但是,如果帧频很高(例如,每秒 60 帧),Flash Player 就不太可能执行多数用户代码,因为用户代码执行的时间可能比给定时间更长。在为 Flash Player 编写代码时,记住这一点很重要。

MXML

MXML 是一个强大的声明性 XML 格式,有助于:

  • 因 XML 格式的声明性质而最大限度地降低构建 GUI 所需的代码量
  • 通过明确分离表示逻辑和交互逻辑降低 GUI 代码的复杂度
  • 在进行软件开发时推进设计模式的使用

清单 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 属性定义 UI 组件的本地样式。样式设计通过使用本地样式定义(见 清单 3)、对外部样式表的引用、组件内的内联样式以及 ActionScript 中的 setStyle 方法完成。
  • RemoteObject 类表示与服务器执行远程操作的一个 HTTP 服务对象。
  • mx:Script 元素包括 CDATA 区域中的 ActionScript 代码块。
  • 有一个布局(即 VBox 类)。
  • 每次在应用程序中声明一个 UI 组件(例如,TextArea)时,就产生一个实例变量,稍后可使用组件的 id 属性在应用程序内引用该变量。
  • 数据绑定通过大括号执行(例如, 将 TextArea 元素的 text 属性绑定到 ActionScript message 实例变量)。

ActionScript

MXML 定义 GUI,而 ActionScript 提供用于处理事件、绑定数据(通过 [Bindable] 元数据标记)的行为,以及调用远程服务的能力。在 清单 3 中,createContacteditContactdeleteContactgetAllContacts 方法都在服务器端调用远程方法。调用远程方法时,ActionScript 就有机会通过声明回调函数处理结果和任何错误了。在 清单 3 中,handleResult 函数将结果作为一个 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 配置 Hibernate,如 清单 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 文件必须位于 Web 应用程序的 WEB-INF/classes/META-INF 文件夹中,Hibernate 才能读取到它。具备了这个条件之后,Hibernate 需要以下信息:

  • 数据库方言(即它与哪个数据库对话,因为很多数据库都有略微不同的 SQL 方言)
  • 经由默认架构的表空间
  • 用于连接数据库的数据库驱动器
  • 数据库 URL
  • 自动检测功能应检测什么(例如,注释类、Hibernate 映射 XML 文件等)
  • 用户名和密码

其他信息也有助于提高 Hibernate 的性能,但不是必需的。

配置 BlazeDS

BlazeDS 有 4 个配置文件:

  • 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 协议。轮询 是指客户端持续与服务器通信,以确保连接始终成立 — 不过在本应用程序中不需要。

加入 My developerWorks 上的 Web 开发小组

My developerWorks Web 开发小组 中与其他开发人员讨论有关 Web 开发的主题并共享相关资源。

不是 My developerWorks 成员?立即加入!

通道端点指定服务器 URL。该端点是编译项目所必需的;客户端 Flash 应用程序将其作为一个硬编码值使用,因此它知道要连接到哪个服务器上。您实际上可以在 MXML 或 ActionScript 中定义端点 URL。

最后,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>


结束语

本文向您展示了如何编写一个运行在 Tomcat 内,并响应联系信息请求的 Java 服务器端 Web 应用程序。您学习了如何同时使用 MXML 和 ActionScript 编写一个 Flex 应用程序,以创建一个客户端 Flash 应用程序。MySQL 充当数据存储,而 Hibernate — 一个 ORM 框架 — 用于将 Java 对象转换成能查询和更新 MySQL 数据库的 SQL 语句。最后,BlazeDS 框架允许 Flash 应用程序进行远程过程调用并在 Java 服务器端 Web 应用程序执行远程调用。



下载

名字大小下载方法
JEE-BlazeDS-Flex-contacts.zip7MBHTTP

关于下载方法的信息

更多下载

注意:

  1. 这个压缩文件包含该项目中所有的源代码(Java、ActionScript 3 和 MXML)、用于生成 WAR 的 Ant 构建文件、配置文件和本文引用和使用的第三方库(JAR 文件格式)。
  2. 一个必需的开源 RDBMS,用于在本文的示例项目中使用
  3. 用于构建示例项目的一个基于 Java 的构建工具
  4. Java SDK (JDK) 版本 6,用于在示例项目内编译 Java 源代码
  5. Flex 4 SDK,用于在示例项目内编译 MXML 和 ActionScript 源代码
  6. Apache Software Foundation servlet 容器,提供运行示例项目的 Java HTTP Web 服务器环境
  7. 用于将 Flex 技术连接到 Java Platform, Enterprise Edition (Java EE) 的 Adobe 框架。该软件仅供参考,因为它已经包含在了本文的项目下载中。
  8. Java EE 容器中间件的 Red Hat ORM 框架。该软件仅供参考,因为它已经包含在了本文的项目下载中。

参考资料

学习

获得产品和技术

  • 以最适合您的方式 评估 IBM 产品:下载产品试用版,在线试用产品,在云环境下试用产品,或者在 SOA Sandbox 中花费几个小时来学习如何高效实现 Service Oriented Architecture。

讨论

关于作者

Arron Ferguson 的照片

Arron Ferguson 担任了 12 年大学讲师,在 British Columbia Institute of Technology 讲授软件工程。他的经验和兴趣包括 Java 技术、XML、Web 技术、2D 和 3D 动画、数字媒体创作。他还是一位自由技术编辑和评论家,出版了一本图书:Creating Content Management Systems in Java(Charles River Media,2006 年)。Arron 还热衷于支持 Linux 和其他开源技术。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, Java technology, Open source
ArticleID=588173
ArticleTitle=创建 Flex 4 和 Java Web 应用程序
publish-date=11222010
author1-email=arron_ferguson@bcit.ca
author1-email-cc=

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。