代码改变世界

AJAX构建应用程序

2006-03-22 16:23  Jeff  阅读(347)  评论(2编辑  收藏  举报

IBM develope上提供了一个AJAX实现应用程序,整理一下.

AJAX 支持动态、异步的 Web 体验,不需要页面刷新。它集成了以下技术:

  • XHTML CSS 提供了基于标准的表示。
  • 文档对象模型(DOM)提供了动态显示和交互。
  • XML XSLT 提供了数据交换和操纵。
  • XMLHttpRequest 提供了异步数据检索。
  • JavaScript 把每一样东西绑定在一起。

   使用 XMLHttpRequest,可以用 JavaScript 发出到服务器的请求,并在不阻塞用户的情况下处理响应。在创建 Web 站点并用 XMLHttpRequest 在客户机浏览器上无刷新地执行屏幕更新的同时,它还提供了更多灵活性和丰富的用户体验。
   下面介绍一个例子。运行需要tomcat作为服务器,这里是代码的下载:/Files/JeffChen/ajax.rar(汗,不支持.war格式的文件,把源码压缩成RAR了,下载下来解压后放到tomcat web程序部署目录就可以)。我已经测试过了。下面是源码的具体解释,适合新手入门.
    

 

    应用程序是一个使用 Java 服务器页面(JSP)技术开发的单一 Web 页面。用户可以用 Web 浏览器调用 Web 页面并输入应用程序要实时验证的订购 ID。在 ID 异步验证的时候,用户可以输入更多信息。用户可以根据作者 出版者 查看图书的书名。屏幕会根据用户的选择填充作者列表 出版者列表。根据选择,书名列表 会被填充。所有这些列表都是实时填充的 —— 换句话说,页面没有刷新,但是数据仍然来自后台层。我们把这种现象叫做实时刷新
   
上图可以看出,XMLHttpRequest JavaScript 对象帮助进行实时异步处理。该对象采用 XML 格式通过 HTTP 对位于 Web 容器内的 LibraryServlet 发出请求。然后 servlet 查询数据库、提取数据并发送回客户机,还是采用 XML 格式通过 HTTP 进行传送。请求和响应都是在没有刷新页面的情况下实时发生的。

   我们研究示例图书订购应用程序的代码,并进一步查看每个基于 AJAX Javascript 组件:

  • 验证订购 ID
  • 查看作者
  • 查看出版者
  • 查看书名

先从验证订购 ID 的函数 <input type="text" name="subscriptionID" onblur="validate(this.form)"/> 开始。这个代码生成文本字段,用户可以在里面输入订购 ID。用户输入 ID 并移到表单的下一个字段时,触发 onBlur 事件。这个事件调用 JavaScript 函数 validate()

var req;
function validate(formObj) {
    init();
    req.onreadystatechange 
= subscriptionValidator;
    req.send(
"subscriptionID=" + formObj.subscriptionID.value);
}

validate() 函数接受 formObj 作为参数。它首先调用 init() 函数:

function init() {
    
if (window.XMLHttpRequest) {
        req 
= new XMLHttpRequest();
    }
 else if (window.ActiveXObject) {
        req 
= new ActiveXObject("Microsoft.XMLHTTP");
    }

    
var url = "/Library/LibraryServlet";
    req.open(
"POST", url, true);
    req.setRequestHeader(
"Content-Type""application/x-www-form-urlencoded");
}

查看代码: init()

现在看 init() 函数的工作(我们把代码分成几部分):

if (window.XMLHttpRequest) {
    req 
= new
 XMLHttpRequest();
}
 else if (window.ActiveXObject) {
    req 
= new ActiveXObject("Microsoft.XMLHTTP"
);
}

init() 函数首先创建 XMLHttpRequest 对象。这个请求对象是 AJAX 的核心。它以 XML 格式发送和接收请求。这段代码检查浏览器对 XMLHttpRequest 对象的支持(多数浏览器都支持它)。如果使用 Microsoft Internet Explorer 5.0 以上版本,那么就执行第二个条件。

req.open("POST", url, true);
req.setRequestHeader(
"Content-Type""application/x-www-form-urlencoded");

代码创建了 XMLHttpRequest 对象之后,需要设置某些请求属性。在前面的代码中,第一行设置请求方法、请求 URL 和请求的类型(是否异步)。它通过调用 XMLHttpRequest 对象上的 open() 方法做这件事。

这里我们要使用 POST 方法。理想情况下,当需要在服务器上修改状态时,请使用 POST。我们的应用程序并不修改状态,但我们仍然倾向于使用 POSTurl 是要执行的 servlet URLtrue 表明我们要异步地执行请求。

对于 POST 方法,我们需要设置 Content-Type 这个请求头。对于 GET 方法来说不需要这个设置。


function validate(formObj) {
    init();
    req.onreadystatechange 
= subscriptionValidator;
    req.send(
"subscriptionID=" + formObj.subscriptionID.value);
}

查看代码:回调句柄 1

继续查看验证方法,下面把 subscriptionValidator 回调句柄分配给 onreadystatechange,请求状态的每个变化都会触发它。

这个回调句柄 都负责什么呢?因为正在异步地处理请求,所以需要一个回调句俩,从服务器返回完整响应的时候调用它 —— 回调句柄是对订购 ID 进行验证的地方(也就是编写实际的验证代码的地方)。

句柄充当侦听器。它一直等待响应完成。为了发送请求,最后一行调用了 send() 方法。请求以名称= 对的形式发送。对于 GET 方法,请求作为 URL 的一部分发送,所以 send() 方法被传递了一个空参数。

请求被发送到 servletservlet 处理请求并实时地发回响应。这就是 servlet 处理请求的方式。下一个代码段表示了 LibraryServlet doPost() 方法。


public 
void doPost(HttpServletRequest req, HttpServletResponse resp) throws 
ServletException, IOException 
{
    String ID 
= null;
    ID 
= req.getParameter("subscriptionID");
    
if (ID != null{
        String status 
= "<message>" + this.validID(ID) + "</message>";
    
this.writeResponse(resp, status);
    }

}

查看代码:回调句柄 2

doPost() 方法从请求参数得到 subscriptionID。为了验证 ID,它调用 validID() 方法。这个方法验证 ID,如果 ID 正确,则返回 true,否则返回 false。它用 XML 格式构造返回状态,并调用 writeResponse() 方法来写响应。现在来看 writeResponse() 方法。

public void writeResponse(HttpServletResponse resp, String output) throws IOException {
    resp.setContentType(
"text/xml");
    resp.setHeader(
"Cache-Control""no-cache");
    resp.getWriter().write(output);
}

响应用 XML 格式发送。第一行设置响应的内容类型为 text/xml。第二行把头 Cache-Control 的值设为 no-cache。这个值是必需的。AJAX 要求响应的输出不能被浏览器缓存。最后一行调用 getWriter().write() 方法来写响应。

查看代码:回调句柄 3

请求由 servlet 处理,响应被发送回客户机。请记住,所有这些都在后台发生,没有页面刷新。现在 前面 讨论过的回调句柄方法会处理并解析响应:

function subscriptionValidator() {
    
if (req.readystate == 4{
    
if (req.status == 200{
        
var messageObj = req.responseXML.getElementsByTagName("message")[0];
        
var message = messageObj.childNodes[0].nodeValue;
        
if (message == "true"{
        msg.innerHTML 
= "Subscription is valid";
        document.forms[
0].order.disabled = false;
        }
 else {
        msg.innerHTML 
= "Subscription not valid";
        document.forms[
0].order.disabled = true;
        }

    }

    }

}

查看代码:回到 XMLHttpRequest

如前所述,XMLHttpRequest 对象是构造和发送请求的核心对象。它也负责读取和解析从服务器返回的响应。请看下面几部分代码。

if (req.readystate == 4{
    
if (req.status == 200{

前面的代码检查请求的状态。如果请求处在就绪状态,就读取和解析响应。

就绪状态是什么意思呢?当请求对象的属性 readystate 的值是 4 时,就意味着客户机接收到了响应而且接收完成。下面我们检查请求的状态(响应是正常页面还是错误页面)。为了保证响应正常,要检查状态的值是否为 200。如果 status 的值是 200,就会处理响应。

var messageObj = req.responseXML.getElementsByTagName("message")[0];
var message = messageObj.childNodes[0].nodeValue;
if (message == "true"{
    msg.innerHTML 
= "Subscription is valid";
    document.forms[
0].order.disabled = false;
}
 else {
    msg.innerHTML 
= "Subscription not valid";
    document.forms[
0].order.disabled = true;
}
    }

接下来,请求对象通过调用 responseXML 属性读取响应。请注意 servlet XML 格式发送回响应,所以我们使用 responseXML。如果响应是以文本格式发送的,那么可以使用 responseText 属性。

在这个示例中,我们处理 XMLservlet 把响应构建在一个 <message> 标记中。要解析这个 XML 标记,请在 XMLHttpRequest 对象的 responseXML 属性上调用 getElementsByTagName() 方法。它得到标记的名称以及标记的子值。根据解析到的值,格式化响应并用 HTML 改写。

现在就完成了对订购 ID 的验证,没有页面刷新。

查看代码:查看作者、出版者和书名

其他的功能 —— 查看作者查看出版者 查看书名 —— 工作的方式类似。只是需要为每个功能定义独立的句柄:

function displayList(field) {
    init();
    titles.innerHTML 
= " ";
    req.onreadystatechange 
= listHandler;
    req.send(
"select=" + escape(field));
}


function displayTitles(formObj) {
    init();
    
var index = formObj.list.selectedIndex;
    
var val = formObj.list.options[index].value;
    req.onreadystatechange 
= titlesHandler;
    req.send(
"list=" + val);
}

请记住,示例应用程序允许用户根据作者和出版者查看书名。所以显示的或者是作者列表 或者是出版者列表。在这类场景中,应用程序只能根据用户的选择调用一个回调句柄 —— 换句话说,对于作者和出版者列表,只有一个 listHandler 回调句柄。

显示书名列表需要使用 titlesHandler。其余的功能仍然一样:servlet 处理请求,用 XML 格式写回响应。然后读取、解析、格式化响应,用 HTML 改写。可以用 HTML 把列表呈现为 select......options 标记。这个示例代码段显示了 titlesHandler 方法。

var temp = "<select name=\"titles\" multiple\>";
for (var i=0; i<index; i++{
    
var listObj = req.responseXML.getElementsByTagName("list")[i];
    temp 
= temp + "<option value=" + i +">" + listObj.childNodes[0].nodeValue 
+ "</option>";
}

temp 
= temp + "</select>";
titles.innerHTML 
= temp;