投递文章投递文章 投稿指南投稿指南 RSS订阅RSS订阅

Ajax基础教程(阿斯利森版)第三章

来源:CSDN 发布时间:2008-05-15 收藏 投稿 字体:【

3.2.1  请求参数作为XML发送

与几年前相比,当前浏览器上JavaScript的兼容性有了长足的进步,已经不可同日而语,再加上越来越成熟的JavaScript开发工具和技术,你可以决定把Web浏览器作为开发平台。并不只是依赖于浏览器来看待模型—视图—控制器模式中的视图,还可以用JavaScript实现部分业务模型。可以使用Ajax技术把模型中的变化持久存储到后台服务器。如果模型放在浏览器上,模型的变化可以一齐传递到服务器,从而减少对服务器的远程调用次数,还可能提高性能。

如果只是使用一个包含名/值对的简单查询串,这可能不够健壮,不足以向服务器传递大量复杂的模型变化。更好的解决方案是将模型的变化作为XML发送到服务器。怎么向服务器发送XML呢?

可以把XML作为请求体的一部分发送到服务器,这与POST请求中将查询串作为请求体的一部分进行发送异曲同工。服务器可以从请求体读到XML,并加以处理。

下面的例子展示了对于一个Ajax请求如何向服务器发送XML。图3-5显示了这个页面,其中有一个简单的选择框,用户可以选择宠物的类型。这是一个相当简化的例子,但是由此可以了解如何向服务器发送XML

3-5 选择框中选中的项将作为XML发送到服务器

代码清单3-9显示了postingXML.html

代码清单3-9  postingXML.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>Sending an XML Request</title>

 

<script type="text/javascript">

 

var xmlHttp;

 

function createXMLHttpRequest() {

    if (window.ActiveXObject) {

        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

    }

    else if (window.XMLHttpRequest) {

        xmlHttp = new XMLHttpRequest();

    }

}

 

function createXML() {

    var xml = "<pets>";

    var options = document.getElementById("petTypes").childNodes;

    var option = null;

    for(var i = 0; i < options.length; i++) {

        option = options[i];

        if(option.selected) {

            xml = xml + "<type>" + option.value + "<\/type>";

        }

    }

 

    xml = xml + "<\/pets>";

    return xml;

}

 

function sendPetTypes() {

    createXMLHttpRequest();

 

    var xml = createXML();

    var url = "PostingXMLExample?timeStamp=" + new Date().getTime();

 

    xmlHttp.open("POST", url, true);

    xmlHttp.onreadystatechange = handleStateChange;

    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");

    xmlHttp.send(xml);

}

 

function handleStateChange() {

    if(xmlHttp.readyState == 4) {

        if(xmlHttp.status == 200) {

            parseResults();

        }

    }

}

 

function parseResults() {

    var responseDiv = document.getElementById("serverResponse");

    if(responseDiv.hasChildNodes()) {

        responseDiv.removeChild(responseDiv.childNodes[0]);

    }

 

    var responseText = document.createTextNode(xmlHttp.responseText);

    responseDiv.appendChild(responseText);

}

 

 

</script>

</head>

<body>

  <h1>Select the types of pets in your home:</h1>

 

  <form action="#">

    <select id="petTypes" size="6" multiple="true">

        <option value="cats">Cats</option>

        <option value="dogs">Dogs</option>

        <option value="fish">Fish</option>

        <option value="birds">Birds</option>

        <option value="hamsters">Hamsters</option>

        <option value="rabbits">Rabbits</option>

  </select>

 

  <br/><br/>

  <input type="button" value="Submit Pets" onclick="sendPetTypes();"/>

</form>

 

<h2>Server Response:</h2>

 

<div id="serverResponse"></div>

 

</body>

</html>

这个例子与前面的POST例子基本上是一样的。区别在于,不是发送由名/值对组成的查询串,而是向服务器发送XML串。

点击表单上的Submit Pets(提交宠物)按钮将调用sendPetTypes函数。类似于前面的例子,这个函数首先创建XMLHttpRequest对象的一个实例,然后调用名为createXML的辅助函数,它根据所选的宠物类型建立XML串。

函数createXML使用document.getElementbyId方法获得select元素的引用,然后迭代处理所有option子元素,对于选中的每个option元素依据所选宠物类型创建XML标记,并逐个追加到XML中。循环结束时,要在返回到调用函数(sendPetTypes)之前向XML串追加结束pets标记。

一旦得到了XML串,sendPetTypes函数继续为请求准备XMLHttpObject,然后把XML串指定为send()方法的参数,从而将XML发送到服务器。

createXML方法中,为什么结束标记中斜线前面有一个反斜线?

SGML规约(HTML就是从SGML发展来的)中提供了一个技巧,利用这个技巧可以识别出script元素中的结束标记,但是其他内容(如开始标记和注释)则不能识别。使用反斜线可以避免把串解析为标记。即使没有反斜线,大多数浏览器也能安全地处理,但是根据严格的XHTML标准,应该使用反斜线。

聪明的读者可能注意到,根据XMLHttpRequest对象的文档,send()方法可以将串和XML文档对象实例作为参数。那么,这个例子为什么使用串连接来创建XML,而不是直接创建文档和元素对象呢?遗憾的是,对于从头构建文档对象,目前还没有跨浏览器的技术。IE通过ActiveX对象提供这个功能,Mozilla浏览器则通过本地JavaScript对象来提供,其他浏览器可能根本不支持,也可能通过其他途径来支持这个功能。

读取XML的服务器端代码如代码清单3-10所示,这个代码稍有些复杂。在此使用了Java servlet来读取请求,并解析XML串,不过你也可以使用其他的服务器端技术。

一旦收到XMLHttpRequest对象的请求,就会调用这个servletdoPost方法。doPost法使用名为readXMLFromRequestBody的辅助方法从请求体中抽取XML然后使用JAXP接口XML串转换为Document对象。

注意,Document对象是W3C指定的Document接口的一个实例。因此,它与浏览器的Document对象有着同样的方法,如getElementsByTagName。可以使用这个方法来得到文档中所有type元素的列表。对于文档中的每个type元素,会得到文本值(应该记得,文本值是type元素的第一个子节点),并逐个追加到串中。处理完所有type元素后,响应串写回到浏览器。

代码清单3-10  PostingXMLExample.java

package ajaxbook.chap3;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class PostingXMLExample extends HttpServlet {

 

    protected void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

 

        String xml = readXMLFromRequestBody(request);

        Document xmlDoc = null;

        try {

            xmlDoc =

                    DocumentBuilderFactory.newInstance().newDocumentBuilder()

                    .parse(new ByteArrayInputStream(xml.getBytes()));

        }

        catch(ParserConfigurationException e) {

            System.out.println("ParserConfigurationException: " + e);

        }

        catch(SAXException e) {

            System.out.println("SAXException: " + e);

        }

 

        /* Note how the Java implementation of the W3C DOM has the same methods

         * as the JavaScript implementation, such as getElementsByTagName and

         * getNodeValue.

         */

        NodeList selectedPetTypes = xmlDoc.getElementsByTagName("type");

        String type = null;

        String responseText = "Selected Pets: ";

        for(int i = 0; i < selectedPetTypes.getLength(); i++) {

            type = selectedPetTypes.item(i).getFirstChild().getNodeValue();

            responseText = responseText + " " + type;

        }

 

        response.setContentType("text/xml");

        response.getWriter().print(responseText);

    }

 

    private String readXMLFromRequestBody(HttpServletRequest request){

        StringBuffer xml = new StringBuffer();

        String line = null;

        try {

            BufferedReader reader = request.getReader();

            while((line = reader.readLine()) != null) {

                xml.append(line);

            }

        }

        catch(Exception e) {

            System.out.println("Error reading XML: " + e.toString());

        }

        return xml.toString();

    }

}

3.2.2  使用JSON向服务器发送数据

做了这么多,你已经能更顺手地使用JavaScript了,也许在考虑把更多的模型信息放在浏览器上。不过,看过前面的例子后(使用XML向服务器发送复杂的数据结构),你可能会改变主意。通过串连接来创建XML串并不好,这也不是用来生成或修改XML数据结构的健壮技术。

JSON概述

XML的一个替代方法是JSON,可以在www.json.org找到。JSON是一种文本格式,它独立于具体语言,但是使用了与C系列语言(如CC#JavaScript等)类似的约定。JSON建立在以下两种数据结构基础上,当前几乎所有编程语言都支持这两种数据结构:

l    /值对集合。在当前编程语言中,这实现为一个对象、记录或字典。

l    值的有序表,这通常实现为一个数组。

因为这些结构得到了如此众多编程语言的支持,所以JSON是一个理想的选择,可以作为异构系统之间的一种数据互换格式。另外,由于JSON是基于标准JavaScript的子集,所以在所有当前Web浏览器上都应该是兼容的。

JSON对象是名/值对的无序集合。对象以 { 开始,以 } 结束,名/值对用冒号分隔。JSON数组是一个有序的值集合,以[ 开始,以 ] 结束,数组中的值用逗号分隔。值可以是串(用双引号引起)、数值、truefalse、对象,或者是数组,因此结构可以嵌套。图3-6以图形方式很好地描述了JSON对象的标记。

3-6  JSON对象结构的图形化表示(摘自www.json.org

请考虑employee对象的简单例子。employee对象可能包含名、姓、员工号和职位等数据。使用JSON,可以如下表示employee对象实例:

var employee = {

    "firstName" : John

    , "lastName" : Doe

    , "employeeNumber" : 123

    , "title" : "Accountant"

}

然后可以使用标准点记法使用对象的属性,如下所示:

var lastName = employee.lastName;   //Access the last name

var title = employee.title;             //Access the title

employee.employeeNumber = 456;      //Change the employee number

JSON有一点很引以为豪,这就是它是一个轻量级的数据互换格式。如果用XML来描述同样的employee对象,可能如下所示:

<employee>

    <firstName>John</firstName>

    <lastName>Doe</lastName>

    <employeeNumber>123</employeeNumber>

    <title>Accountant</title>

</employee>

显然,JSON编码比XML编码简短。JSON编码比较小,所以如果在网络上发送大量数据,可能会带来显著的性能差异。

www.json.org网站列出了至少与其他编程语言的14种绑定,这说明,不论在服务器端使用何种技术,都能通过JSON与浏览器通信。

使用JSON的示例

下面是一个简单的例子,展示了如何使用JSONJavaScript对象转换为串格式,并使用Ajax技术将这个串发送到服务器,然后服务器根据这个串创建一个对象。这个例子中没有业务逻辑,也几乎没有用户交互,它强调的是客户端和服务器端的JSON技术。图3-7显示了一个“字符串化的”Car对象。

3-7  “字符串化的”Car对象

因为这个例子几乎与前面的POST例子完全相同,所以我们只关注JSON特定的技术。点击表单上的按钮将调用doJSON函数。这个函数首先调用getCarObject函数来返回一个新的Car对象实例,然后使用JSON JavaScript库(可以从www.json.org免费得到)将Car对象转换为JSON串,再在警告框中显示这个串。接下来使用XMLHttpRequest对象将JSON编码的Car对象发送到服务器。

因为有可以免费得到的JSON-Java绑定库,所以编写Java servlet来为JSON请求提供服务相当简单。更妙的是,由于对每种服务器端技术都有相应的JSON绑定,所以可以使用任何服务器端技术实现这个例子。

文本框:  
图3-8  读取JSON串之后的服务器响应

JSONExample servletdoPost方法为JSON请求提供服务。它首先调用readJSONStr- ingFromRequestBody方法从请求体获得JSON串,然后创建JSONObject的一个实例,向JSONObject构造函数提供JSON串。JSONObject在对象创建时自动解析JSON串。一旦创建了JSONObject,就可以使用各个get方法来获得你感兴趣的对象属性。

这里使用getStringgetInt方法来获取yearmakemodelcolor属性。这些属性连接起来构成一个串返回给浏览器,并在页面上显示。图3-8显示了读取JSON对象之后的服务器响应。

代码清单3-11显示了jsonExample.html,代码清单3-12显示了JSONExample.java

代码清单3-11  jsonExample.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>JSON Example</title>

 

<script type="text/javascript" src="json.js"></script>

<script type="text/javascript">

 

var xmlHttp;

 

function createXMLHttpRequest() {

    if (window.ActiveXObject) {

        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

    }

    else if (window.XMLHttpRequest) {

        xmlHttp = new XMLHttpRequest();

    }

}

 

function doJSON() {

    var car = getCarObject();

 

    //Use the JSON JavaScript library to stringify the Car object

    var carAsJSON = JSON.stringify(car);

    alert("Car object as JSON:\n " + carAsJSON);

 

    var url = "JSONExample?timeStamp=" + new Date().getTime();

 

    createXMLHttpRequest();

    xmlHttp.open("POST", url, true);

    xmlHttp.onreadystatechange = handleStateChange;

    xmlHttp.setRequestHeader("Content-Type",

                    "application/x-www-form-urlencoded;");

    xmlHttp.send(carAsJSON);

}

 

function handleStateChange() {

    if(xmlHttp.readyState == 4) {

        if(xmlHttp.status == 200) {

            parseResults();

        }

    }

}

 

function parseResults() {

    var responseDiv = document.getElementById("serverResponse");

    if(responseDiv.hasChildNodes()) {

        responseDiv.removeChild(responseDiv.childNodes[0]);

    }

 

    var responseText = document.createTextNode(xmlHttp.responseText);

    responseDiv.appendChild(responseText);

}

 

function getCarObject() {

    return new Car("Dodge", "Coronet R/T", 1968, "yellow");

}

 

function Car(make, model, year, color) {

    this.make = make;

    this.model = model;

    this.year = year;

    this.color = color;

}

 

</script>

</head>

 

<body>

 

  <br/><br/>

  <form action="#">

      <input type="button" value="Click here to send JSON data to the server"

        onclick="doJSON();"/>

  </form>

 

  <h2>Server Response:</h2>

 

  <div id="serverResponse"></div>

 

</body>

</html>

代码清单3-12  JSONExample.java

package ajaxbook.chap3;

 

import java.io.*;

import java.net.*;

import java.text.ParseException;

import javax.servlet.*;

import javax.servlet.http.*;

import org.json.JSONObject;

 

public class JSONExample extends HttpServlet {

 

    protected void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        String json = readJSONStringFromRequestBody(request);

 

        //Use the JSON-Java binding library to create a JSON object in Java

        JSONObject jsonObject = null;

        try {

            jsonObject = new JSONObject(json);

        }

        catch(ParseException pe) {

            System.out.println("ParseException: " + pe.toString());

        }

 

        String responseText = "You have a " + jsonObject.getInt("year") + " "

            + jsonObject.getString("make") + " " + jsonObject.getString("model")

            + " " + " that is " + jsonObject.getString("color") + " in color.";

 

        response.setContentType("text/xml");

        response.getWriter().print(responseText);

    }

 

    private String readJSONStringFromRequestBody(HttpServletRequest request){

        StringBuffer json = new StringBuffer();

        String line = null;

        try {

            BufferedReader reader = request.getReader();

            while((line = reader.readLine()) != null) {

                json.append(line);

            }

        }

        catch(Exception e) {

            System.out.println("Error reading JSON string: " + e.toString());

        }

        return json.toString();

    }

}

3.3 第三章小结

本章介绍了XMLHttpRequest对象与服务器之间相互通信的各种方法。XMLHttpRequest对象可以使用HTTP GETPOST方法发送请求,请求数据可以作为查询串、XMLJSON数据发送。处理请求之后,服务器一般会发送简单文本、XML数据甚至JSON数据作为响应。每个格式都有自己最适用的场合。

如果不能根据请求的结果动态更新页面的内容,Ajax就没有多大的用处。当前的浏览器都把Web页面的内容提供为一个遵循W3C DOM标准的对象模型。基于这个对象模型,就可以使用JavaScript之类的脚本语言在页面上增加、更新和删除内容,而不必与服务器建立往返通信。尽管还是存在一些特异的地方,但如果Web页面是根据W3C标准编写的,并使用标准JavaScript修改,那么在所有与标准兼容的浏览器上这些页面大多都有同样的表现。如今的浏览器还支持非标准的innerHTML属性,可以用来更新Web页面上的元素。

你现在已经熟悉了XMLHttpRequest对象,并且了解了如何使用XMLHttpRequest对象与服务器进行无缝通信。你还知道了怎样动态地更新Web页面的内容。下面再学些什么呢?

Ajax的潜力无穷无尽,第4章将就此简单地谈一谈。知道如何使用Ajax只是一方面,如何在合适的环境中加以应用则是另一方面。下一章会介绍一些常见的情况,在这些情况下,Web应用就很适合采用Ajax技术。

最新评论:
评论内容:请自觉遵守互联网相关政策法规。
用户名: 密码: 匿名 注册
热门文章
随机推荐
About iTtang - 联系方法  - 专题列表 - 友情链接  -  高级搜索   -  帮助中心  -