AJAX從服務端獲取數(shù)據(jù)的三種方法
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
在本文中將給出一個例子來介紹使用AJAX技術從服務端獲得數(shù)據(jù)的三種方法。這個例子很簡單,就是兩個選擇框(html中的<select>標簽),通過選中第一個select的某一項后,會從服務端得到一些數(shù)據(jù),并加載到第2個select中。 方法一、從服務端獲得XML格式的數(shù)據(jù) 從服務端獲得數(shù)據(jù)的最容易想到的方法就是在服務端反加一定格式的數(shù)據(jù),一般是XML格式,然后在服務端使用XMLDocument或其他技術來讀取這些數(shù)據(jù),并生成<select>標簽中選項的格式文本(<option>標簽)。下面的addOptions函數(shù)是這個例子的核心函數(shù),它負責根據(jù)從服務端獲得的數(shù)據(jù)生成<select>標簽中的<option>標簽。在這里所使用的方法是利用了<select>標簽的innerHTML屬性(僅限于firefox),如果是IE,要使用outerHTML屬性(IE中<select>標簽的innerHTML屬性有一些小bug,讀者可以試著在IE中使用innerHTML屬性,看看會發(fā)生什么情況)。addOptions方法的實現(xiàn)代碼如下: // select表示<select>對象,xml表示XMLDocument對象 function addOptions(select, xml) { if(select) { var options = ""; for(var i = 0; i < xml.childNodes[0].childNodes.length ; i++) { if(xml.childNodes[0].childNodes[i].nodeName == "list") { var s = ""; if(isIE()) s = xml.childNodes[0].childNodes[i].text; else s = xml.childNodes[0].childNodes[i].textContent options += "<option value='" + s + "'>" ; options += s; options += "</option>" } } var id = select.id; if(isIE()) select.outerHTML = "<SELECT id='" + id + "' onchange='onChange(this)'>" + options + "</SELECT>"; else select.innerHTML = options; } } onReadState函數(shù)將在XMLHttpRequest對象的異步訪問服務端時調(diào)用。當readyState為4時表示成功從服務端返回XML數(shù)據(jù)。這個函數(shù)的實現(xiàn)代碼如下: // myRequest表示XMLHttpRequest對象,selectId表示<select>標簽的id屬性值 function onReadyState(myRequest, selectId) { if(myRequest.readyState == 4) // 4表示成功獲得相應信息 { try { var xml = myRequest.responseXML; // 獲得XMLDocument對象 var kind = document.getElementById(selectId); // 獲得<select>對象 addOptions(kind, xml); // 向<select>標簽中加入<option>標簽 } catch(e) { alert("onReadyState:" + e); } } } getData函數(shù)負責向服務端發(fā)送請求,并設置異步事件。實現(xiàn)代碼如下: function getData(url, selectId) { var myRequest = getXMLHTTPRequest(); // 獲得一個XMLHttpRequest對象 if(myRequest) { myRequest.onreadystatechange = function() // 接收獲得數(shù)據(jù)狀態(tài)的事件函數(shù) { onReadyState(myRequest, selectId); } try { myRequest.open( "post", url, true); } catch(e) { alert(e); } try { myRequest.send(""); } catch(e) { alert(e); } } } 現(xiàn)在本例子的核心代碼已經(jīng)實現(xiàn)完成,下一步就是在html而加載時從服務端獲得第1個<select>標簽的數(shù)據(jù),并將其加載到第1個<select>標簽中。讓我們先看一下這個靜態(tài)的html代碼。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="myscript.js"> </script> </head> <body> <select id="bigKind" onchange="onChange(this)" > </select> <select id="smallKind" > </select> </body> </html> window.onload = onLoad function onLoad() { try { getData("../GetXML", "bigKind"); } catch(e) { alert("onLoad:" + e); } }
package servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import database.MyData; public class GetXML extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/xml;charset=UTF-8"); PrintWriter out = response.getWriter(); try { String s = request.getParameter("kind"); out.println("<data>"); if (s == null) { for (String key : MyData.data.keySet()) { out.println("<list>" + key + "</list>"); } } else { s = java.net.URLDecoder.decode(s, "UTF-8"); System.out.println(s); java.util.List<String> smallKind = MyData.data.get(s); if (smallKind != null) { for (String kind : smallKind) { out.println("<list>" + kind + "</list>"); } } } out.println("</data>"); } finally { out.close(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } public String getServletInfo() { return "Short description"; } }
不管讀者會不會java和servlet,從這個程序中的processRequest方法中都可以看出,首先會獲得請求參數(shù)kind,如果這個參數(shù)不存在,則返回bigKind所需要的數(shù)據(jù),以xml格式返回,類似于如下的格式: <data> <list>data1</list> <list>data2</list> </data>
package database; import java.util.*; public class MyData { public static Map<String, List<String>> data; static { data = new HashMap<String, List<String>>(); List<String> eProducts = new LinkedList<String>(); eProducts.add("手機"); eProducts.add("數(shù)碼/IT"); eProducts.add("家電"); eProducts.add("電腦"); data.put("消費電子", eProducts); List<String> goods = new LinkedList<String>(); goods.add("化妝"); goods.add("健康"); goods.add("玩具"); goods.add("辦公/文體 "); goods.add("童裝童鞋"); goods.add("其他"); data.put("日用百貨", goods); List<String> books = new LinkedList<String>(); books.add("小說"); books.add("動漫"); books.add("經(jīng)濟"); books.add("法律"); books.add("計算機"); books.add("英語"); books.add("通訊"); books.add("其他"); data.put("圖書", books) ; } }
function onChange(obj) { try { getData(encodeURI(encodeURI("../GetXML?kind=" +obj.options[obj.selectedIndex].value)), "smallKind"); } catch(e) { alert(e); } } 這個函數(shù)是<select>標簽的onchange事件函數(shù)。obj表示<select>標簽本身。這個函數(shù)中只有一條有實際意義的語句,也就是調(diào)用了getData方法,這個方法人在onLoad方法中調(diào)用getData時差不多,只是在傳送url時使用了兩個encodeURI方法。由于XMLHttpRequest方法以utf-8向服務端發(fā)送數(shù)據(jù),因此,要使用兩個encodeURI向服務端發(fā)送%xx形式的utf-8編碼,然后在服務端進行解析。我們在GetXML中的processRequest方法中可以找到如下的一條語句: s = java.net.URLDecoder.decode(s, "UTF-8");
就是進行解碼操作。 注:如果在IE中,客戶端可以不使用encodeURI對帶中文的URL進行編碼,服務端也不用解碼。在服務端仍然可以正常顯示中文。但在firefox中就必須要進行編碼和解碼。因此,要想跨瀏覽器,就需要使用本文所述的方法。 方法二、直接獲得<option>...</option>內(nèi)容的字符串 上面的獲得數(shù)據(jù)的方法是從服務端獲得了一個XML文檔,并轉換成XMLDocument對象,然后解析。這種方法雖然很好,但是操作XMLDocument對象還是有些麻煩,因此,我們可以在服務端直接反回<select>標簽所需要的<option>標簽字符串,然后將這些字符串傳給<select>對象的innerHTML或outerHTML就可以了。服務端的代碼和上面的實現(xiàn)代碼類似,只需要將<data>去掉,然后將<list>改為<option>后,并使用如下的語句來設置ContentType: response.setContentType("text/html;charset=UTF-8"); 客戶端可通過XMLHttpRequest對象的responseText屬性獲得這些含有<option>的文本,并將其賦給innerHTML或outerHTML屬性。這種方法雖然很方便,但并不靈活。如果客戶端不使用<select>標簽,而是使用<table>或其他的標簽顯示數(shù)據(jù),那么返回的這些數(shù)據(jù)就沒什么用處了。而即方便,又靈活的應該是下面要介紹的方法。 方法三、從服務端返回javascript代碼,在客戶端使用eval函數(shù)執(zhí)行 我們可以在服務端返回類似于如下的字符串: var options = new Array(); options.push(‘data1’); options.push(‘data2’); 然后使用eval函數(shù)執(zhí)行上面的字符串,這樣我們在javascript中就可以使用options數(shù)組了。我個人認為,使用數(shù)組要比使用XMLDocument更容易,代碼量也更少。如果要返回更為復雜的數(shù)據(jù),也可以使用javascript中的類或其他數(shù)據(jù)結構。根據(jù)上面的思想,新的processRequest方法的代碼如下: protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("var options = new Array();"); try { String s = request.getParameter("kind"); if (s == null) { for (String key : MyData.data.keySet()) { out.println("options.push('" + key + "');"); } } else { s = java.net.URLDecoder.decode(s, "UTF-8"); System.out.println(s); java.util.List<String> smallKind = MyData.data.get(s); if (smallKind != null) { for (String kind : smallKind) { out.println("options.push('" + kind + "');"); } } } } finally { out.close(); } } 客戶端經(jīng)過改進的addOptions函數(shù)如下: // javascript表示從服務端返回的javascript代碼字符串 function addOptions(select, javascript) { if(select) { if(select.id == "smallKind") { if(isIE()) select.options.length = 0; } var myOptions = ""; eval(javascript); //執(zhí)行從服務端返回的javascript代碼 for(var i = 0; i < options.length ; i++) // 從options數(shù)組中取數(shù)據(jù) { var s = ""; if(isIE()) { select.options[select.options.length] = new Option(options[i], options[i]); } else { myOptions += "<option value='" + options[i] + "'>" ; myOptions += options[i]; myOptions += "</option>" } } } var id = select.id; if(!isIE()) select.innerHTML = myOptions; }
在firefox中使用innerHTML時,在html未裝載完時,只要<select>標簽被裝載完(也就是調(diào)用了addOptions方法后),就可以訪問<select>標簽中的<option>了。個人感覺這一點要從IE做得好。順便說一句,筆者使用的是IE6,不知道ie7會是什么效果。如果哪位試過,可以跟貼。圖1是本例的效果圖。 本來想提供asp.net的例子來著,結果不知怎么著,vs2008的asp.net設計視圖突然不響應了,誰知道是怎么回事?。?? 該文章在 2013/7/11 22:43:12 編輯過 |
關鍵字查詢
相關文章
正在查詢... |