在本系列的第1部分中,您学习了如何在Asynchronous JavaScript and XML(Ajax)和Java Platform, Enterprise Edition(Java EE)应用程序中使用javax.script API。本文将展示如何为同时在服务器和客户机上使用JavaScript的Web 应用程序实现远程过程调用(Remote Procedure Call,RPC)机制。您还将学习一些有趣的技巧,例如用JavaScript实现Java接口、构建XMLHttpRequest包装器、使Ajax调试更加容易以及使用JSP 标记文件生成JavaScript代码。
RPC机制非常简单。服务器上有一组 JavaScript函数,现在希望能从Web浏览器调用它们,就像有一个JavaScript引擎在同时执行客户机代码和服务器代码一样。因此,需要有一些客户端例程,这些例程应该与服务器端的对应例程有相同的名称和参数。
客户端例程将使用Ajax 把它们的参数传递到服务器,在服务器上进行真正的处理。一个Java servlet 将调用服务器端函数,并使用JSON格式将结果返回到客户机。然后,客户端例程计算 Ajax 响应,将JSON 字符串转换回JavaScript对象,后者被返回到应用程序。
作为应用程序开发人员,可以将精力放在构建用户界面和服务器中执行的函数上。您不需要处理Ajax或RPC 问题,因为本文以标记文件的形式提供了一个JavaScript代码生成器,您可以在JSP页面使用它来自动生成客户端例程。为了理解其中的工作原理,我们从一个示例应用程序开始。
开发一个JVM 监视应用程序
本文中的示例应用程序使用Java Management API 监视运行托管应用程序的Java EE 服务器的JVM。用户界面由一个简单的Web页面组成,该页面显示各种不同的指示器,例如 Java类的数量、内存消耗、垃圾收集器的活动和线程的数量。
这些信息通过Ajax获得,并插入到一个HTML表中(如图 1 所示;单击 这里 查看图 1的放大图)。更有趣的是,这个Web页面包含一个表单,通过该表单可以为给定的秒数分配内存。还可以调用JVM的垃圾收集器(GC)。
图 1. 示例应用程序
在服务器端,应用程序使用一个JavaScript文件,Web浏览器将借助 Ajax 并使用本系列第1部分提供的脚本运行器调用该文件中的函数。这是一个简单的servlet,它处理URL 以.jss 扩展名结束的所有请求。该 servlet 查找服务器上相应的JavaScript文件,并使用Java Scripting API执行它。
创建Web页面
清单 1 显示MonitorPage.jsp文件中的表和表单。每个数据单元有一个ID,以便用JavaScript 更新表中的内容。<body> 标记的onload 属性用于调用一个名为 init()的JavaScript函数,该函数将初始化应用程序的客户端部分。另外两个函数 allocMem()和gc() 是在用户单击按钮时调用的。
清单 1. MonitorPage.jsp的HTML代码
<html>
<head>
...
<style type="text/css">
th { text-align: left; }
td { text-align: right; }
.space { margin: 10px; }
</style>
</head>
<body onload="init()">
<table border="1" cellpadding="5">
<tr>
<th colspan=2>Classes</th>
<th colspan=2>Heap Memory</th>
<th colspan=2>Non-Heap Memory</th>
<th colspan=2>Garbage Collector</th>
<th colspan=2>Threads</th>
</tr>
<tr>
<th>Loaded</th>
<td id="info.classes.loaded"></td>
<th>Used</th>
<td id="info.memory.heap.used"></td>
<th>Used</th>
<td id="info.memory.nonHeap.used"></td>
<th>Count</th>
<td id="info.gc.count"></td>
<th>Live</th>
<td id="info.threads.live"></td>
</tr>
<tr>
<th>Unloaded</th>
<td id="info.classes.unloaded"></td>
<th>Committed</th>
<td id="info.memory.heap.committed"></td>
<th>Committed</th>
<td id="info.memory.nonHeap.committed"></td>
<th>Time</th>
<td id="info.gc.time"></td>
<th>Peak</th>
<td id="info.threads.peak"></td>
</tr>
</table>
<br>
<form name="monitorForm">
Size: <input name="size" size="10">
<span class="space"></span>
Seconds: <input name="seconds" size="4">
<span class="space"></span>
<button type="button"
onclick="allocMem(this.form.size.value, this.form.seconds.value)"
>Allocate Memory</button>
<span class="space"></span>
<button type="button" onclick="gc()">Collect Garbage</button>
</form>
</body>
</html>
MonitorPage.jsp文件(见清单 2)使用一个名为 <js:rpc>的定制标记来生成客户端 JavaScript函数,这些函数调用服务器端对应的函数。<js:rpc> 标记有以下属性:
script | 将在服务器上执行的脚本的URL |
function | 被远程调用的JavaScript函数的签名 |
validator | 一个可选表达式,在Web浏览器中将计算该表达式以验证函数的参数 |
jsonVar | 一个可选 JavaScript 变量的名称,该变量用于存储 JSON 响应 |
method | HTTP方法,可以是 GET或POST |
async | 表明应该异步还是同步使用XMLHttpRequest的一个布尔属性 |