久久精品水蜜桃av综合天堂,久久精品丝袜高跟鞋,精品国产肉丝袜久久,国产一区二区三区色噜噜,黑人video粗暴亚裔

Ajax- 與服務(wù)器通信2

來自站長百科
跳轉(zhuǎn)至: 導(dǎo)航、? 搜索

導(dǎo)航: 上一頁 | ASP | PHP | JSP | HTML | CSS | XHTML | aJAX | Ruby | JAVA | XML | Python | ColdFusion

到此為止,你已經(jīng)了解了如何使用Ajax技術(shù)向服務(wù)器發(fā)送請求,也知道了客戶可以采用多種方法解析服務(wù)器的響應(yīng)。前面的例子中只缺少一個內(nèi)容,就是你尚未將任何數(shù)據(jù)作為請求的一部分發(fā)送給服務(wù)器。在大多數(shù)情況下,向服務(wù)器發(fā)送一個請求而沒有任何請求參數(shù)是沒有什么意義的。如果沒有請求參數(shù),服務(wù)器就得不到上下文數(shù)據(jù),也無法根據(jù)上下文數(shù)據(jù)為客戶創(chuàng)建“個性化”的響應(yīng),實際上,服務(wù)器會向每一個客戶發(fā)送同樣的響應(yīng)。

要想充分發(fā)揮Ajax技術(shù)的強大功能,這要求你向服務(wù)器發(fā)送一些上下文數(shù)據(jù)。假設(shè)有一個輸入表單,其中包含需要輸入郵件地址的部分。根據(jù)用戶輸入的ZIP編碼,可以使用Ajax技術(shù)預(yù)填相應(yīng)的城市名。當然,要想查找ZIP編碼對應(yīng)的城市,服務(wù)器首先需要知道用戶輸入的ZIP編碼。

你需要以某種方式將用戶輸入的ZIP編碼值傳遞給服務(wù)器。幸運的是,XMLHttpRequest對象的工作與你以往慣用的HTTP技術(shù)(GET和POST)是一樣的。

GET方法把值作為名/值對放在請求URL中傳遞。資源URL的最后有一個問號(?),問號后面就是名/值對。名/值對采用name=value的形式,各個名/值對之間用與號(&)分隔。

下面是GET請求的一個例子。這個請求向localhost服務(wù)器上的yourApp應(yīng)用發(fā)送了兩個參數(shù):firstName和middleName。需要注意,資源URL和參數(shù)集之間用問號分隔,firstName和middleName之間用與號(&)分隔:

http://localhost/yourApp?firstName=Adam&middleName=Christopher

服務(wù)器知道如何獲取URL中的命名參數(shù)。當前大多數(shù)服務(wù)器端編程環(huán)境都提供了簡單的API,使你能很容易地訪問命名參數(shù)。


采用POST方法向服務(wù)器發(fā)送命名參數(shù)時,與采用GET方法幾乎是一樣的。類似于GET方法,POST方法會把參數(shù)編碼為名/值對,形式為name=value,每個名/值對之間也用與號(&)分隔。這兩種方法的主要區(qū)別在于,POST方法將參數(shù)串放在請求體中發(fā)送,而GET方法是將參數(shù)追加到URL中發(fā)送。


如果數(shù)據(jù)處理不改變數(shù)據(jù)模型的狀態(tài),HTML使用規(guī)約理論上推薦采用GET方法,從這可以看出,獲取數(shù)據(jù)時應(yīng)當使用GET方法。如果因為存儲、更新數(shù)據(jù),或者發(fā)送了電子郵件,操作改變了數(shù)據(jù)模型的狀態(tài),這時建議使用POST方法。


每個方法都有各自特有的優(yōu)點。由于GET請求的參數(shù)編碼到請求URL中,所以可以在瀏覽器中為該URL建立書簽,以后就能很容易地重新請求。不過,如果是異步請求就沒有什么用。從發(fā)送到服務(wù)器的數(shù)據(jù)量來講,POST方法更為靈活。使用GET請求所能發(fā)送的數(shù)據(jù)量通常是固定的,因瀏覽器不同而有所差異,而POST方法可以發(fā)送任意量的數(shù)據(jù)。


HTML form元素允許通過將form元素的method屬性設(shè)置為GET或POST來指定所需的方法。在提交表單時,form元素自動根據(jù)其method屬性的規(guī)則對input元素的數(shù)據(jù)進行編碼。XMLHttpRequest對象沒有這種內(nèi)置行為。相反,要由開發(fā)人員使用JavaScript創(chuàng)建查詢串,其中包含的數(shù)據(jù)要作為請求的一部分發(fā)送給服務(wù)器。不論使用的是GET請求還是POST請求,創(chuàng)建查詢串的技術(shù)是一樣的。惟一的區(qū)別是,當使用GET發(fā)送請求時,查詢串會追加到請求URL中,而使用POST方法時,則在調(diào)用XMLHttpRequest對象的send()方法時發(fā)送查詢串。


圖3-4顯示了一個示例頁面,展示了如何向服務(wù)器發(fā)送請求參數(shù)。這是一個簡單的輸入表單,要求輸入名、姓和生日。這個表單有兩個按鈕,每個按鈕都會向服務(wù)器發(fā)送名、姓和生日數(shù)據(jù),不過一個使用GET方法,另一個使用POST方法。服務(wù)器以回顯輸入數(shù)據(jù)作為響應(yīng)。在瀏覽器在頁面上打印出服務(wù)器的響應(yīng)時,請求響應(yīng)周期結(jié)束。
Image007.jpg


圖3-4 瀏覽器使用GET或POST方法發(fā)送輸入數(shù)據(jù),服務(wù)器回顯輸入數(shù)據(jù)作為響應(yīng)

代碼清單3-7顯示了getAndPostExample.html,代碼清單3-8顯示了向瀏覽器回顯名、姓和生日數(shù)據(jù)的Java servlet。

代碼清單3-7 getAndPostExample.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

 "
<html xmlns="
<head>
<title>Sending Request Data Using GET and POST</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 createQueryString() {
var firstName = document.getElementById("firstName").value;
var middleName = document.getElementById("middleName").value;
var birthday = document.getElementById("birthday").value;
var queryString = "firstName=" + firstName + "&middleName=" + middleName
+ "&birthday=" + birthday;
return queryString;
}
function doRequestUsingGET() {
createXMLHttpRequest();
var queryString = "GetAndPostExample?";
queryString = queryString + createQueryString()
+ "&timeStamp=" + new Date().getTime();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", queryString, true);
xmlHttp.send(null);
}
function doRequestUsingPOST() {
createXMLHttpRequest();
var url = "GetAndPostExample?timeStamp=" + new Date().getTime();
var queryString = createQueryString();
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded;");
xmlHttp.send(queryString);
}
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>Enter your first name, middle name, and birthday:</h1>
<table>
<tbody>
<tr>
<td>First name:</td>
<td><input type="text" id="firstName"/>
</tr>
<tr>
<td>Middle name:</td>
<td><input type="text" id="middleName"/>
</tr>
<tr>
<td>Birthday:</td>
<td><input type="text" id="birthday"/>
</tr><nowiki>
</tbody><nowiki>
</table><nowiki>
<form action="#"><nowiki>
<input type="button" value="Send parameters using GET"
onclick="doRequestUsingGET();"/>
<br/><br/>
<input type="button" value="Send parameters using POST"
onclick="doRequestUsingPOST();"/>
</form>
<br/>
<h2>Server Response:</h2>
<div id="serverResponse"></div>
</body>
</html>

代碼清單3-8 向瀏覽器回顯名、姓和生日

package ajaxbook.chap3; 
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class GetAndPostExample extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response, String method)
throws ServletException, IOException {
//Set content type of the response to text/xml
response.setContentType("text/xml");
//Get the user's input
String firstName = request.getParameter("firstName");
String middleName = request.getParameter("middleName");
String birthday = request.getParameter("birthday");
//Create the response text
String responseText = "Hello " + firstName + " " + middleName
+ ". Your birthday is " + birthday + "."
+ " [Method: " + method + "]";
//Write the response back to the browser
PrintWriter out = response.getWriter();
out.println(responseText);
//Close the writer
out.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Process the request in method processRequest
processRequest(request, response, "GET");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Process the request in method processRequest
processRequest(request, response, "POST");
}
}


下面先來分析服務(wù)器端代碼。這個例子使用了Java servlet來處理請求,不過也可以使用任何其他服務(wù)器端技術(shù),如PHP、CGI或.NET。Java servlet必須定義一個doGet方法和一個doPost方法,每個方法根據(jù)請求方法(GET或POST)來調(diào)用。在這個例子中,doGet和doPost都調(diào)用同樣的方法processRequest來處理請求。

processRequest方法先把響應(yīng)的內(nèi)容類型設(shè)置為text/xml,盡管在這個例子中并沒有真正用到XML。通過使用getParameter方法從request對象獲得3個輸入字段。根據(jù)名、姓和生日,以及請求方法的類型,會建立一個簡單的語句。這個語句將寫至響應(yīng)輸出流,最后響應(yīng)輸出流關(guān)閉。

瀏覽器端JavaScript與前面的例子同樣是類似的,不過這里稍稍增加了幾個技巧。這里有一個工具函數(shù)createQueryString負責(zé)將輸入?yún)?shù)編碼為查詢串。createQueryString函數(shù)只是獲取名、姓和生日的輸入值,并將它們追加為名/值對,每個名/值對之間由與號(&)分隔。這個函數(shù)會返回查詢串,以便GET和POST操作重用。

點擊Send Parameters Using GET(使用GET方法發(fā)送參數(shù))按鈕將調(diào)用doRequestUsingGET函數(shù)。這個函數(shù)與前面例子中的許多函數(shù)一樣,先調(diào)用創(chuàng)建XMLHttpRequest對象實例的函數(shù)。接下來,對輸入值編碼,創(chuàng)建查詢串。

在這個例子中,請求端點是名為GetAndPostExample的servlet。在建立查詢串時,要把createQueryString函數(shù)返回的查詢串與請求端點連接,中間用問號分隔。

JavaScript仍與前面看到的類似。XMLHttpRequest對象的onreadystatechange屬性設(shè)置為要使用handleStateChange函數(shù)。open()方法指定這是一個GET請求,并指定了端點URL,在這里端點URL中包含有編碼的參數(shù)。send()方法將請求發(fā)送給服務(wù)器,handleSta- teChange函數(shù)處理服務(wù)器響應(yīng)。

當請求成功完成時,handleStateChange函數(shù)將調(diào)用parseResults函數(shù)。parseResults函數(shù)獲取div元素,其中包含服務(wù)器的響應(yīng),并把它保存在局部變量responseDiv中。使用responseDiv的removeChild方法先將以前的服務(wù)器結(jié)果刪除。最后,創(chuàng)建包含服務(wù)器響應(yīng)的新文本節(jié)點,并將這個文本節(jié)點追加到responseDiv。

使用POST方法而不是GET方法基本上是一樣的,只是請求參數(shù)發(fā)送給服務(wù)器的方式不同。應(yīng)該記得,使用GET時,名/值對會追加到目標URL。POST方法則把同樣的查詢串作為請求體的一部分發(fā)送。

點擊Send Parameters Using POST(使用POST方法發(fā)送參數(shù))按鈕將調(diào)用doRequest- UsingPOST函數(shù)。類似于doRequestUsingGET函數(shù),它先創(chuàng)建XMLHttpRequest對象的一個實例,腳本再創(chuàng)建查詢串,其中包含要發(fā)送給服務(wù)器的參數(shù)。需要注意,查詢串現(xiàn)在并不連接到目標URL。

接下來調(diào)用XMLHttpRequest對象的open()方法,這一次指定請求方法是POST,另外指定了沒有追加名/值對的“原”目標URL。onreadystatechange屬性設(shè)置為handleStateCh- ange函數(shù),所以響應(yīng)會以與GET方法中相同的方式得到處理。為了確保服務(wù)器知道請求體中有請求參數(shù),需要調(diào)用setRequestHeader,將Content-Type值設(shè)置為application/x- www-form-urlencoded。最后,調(diào)用send()方法,并把查詢串作為參數(shù)傳遞給這個方法。

點擊兩個按鈕的結(jié)果是一樣的。頁面上會顯示一個串,其中包括指定的名、姓和生日,另外還會顯示所用請求方法的類型。

為什么要把時間戳追加到目標URL?

在某些情況下,有些瀏覽器會把多個XMLHttpRequest請求的結(jié)果緩存在同一個URL。如果對每個請求的響應(yīng)不同,這就會帶來不好的結(jié)果。把當前時間戳追加到URL的最后,就能確保URL的惟一性,從而避免瀏覽器緩存結(jié)果。


請求參數(shù)作為XML發(fā)送[ ]

與幾年前相比,當前瀏覽器上JavaScript的兼容性有了長足的進步,已經(jīng)不可同日而語,再加上越來越成熟的JavaScript開發(fā)工具和技術(shù),你可以決定把Web瀏覽器作為開發(fā)平臺。并不只是依賴于瀏覽器來看待模型—視圖—控制器模式中的視圖,還可以用JavaScript實現(xiàn)部分業(yè)務(wù)模型。可以使用Ajax技術(shù)把模型中的變化持久存儲到后臺服務(wù)器。如果模型放在瀏覽器上,模型的變化可以一齊傳遞到服務(wù)器,從而減少對服務(wù)器的遠程調(diào)用次數(shù),還可能提高性能。

如果只是使用一個包含名/值對的簡單查詢串,這可能不夠健壯,不足以向服務(wù)器傳遞大量復(fù)雜的模型變化。更好的解決方案是將模型的變化作為XML發(fā)送到服務(wù)器。怎么向服務(wù)器發(fā)送XML呢?

可以把XML作為請求體的一部分發(fā)送到服務(wù)器,這與POST請求中將查詢串作為請求體的一部分進行發(fā)送異曲同工。服務(wù)器可以從請求體讀到XML,并加以處理。

下面的例子展示了對于一個Ajax請求如何向服務(wù)器發(fā)送XML。圖3-5顯示了這個頁面,其中有一個簡單的選擇框,用戶可以選擇寵物的類型。這是一個相當簡化的例子,但是由此可以了解如何向服務(wù)器發(fā)送XML。

Image008.jpg


圖3-5 選擇框中選中的項將作為XML發(fā)送到服務(wù)器

代碼清單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"><.nowiki><br> <nowiki><html xmlns="http://www.w3.org/1999/xhtml"><.nowiki><br> <head><br> <nowiki><title>Sending an XML Request</title><.nowiki><br> <nowiki><script type="text/javascript"><.nowiki><br> <nowiki>var xmlHttp;<.nowiki><br> <nowiki>function createXMLHttpRequest() {<.nowiki><br> if (window.ActiveXObject) {<br> xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");<br> }<br> else if (window.XMLHttpRequest) {<br> xmlHttp = new XMLHttpRequest();<br> }<br> }<br> function createXML() {<br> var xml = "<pets>";<br> var options = document.getElementById("petTypes").childNodes;<br> var option = null;<br> for(var i = 0; i < options.length; i++) {<br> option = options[i];<br> if(option.selected) {<br> xml = xml + "<type>" + option.value + "<\/type>";<br> }<br> }<br> xml = xml + "<\/pets>";<br> return xml;<br> }<br> function sendPetTypes() {<br> createXMLHttpRequest();<br> var xml = createXML();<br> var url = "PostingXMLExample?timeStamp=" + new Date().getTime();<br> xmlHttp.open("POST", url, true);<br> xmlHttp.onreadystatechange = handleStateChange;<br> xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");<br> xmlHttp.send(xml);<br> }<br> function handleStateChange() {<br> if(xmlHttp.readyState == 4) {<br> if(xmlHttp.status == 200) {<br> parseResults();<br> }<br> }<br> }<br> function parseResults() {<br> var responseDiv = document.getElementById("serverResponse");<br> if(responseDiv.hasChildNodes()) {<br> responseDiv.removeChild(responseDiv.childNodes[0]);<br> }<br> var responseText = document.createTextNode(xmlHttp.responseText);<br> responseDiv.appendChild(responseText);<br> }<br> </script><br> </head><br> <body><br> <nowiki><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例子基本上是一樣的。區(qū)別在于,不是發(fā)送由名/值對組成的查詢串,而是向服務(wù)器發(fā)送XML串。
點擊表單上的Submit Pets(提交寵物)按鈕將調(diào)用sendPetTypes函數(shù)。類似于前面的例子,這個函數(shù)首先創(chuàng)建XMLHttpRequest對象的一個實例,然后調(diào)用名為createXML的輔助函數(shù),它根據(jù)所選的寵物類型建立XML串。

函數(shù)createXML使用document.getElementbyId方法獲得select元素的引用,然后迭代處理所有option子元素,對于選中的每個option元素依據(jù)所選寵物類型創(chuàng)建XML標記,并逐個追加到XML中。循環(huán)結(jié)束時,要在返回到調(diào)用函數(shù)(sendPetTypes)之前向XML串追加結(jié)束pets標記。

一旦得到了XML串,sendPetTypes函數(shù)繼續(xù)為請求準備XMLHttpObject,然后把XML串指定為send()方法的參數(shù),從而將XML發(fā)送到服務(wù)器。

在createXML方法中,為什么結(jié)束標記中斜線前面有一個反斜線?

SGML規(guī)約(HTML就是從SGML發(fā)展來的)中提供了一個技巧,利用這個技巧可以識別出script元素中的結(jié)束標記,但是其他內(nèi)容(如開始標記和注釋)則不能識別。使用反斜線可以避免把串解析為標記。即使沒有反斜線,大多數(shù)瀏覽器也能安全地處理,但是根據(jù)嚴格的XHTML標準,應(yīng)該使用反斜線。
聰明的讀者可能注意到,根據(jù)XMLHttpRequest對象的文檔,send()方法可以將串和XML文檔對象實例作為參數(shù)。那么,這個例子為什么使用串連接來創(chuàng)建XML,而不是直接創(chuàng)建文檔和元素對象呢?遺憾的是,對于從頭構(gòu)建文檔對象,目前還沒有跨瀏覽器的技術(shù)。IE通過ActiveX對象提供這個功能,Mozilla瀏覽器則通過本地JavaScript對象來提供,其他瀏覽器可能根本不支持,也可能通過其他途徑來支持這個功能。

讀取XML的服務(wù)器端代碼如代碼清單3-10所示,這個代碼稍有些復(fù)雜。在此使用了Java servlet來讀取請求,并解析XML串,不過你也可以使用其他的服務(wù)器端技術(shù)。

一旦收到XMLHttpRequest對象的請求,就會調(diào)用這個servlet的doPost方法。doPost方法使用名為readXMLFromRequestBody的輔助方法從請求體中抽取XML,然后使用JAXP接口將XML串轉(zhuǎn)換為Document對象。

注意,Document對象是W3C指定的Document接口的一個實例。因此,它與瀏覽器的Document對象有著同樣的方法,如getElementsByTagName??梢允褂眠@個方法來得到文檔中所有type元素的列表。對于文檔中的每個type元素,會得到文本值(應(yīng)該記得,文本值是type元素的第一個子節(jié)點),并逐個追加到串中。處理完所有type元素后,響應(yīng)串寫回到瀏覽器。

代碼清單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();
}
}


使用JSON向服務(wù)器發(fā)送數(shù)據(jù)[ ]

做了這么多,你已經(jīng)能更順手地使用JavaScript了,也許在考慮把更多的模型信息放在瀏覽器上。不過,看過前面的例子后(使用XML向服務(wù)器發(fā)送復(fù)雜的數(shù)據(jù)結(jié)構(gòu)),你可能會改變主意。通過串連接來創(chuàng)建XML串并不好,這也不是用來生成或修改XML數(shù)據(jù)結(jié)構(gòu)的健壯技術(shù)。

JSON概述

XML的一個替代方法是JSON,可以在www.json.org找到。JSON是一種文本格式,它獨立于具體語言,但是使用了與C系列語言(如C、C#、JavaScript等)類似的約定。JSON建立在以下兩種數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)上,當前幾乎所有編程語言都支持這兩種數(shù)據(jù)結(jié)構(gòu):

l 名/值對集合。在當前編程語言中,這實現(xiàn)為一個對象、記錄或字典。

l 值的有序表,這通常實現(xiàn)為一個數(shù)組。

因為這些結(jié)構(gòu)得到了如此眾多編程語言的支持,所以JSON是一個理想的選擇,可以作為異構(gòu)系統(tǒng)之間的一種數(shù)據(jù)互換格式。另外,由于JSON是基于標準JavaScript的子集,所以在所有當前Web瀏覽器上都應(yīng)該是兼容的。

JSON對象是名/值對的無序集合。對象以 { 開始,以 } 結(jié)束,名/值對用冒號分隔。JSON數(shù)組是一個有序的值集合,以[ 開始,以 ] 結(jié)束,數(shù)組中的值用逗號分隔。值可以是串(用雙引號引起)、數(shù)值、true或false、對象,或者是數(shù)組,因此結(jié)構(gòu)可以嵌套。圖3-6以圖形方式很好地描述了JSON對象的標記。

Image009.jpg


圖3-6 JSON對象結(jié)構(gòu)的圖形化表示(摘自www.json.org)

請考慮employee對象的簡單例子。employee對象可能包含名、姓、員工號和職位等數(shù)據(jù)。使用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有一點很引以為豪,這就是它是一個輕量級的數(shù)據(jù)互換格式。如果用XML來描述同樣的employee對象,可能如下所示:

<employee>
<firstName>John</firstName>
<lastName>Doe</lastName>
<employeeNumber>123</employeeNumber>
<title>Accountant</title>
</employee>

顯然,JSON編碼比XML編碼簡短。JSON編碼比較小,所以如果在網(wǎng)絡(luò)上發(fā)送大量數(shù)據(jù),可能會帶來顯著的性能差異。

www.json.org網(wǎng)站列出了至少與其他編程語言的14種綁定,這說明,不論在服務(wù)器端使用何種技術(shù),都能通過JSON與瀏覽器通信。

使用JSON的示例

下面是一個簡單的例子,展示了如何使用JSON將JavaScript對象轉(zhuǎn)換為串格式,并使用Ajax技術(shù)將這個串發(fā)送到服務(wù)器,然后服務(wù)器根據(jù)這個串創(chuàng)建一個對象。這個例子中沒有業(yè)務(wù)邏輯,也幾乎沒有用戶交互,它強調(diào)的是客戶端和服務(wù)器端的JSON技術(shù)。圖3-7顯示了一個“字符串化的”Car對象。

Image010.jpg


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

因為這個例子幾乎與前面的POST例子完全相同,所以我們只關(guān)注JSON特定的技術(shù)。點擊表單上的按鈕將調(diào)用doJSON函數(shù)。這個函數(shù)首先調(diào)用getCarObject函數(shù)來返回一個新的Car對象實例,然后使用JSON JavaScript庫(可以從www.json.org免費得到)將Car對象轉(zhuǎn)換為JSON串,再在警告框中顯示這個串。接下來使用XMLHttpRequest對象將JSON編碼的Car對象發(fā)送到服務(wù)器。

因為有可以免費得到的JSON-Java綁定庫,所以編寫Java servlet來為JSON請求提供服務(wù)相當簡單。更妙的是,由于對每種服務(wù)器端技術(shù)都有相應(yīng)的JSON綁定,所以可以使用任何服務(wù)器端技術(shù)實現(xiàn)這個例子。 Image011.jpg


JSONExample servlet的doPost方法為JSON請求提供服務(wù)。它首先調(diào)用readJSONStr- ingFromRequestBody方法從請求體獲得JSON串,然后創(chuàng)建JSONObject的一個實例,向JSONObject構(gòu)造函數(shù)提供JSON串。JSONObject在對象創(chuàng)建時自動解析JSON串。一旦創(chuàng)建了JSONObject,就可以使用各個get方法來獲得你感興趣的對象屬性。

這里使用getString和getInt方法來獲取year、make、model和color屬性。這些屬性連接起來構(gòu)成一個串返回給瀏覽器,并在頁面上顯示。圖3-8顯示了讀取JSON對象之后的服務(wù)器響應(yīng)。

代碼清單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=" <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();
}
}