`
zhangziyangup
  • 浏览: 1066208 次
文章分类
社区版块
存档分类
最新评论

使用 Alphablox 创建 J2EE 网络聊天室

 
阅读更多

概述

DWE 为企业创建和使用数据仓库提供强大的支持,DB2 Alphablox 是该产品中负责数据分析和展示的关键组件。DB2 Alphablox 不仅提供强大的数据分析功能,还结合当前应用广泛的 J2EE 技术,提供基于 MVC 的应用框架,使得分析功能和企业的其他 J2EE 服务融为一体。在这个框架中,DB2 Alphablox 将网络应用难以处理的很多问题进行封装成易于使用的组件模块,使得开发人员可以很方便的使用。本文以创建一个聊天室网络应用为例子,介绍 DB2 Alphablox 的一些关键技术,包括客户端界面创建,服务器端系统管理以及各种通信技术的融合。

Talkheads 聊天室

进入聊天室,用户将看到如 图 1 的界面:


图 1. Talkheads 聊天室界面
图 1. Talkheads 聊天室界面

用户输入自己的姓名,然后选择要进入聊天室房间。选择时,可以通过“room info”按钮查看某个聊天室的情况,包括多少人在该聊天室,他们的名字是什么等等;通过“enter”进入某个聊天室,在进入某个聊天室时,系统将检查用户所使用的名字是否已经被使用,你不希望同一个聊天室里有两个人用相同的名字,对不对?

当用户成功进入聊天室后,将会进入 图 2 所示的聊天对话框。聊天室中所有人的对话将会显示在靠上的窗口,而用户可以通过靠下的窗口输入语句并发送。


图 2. 聊天对话框界面
图 2. 聊天对话框界面

DB2 Alphablox 应用的组成结构

在具体介绍聊天室应用之前,先简单介绍一下 Alphablox 网络应用的基本结构,主要涉及到三个概念:

  • Blox:组件;
  • Container:容器,本身也是组件;
  • BloxContext:组件上下文,不同于普通的J2EE Context。

Blox

Blox 是 Alphablox 最基本的功能单元,理解 Blox 是使用 Alphablox 创建网络应用的第一步。Alphablox 所提供的整套 Blox 覆盖了创建数据分析应用所需的绝大部分功能,包括数据提取,数据展示,数据操作,以及报表的导出。Alphablox 所提供的参考手册对每个 Blox 的所有功能有非常详细的描述。在这里我们只是概括的讲述 Blox 的共有特性。

通常每个 Blox 由 3 个文件组成,它们是 BloxTag,Blox,Peer。我们用作示例的 Blox 命名为 His,它们之间的关系如 图 3 所示:


图 3. Blox 基本组成结构
图 3. Blox 基本组成结构

其中 BloxTag 是遵守 JSP TAG 标准的一个对象,开发人员可以方便的通过 HisTag 创建一个 HisBlox 的实例,配置该实例的属性,而不必进行 Java 代码的操作。例如如下的代码片断创建一个 HisBlox 的实例,并指定其 name 为 HERO,age 为28:


列表 1. BloxTag 实例

<blox:hisname=”HERO”age=”28”/>

这段代码基本等价于在 JSP 中嵌入以下代码片断:


列表 2. 基本等价的 JSP 片断

<%...
HisBloxhisBlox
=newHisBlox();
hisBlox.setName(“HERO”);
hisBlox.setAge(
28);
%>

之所以说基本等价是因为前者具有更少的代码量,并且当 HisBlox 升级时,使用前者的应用需要更少的改动。

对于复杂的 Blox 而言,Peer 储存每个 Blox 的状态,代理每个 Blox 的行为,还肩负着与别的 Peer 通讯的责任。对于一些只有简单功能的 Blox,比如 ButtonBlox,并不需要这样的分离。这听起来比较复杂,幸运的是开发人员通常不用关心 Peer,它完全由 Blox 的实例进行控制和管理。

每个具有外观的 Blox 还有拥有一个 View 对象,它负责为 Blox 生成一段 HTML 语句,将 Blox 的实例展现在浏览器上,例如一个 ButtonBlox 会转变成如下的 HTML 代码:


列表 3. 为 ButtonBlox 生成的 HTML 代码

<inputtype=”button”class=”color:red”onclick=”…”/>

Alphablox 如何让这些 Blox 为我们工作呢?以一个包含 HisTag 的 JSP 页面为例,当它部署时,Web 服务器会请求 Alphablox 协助进行翻译,从而将 HisBlox 翻译成正确的 Java 语句,并嵌入到生成的 Servlet 文件中。当客户通过浏览器第一次请求该页面时,HisView 将生成的 HTML 片段与 Servlet 输出的其他的 HTML 一起发送到客户浏览器上。之所以强调第一次请求,是因为在该会话以后的访问中,用户对 HisBlox 的请求被封装成 XMLHttpRequest 对象传递到服务器端的 HisBlox 实例,后者处理这个请求,Alphablox 将请求结果封装成一个响应对象,Alphablox 客户端解析这个响应对象,做出相应的动作。

Blox 容器

单个 Blox 所能实现的功能是有限的,通常我们需要多个 Blox 协同工作,即使是一个普通的验证页面,也是由两个 EditBlox(用户名/密码)和一个 ButtonBlox(提交)组成的。为了让多个 Blox 更好的协作,Alphablox 提供了容器的机制。容器具有如下的主要功能:

  • 布局控制:Alphablox 提供网格布局(GridLayout),水平布局(HorizontalLayout)等布局方式,具体使用方法请参考 Alphablox API;
  • 管理对容器内各个 Blox 的访问:Alpahblox 提供了多种方式从容器中获取 Blox,如果你知道控件的具体类型,你可以用 getXXX( blox’s name ) 获取;如果你只知道控件的 ID 或 Name,则可以通过 searchForComponent 和 searchForAllComponents,前者只搜索第一层次,后者搜索所有层次;
  • 借助 Controller 管理 Blox 之间的通讯;当用户操作 Alphablox 的应用时,用户的动作(如点击鼠标、键入信息)和被操作的 Blox 的 ID 一起封装成一个消息发送到 Server 端。在 Server 端,每个 Blox 有自身的事件处理器,Alphablox 按照 Blox 所组成的层次关系,将对应的事件处理器实例组织起来。当事件到来时,Controller 使用如下算法进行处理:
    1. 从容器中找出产生事件的 Blox,命名为 event_src_blox;
    2. event_src_blox 的 controller 是否能处理该事件,能则 goto 步骤 c,否则 goto 步骤 d;
    3. 调用处理函数,看返回值,为 True 则 goto 步骤 e;为 False 则继续;
    4. 如果 event_src_blox 不是顶层容器,event_src_blox 重新赋值为它的父容器, goto 步骤 b;
    5. 退出。

图 4 展示了一个简单容器的示意图:


图 4. Alphablox 容器示意图
图 4. Alphablox 容器示意图

Blox 上下文

现在大家已经看到 Alphablox 网络应用的基本元素和组织方法。众所周知,并行处理多个客户请求是网络应用最重要的特点之一,Alphablox 如何处理并发请求的呢?秘密就是 BloxContext。Alphablox 的并发处理是基于 Session 的,在每个会话被创建时,一个 BloxContext 的实例就会随之创建,同时它会与被访问的应用中的所有 Blox 实例联系起来。如果不考虑有的用户对 Blox 访问权限的不同,每个用户的 BloxContext 在最初分配时都存放相同的 Blox 实例。例如,所有访问我们聊天室对象的 BloxContext 实例都存放了两个 EditBlox 的实例,一个 ButtonBlox 的实例。

运行时,每个用户的操作通常只会影响到自己的那份 Blox 实例,随着时间的推移,每个 BloxContext 的实例就具有了不同的内容。

通过 Controller 和 JSP 的某些特性,我们可以获取服务器端所有会话的 BloxContext 的实例,进而对任意一个 Blox 的实例进行操作,从而实现修改别的会话中的 Blox 实例。这就是 Alphablox 聊天室实现的基础。

聊天室实现

使用 Alphablox 所提供的服务,我们可以轻松采用 MVC 的体系结构:

  • View:提供聊天室信息展示,进入聊天室按钮,聊天对话框的功能;
  • Model:创建并管理各个聊天室,注册用户,注销用户;
  • Controller:接受用户消息,包括发送信息,用户退出等。


图 5. 聊天室体系结构
图 5. 聊天室体系结构

以下 3 个小节详细介绍各层的实现细节。

Model 层

该层提供数据存储的功能,它由一个聊天室工厂和聊天室类组成。他们之间的关系图如 图 6 所示:


图 6. Model 层类图
图 6. Model 层类图

其中 TalkServerFactory 负责 TalkServer 的创建,也是 Model 层提供给 View 层的接口。

属性:public static Map serversMap = new HashMap(31);

用于存放聊天室房间名字与房间对象的映射。


列表 4. 主要方法

publicITalkServergetServerByName(Stringname)...{
ITalkServerts
=(ITalkServer)serversMap.get(name);
if(ts==null)...{
ts
=newTalkServer(name);
serversMap.put(name,ts);
}

returnts;
}

这个方法判断该名字的房间是否已经存在,如果不存在则创建并返回,否则返回对应的房间。

View 实现

该层包括一个 JSP 文件和一个 XML 文件,分别对应 图 1图 2 所示的界面。JSP 页面代码可以划分为以下流程图:


图 7. 聊天室流程控制图
图 7. 聊天室流程控制图

下面分别介绍各个环节的实现方法。首先是聊天室展示,每个聊天室具有以下图示的内容,每个页面可以展示的聊天室个数可以订制。


图 8. 聊天室展示
图 8. 聊天室展示

按钮 GetInfo 用以获取该聊天室的信息,例如多少人在这里,都叫什么名字等等;Enter 用来进入该聊天室。他们的代码都在客户端实现,如下所示:


列表 5. GetInfo 与 Enter 的代码

<scriptlanguage="javascript">
functioncheckName(roomname)...{
varusername=document.getElementById('nameedit').value;
if(username.value==''||roomname=='')...{
alert(
"missusernameorroomname!!");
returnfalse;
}

if(serverFactory.isNameRegistered(username,roomname))...{
alert(
'usernameisinuse!!');
returnfalse;
}

document.forms[
0].submit();
returntrue;
}

functiondisplayInfo(roomName)...{
varstr="themembersinroom"+roomName+"are:";
alert(str
+serverFactory.getMembersFromServer(roomName));
}

</script>

其中用到了 serverFactory.isNameRegistered(username,roomname)。该语句以 usernameroomname 为参数判断在该聊天室中是否已经有人使用该用户名。通过 Alphablox 所提供的 clientBean 服务,我们可以方便在 JavaScript 中调用服务器端 JavaBean 的方法。方法如下:


列表 6. JavaBean 中的方法

<jsp:useBeanid="serverFactory"
class
="cdl.abx.talk.TalkServerFactory"
scope
="session">
</jsp:useBean>
<blox:header>
<blox:clientBeanname="serverFactory">
</blox:clientBean>
</blox:header>

首先我们用 jsp:useBean 创建一个普通的 JavaBean,由 blox:clientBean 为这个 bean 创建了一个 JavaScript 对象,然后我们便可以像操作 JavaScript 对象一样操作这个 JavaBean。人们不禁要问 Alphablox 究竟做了什么,让我们可以如此自由。其实客户端的这个对象只是一个 Proxy,它的方法将参数通过 XMLHttpRequest 传递到服务器端,Alphablox 调用真正的 Java 方法处理,并将结果通过 XMLHttpResponse 发送回来。

当用户点击“进入”按钮,系统以用户名和聊天室名字为参数验证该用户名是否合法,如果合法则成功提交到该页面,从而进入聊天室。然后,系统将为该会话生成一个上下文实例,并将该实例注册到聊天室对象中。最后显示聊天对话框。代码如下所示:


列表 7. 显示聊天对话框的方法

<%...
finalBloxContextcontext
=BloxContextFactory.getBloxContext(request,response);
finalITalkServerserver
=serverFactory.getServerByName(roomname);
server.registerBloxContext(context);
%>
<blox:containerid="talkBlox"width="0"height="0">
<%...
FilectxPath
=newFile(pageContext.getServletContext().getRealPath(""));
StringdialogPath=ctxPath.getAbsolutePath()+File.separator+"talkDialog.xml";
dialog
=Dialog.createFromResource(dialogPath);
%>
</blox:container>
<%...
dialog.setController(
newTalkController(dialog,server,context));
talkBlox.getBloxModel().getDispatcher().showDialog(dialog);
%>

在此需要说明对话框的创建过程。Swing 的图形化界面相比已经为大家所熟悉,其所使用的 MVC 框架为创建更容易维护的界面工程提供坚实的基础。Alphablox 提供类似的框架,所不同的是所封装的对象不是操作系统所提供的图形工具,而是网页上的各种图形。

这里着重讲述对话框的生成和弹出,它主要分为三个步骤:

  1. 生成 Dialog 的实例;
  2. 创建 TalkController 的实例,并用它设置为 Dialog 的控制器;
  3. 显示这个 Dialog。

其中步骤 1 使用从指定路径的资源文件生成一个对话框,这也是 Alphablox 为方便编程人员使用的封装。该资源文件如下所示:


列表 8. 对话框的资源文件

<?xmlversion="1.0"encoding="UTF-8"?>
<Dialogname="talkDialog"title="talkDialog"cache="false"
modal
="true"alignment="left"layout="vertical">
<Statictitle="wordsrecordwindow:"/>
<Editname="allWords"charactersPerLine="40"lines="10"/>
<Spacerheight="20"/>
<Statictitle="newwordswindow:"/>
<ComponentContainerlayout="horizontal"alignment="left">
<Editname="newWords"charactersPerLine="35"lines="2"/>
<Buttonname="sendWords"title="send"/>
</ComponentContainer>
<Spacer/>
</Dialog>

文件中描述了对话框中各个部件的类型名字,尺寸,布局方法。Alphablox 对它进行解析,生成一个对话框。请注意生成对话框实例的代码被 <blox:container> 所包围,这样做能够保证这段代码只在页面第一次加载的时候执行,从而减少 IO 的时间开销。

Controller 层

最后到达控制层。在视图层中,我们已经看到控制器如何被实例化,以及如何被设置到 Dialog 上,在这里详细描述控制器的实现。该层只有一个类,负责用户操作的响应,它的类图如下。


图 9. Controller 层类图
图 9. Controller 层类图

每个客户都会有一个对话框。Alphablox 所提供的事件分发机制保证 Dialog 上每个控件所产生的事件都会触发自己所对应的方法。例如,某个对话框关闭,将会导致自己的 Controller 的如下方法被调用:


列表 9. 对话框关闭的代码

publicbooleanhandleClosedEvent(ClosedEventevt)...{
Componentcomp
=evt.getComponent();
server.unregisterBloxContext(ctx);
returnfalse;
}

如果用户点击发送按钮,将会导致如下方法被调用:


列表 9. 对话框关闭的代码

publicvoidactionSendWords()throwsException...{
sendWords();
}

为了方便编程,Alphablox 的应用遵循一种模式,即 actionXXX 是表示响应 XXX 组件的单击事件。

最后是整个聊天室的核心代码:


列表 10. 聊天室核心代码

privatevoidsendWords()throwsException...{
Stringstr
=server.getUserName(ctx);
Stringwords
=newWords.getValue();
StringBuffersbtmp
=newStringBuffer(256);
sbtmp.append(str
+"["+newjava.util.Date().toString()+"]: ");
sbtmp.append(words);
sbtmp.append(
" ");
sb.insert(
0,sbtmp.toString());

Iteratoriter
=server.getAllContext();
while(iter.hasNext())...{
BloxContextctx
=(BloxContext)iter.next();
ContainerBloxcontainerBlox
=(ContainerBlox)ctx.getBlox("talkBlox");
if(containerBlox!=null)...{
try...{
Dialogdialog
=
containerBlox.getBloxModel().findDialog(TalkController.dialogName);
EditallWords
=dialog.getEdit("allWords");
allWords.setValue(sb.toString());
allWords.changed();
}
catch(Exceptionex)...{
ex.printStackTrace();
}

}

}

newWords.clear();
newWords.changed();
}

在这里,我们利用 JavaBean 的静态变量保存所有的 Blox 上下文,分别从 Blox 上下文中获得聊天对话框,再从聊天对话框中查找到聊天记录窗口,修改内容,将其状态设置为“已改变”。最后 Alphablox 在下次更新客户端时便会将此更新一起完成。

小结

本文讲述了一个简单的网络聊天室。在构造的过程中,我们利用 Alphablox 所提供的架构和服务极大简化了系统的构造。

下载

描述 名字 大小 下载方法 实例代码
dm-0612hujh.zip 21KB HTTP
关于下载方法的信息


参考资料

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics