Pushlet的基本使用形式是极为简单的。后面的一些示例会说明这一点。
Pushlet基于HTTP流,这种技术常常用在多媒体视频、通讯应用中,比如QuickTime。与装载HTTP页面之后马上关闭HTTP连接的做法相反,Pushlet采用HTTP流方式将新变动的数据主动地推送到client(
客户端),再此期间HTTP连接一直保持打开。有关如何在Java中实现这种Keep-alive的
长连接请参看Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1规范》。
示例1
我们利用HTTP流开发一个JSP页面(因为它易于部署,而且它在web server中也是作为servlet对待的),此页面在一个
定时器循环中不断地发送新的HTML内容给client:
<%
int i = 1
try { while (true) { out.print("<h1>"+(i++)+"</h1>")
out.flush()
try { Thread.sleep(3000)
} catch (InterruptedException e) { out.print("<h1>"+e+"</h1>")
} } } catch (Exception e) { out.print("<h1>"+e+"</h1>")
}%>
在Pushlet
源代码中提供了此页面(examples/basics/push-html-stream.jsp)。上面的页面并不是十分有用,因为在我们刷新页面时,新内容机械地、持续不断地被添加到页面中,而不是server端更新的内容。
示例2
现在让我们步入Pushlet工作机理中一探究竟。通过运行Pushlet的示例
源代码(examples/basics/ push-js-stream.html),我们会看到这个每3秒刷新一次的页面。那么它是如何实现的呢?
此示例中包含了三个文件:push-js-stream.html、push-js-stream-pusher.jsp、push-js-stream-display.html。
其中push-js-stream.html是主
框架文件,它以HTML Frame的形式包含其它两个页面。
push-js-stream-pusher.jsp是一个JSP,它执行在server端,此文件内容如下:
7: <%
8: /** Start a line of JavaScript with a function call to parent frame. */
9: String jsFunPre = "<script language=JavaScript >parent.push('";
10:
11: /** End the line of JavaScript */
12: String jsFunPost = "')</script> ";
13:
14: int i = 1;
15: try {
16:
17: // Every three seconds a line of JavaScript is pushed to the client
18: while (true) {
19:
20: // Push a line of JavaScript to the client
21: out.print(jsFunPre+"Page "+(i++)+jsFunPost);
22: out.flush();
23:
24: // Sleep three secs
25: try {
26: Thread.sleep(3000);
27: } catch (InterruptedException e) {
28: // Let client display exception
29: out.print(jsFunPre+"InterruptedException: "+e+jsFunPost);
30: }
31: }
32: } catch (Exception e) {
33: // Let client display exception
34: out.print(jsFunPre+"Exception: "+e+jsFunPost);
35: }
36: %>
注意在示例1和示例2中使用JSP时都存在一个问题:一些servlet引擎在某个client离开时会“吃掉”IOException,以至于JSP页面将永不抛出此异常。所以在这种情况下,页面循环将会永远执行下去。而这正是Pushlet实现采用servlet的原因之一:可以捕获到IOException。
在上面代码的第21行中可以看到在一个
定时器循环(3秒/周期)中打印了一些HTML并将它们输出到client浏览器。请注意,这里推送的并非HTML而是Javascript!这样做的意义何在?它把类似“parent.push('Page 4')”的一行代码推送到
浏览器;而具有JavaScript引擎的浏览器可以直接执行收到的每一行代码,并调用parent.push()函数。而代码中的Parent便是
浏览器页面中所在Frame的Parent,也就是push-js-stream.html。让我们看看都发生了什么?
<script LANGUAGE="JavaScript">
var pageStart="<HTML><HEAD></HEAD><BODY BGCOLOR=blue TEXT=white><H2>Server pushes: <para>";
var pageEnd="</H2></BODY></HTML>";
// Callback function with message from server.
// This function is called from within the hidden JSP pushlet frame
function push(content) {
// Refresh the display frame with the content received
window.frames['displayFrame'].document.writeln(pageStart+content+pageEnd);
window.frames['displayFrame'].document.close();
}</script>
<!-- frame to display the content pushed by the pushlet -->
<!-- Hidden frame with the pushlet that pushes lines of JavaScript-->
</FRAMESET>
可以看到push-js-stream.html中的push()函数被名为pushletFrame的JSP Frame调用:把传入的参数值写入到displayFrame(此Frame为push-js-stream-display.html)。这是动态HTML的一个小技巧:使用
document对象的writeln方法刷新某个Frame或者Window的内容。
于是displayFrame成为了用于显示内容的、真正的视图。displayFrame初始化为黑色背景并显示“wait…”直到来自server的内容被推送过来:
WAIT...
这便是Pushlet的基本做法:我们从servlet(或者从示例中的JSP)把JavaScript代码作为HTTP流推送到
浏览器。这些代码被
浏览器的JavaScript引擎解释并完成一些有趣的工作。于是便轻松地完成了从server端的Java到
浏览器中的JavaScript的回调。
上面的示例展示了Pushlet原理,但这里存在一些等待解决的问题和需要增添的特性。于是我建立了一个小型的server端Pushlet框架(其类结构图表将会展示在下面),添加了一些用在client中的JavaScript库。由于client需要依赖更多的DHTML特性(比如Layers),我们将首先粗略地温习一些DHTML知识。示例代码见examples/dhtml。
DHTML(动态HTML)
DHTML(动态HTML)提供了在
浏览器中维护内容、进行用户交互的扩展能力。就像Java开发者使用servlet和JSP那样,DHTML也应该是你的
工具箱中的一部分。
DHTML涉及到HTML、
级联样式表(CSS)、JavaScript和DOM。传统的页面只能通过重新装载来自server新页面的方式进行更新。DHTML提供了在页面被装载完毕后对
浏览器内的HTML文档的完全控制。你应该见过一些带有“图像翻滚”、弹出内容、可收缩菜单功能的web页面,它们便是使用DHTML技术实现的。尽管存在一些标准上的差异(见下面的“跨
浏览器DHTML”),多数兼容JavaScript1.4版本的浏览器(后面将简称为“版本4的浏览器”)都支持DHTML。
从开发者的角度审视
浏览器中的整个文档,比如Frame、图片、表格等,它们都可以表示为具有层次的对象模式――DOM。通过使用JavaScript可以维护DOM的成员,不但可以改变文档的内容和外观,而且还可以捕捉例如鼠标移动、form提交这些用户事件,而后对DOM进行相应修改。例如鼠标移动到图片的上方可以产生“mouse-over”事件,这时通过显示高亮版本的图片或者弹出解释性文字的方式修改页面外观。这听起来不错吧!我们现在就熟悉一下DHTML标准!但是谁定义了DHTML标准?
这是一些DHTML初学者首先遇到的问题。首先,你需要一个版本4以上的
浏览器。DHTML相关规范的官方标准出自World Wide Web Consortium (W3)。但是
微软和Netscape出品的版本4以上的
浏览器都有一些私有的DHTML扩展,这是你必须注意的。
幸运的是大多数用户都有版本4以上的
浏览器,而且一些开发者(Dannymen、Dan Steinman和Danny Goodman)建造了跨越浏览器的、可重用的DHTML库。
作为一名Java开发者,你要接受这个事实:你应该适当地明白基于对象、甚至
面向对象的JavaScript编程。在我的DHTML中你将找到一些示例,但了解更多的DHTML资源也是很值得的。尤其在使用跨越
浏览器的DHTML库对付那些顽固的浏览器问题时,一切都变得有趣、而不是枯燥。
就如Java获得在广阔的server端市场、DHTML在client领域具有许多强大特性那样,Pushlet以一种直接的方式将这两项伟大的技术捆绑在一起。下一个章节将详细讨论Pushlet这个server端
轻量级框架和client端DHTML库。