Ajax 是 Asynchronous JavaScript and XML 的簡稱,這指出了 Ajax 的核心觀念
(Asynchronous)與所使用到的主要兩個技術(JavaScript、XML)。
要達到 Asynchronous 利用的就是 JavaScript 中的XMLHttpRequest 物件。
XMLHttpRequest:
在 JavaScript 中利用new XMLHttpRequest()語法建立。包含下列幾個標準屬性-
onreadystatechange
參考至callback函式,readyState每次改變時,都會呼叫onreadystatechange所參考的函式。
readyState
會有0到4的數值,分別表示不同的請求狀態:
0 = 未初始化的連線(uninitialized),還沒呼叫open()
1 = 載入中(loading),呼叫open(),還沒呼叫send()
2 = 已載入(loaded),呼叫send(),請求header/status準備好
3 = 互動中(interactive),正在與伺服器互動中
4 = 請求完成(completed),完成請求
responseText
伺服器傳來的請求回應文字,會設定給這個屬性。
responseXML
伺服器傳來的請求回應如果是XML,會成為DOM設定給這個屬性。
status
伺服器回應的狀態碼,例如200是OK,404為Not Found…
statusText
伺服器回應的狀態文字。
接下來我們實際寫個web頁面來發送XMLHttpRequestonreadystatechange
參考至callback函式,readyState每次改變時,都會呼叫onreadystatechange所參考的函式。
readyState
會有0到4的數值,分別表示不同的請求狀態:
0 = 未初始化的連線(uninitialized),還沒呼叫open()
1 = 載入中(loading),呼叫open(),還沒呼叫send()
2 = 已載入(loaded),呼叫send(),請求header/status準備好
3 = 互動中(interactive),正在與伺服器互動中
4 = 請求完成(completed),完成請求
responseText
伺服器傳來的請求回應文字,會設定給這個屬性。
responseXML
伺服器傳來的請求回應如果是XML,會成為DOM設定給這個屬性。
status
伺服器回應的狀態碼,例如200是OK,404為Not Found…
statusText
伺服器回應的狀態文字。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>動態載入清單</title> <script type="text/javascript" src=dynamicList.js></script> </head> <body> 語言… <br/> <select id="langs" onchange="refreshList();"> <option value="func">功能說明</option> <option value="java">Java</option> <option value="c#">C#</option> </select> <br/><br/> 相關技術… <br/> <select id="techs" size="6" style="width:300px;"/> </body> </html>主要功能是選擇 id 為 langs 的 select html 元件時,會利用 Ajax 去後端 server 取得
相關資料,非同步的更動 id 為 techs 的 select html元件。
另外主要功能的JavaScript是利用
<script type="text/javascript" src=dynamicList.js></script>來引入。
var xmlHttp; window.onload = refreshList; function createXMLHttpRequest() { if(window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else if(window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } } function prepareXML() { var xml = "<langs>"; var lang = document.getElementById("langs").value; xml = xml + "<lang>" + lang + "<\/lang>"; xml = xml + "<\/langs>"; return xml; } function refreshList() { var xml = prepareXML(); var url = "refreshservlet"; createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.open("POST", url); xmlHttp.setRequestHeader("Content-Type", "text/xml"); xmlHttp.send(xml); } function handleStateChange() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { clearList(); updateList(); } } } // 清除上一次的顯示結果 function clearList() { var techs = document.getElementById("techs"); while(techs.childNodes.length > 0) { techs.removeChild(techs.childNodes[0]); } } // 以回應更新資料 function updateList() { var results = xmlHttp.responseXML.getElementsByTagName("tech"); var techs = document.getElementById("techs"); var option = null; for(var i = 0; i < results.length; i++) { option = document.createElement("option"); option.appendChild(document.createTextNode(results[i].firstChild.nodeValue)); techs.appendChild(option); } }由上面我們可以看到將XMLHttpRequest的onreadystatechange屬性
註冊到handleStateChange method,並利用post機制傳送XML格式的資料。
而所謂的XML格式資料其實就是符合XML規格的字串資料。
因為非同步的資料皆由XMLHttpRequest所控制,所以server回傳資料
也是由 XMLHttpRequest 的 responseXML 屬性取得。
接下來我們用一個servlet來接收並回傳由client端發送來的資料。
public class RefreshServlet extends HttpServlet { private static Map inMemoryDB = new HashMap(); public void init() throws ServletException { inMemoryDB.put("func", new String[] { "非同步", "動態清單" }); inMemoryDB.put("java", new String[] { "JSP", "J2EE", "Spring", "Hibernate" }); inMemoryDB.put("c#", new String[] { "ASP.Net", "ADO.Net" }); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String xml = readXMLFromRequestBody(request); Document xmlDoc = null; try { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); xmlDoc = builder.parse(new ByteArrayInputStream(xml.getBytes())); } catch (ParserConfigurationException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } String responseXML = prepareXMLResponse(xmlDoc); response.setContentType("text/xml;charset=utf-8"); response.getWriter().print(responseXML); response.getWriter().close(); } private String readXMLFromRequestBody(HttpServletRequest request) { StringBuffer xml = new StringBuffer(); try { BufferedReader reader = request.getReader(); String line = null; while ((line = reader.readLine()) != null) { xml.append(line); } } catch (Exception e) { System.out.println("XML讀取有誤…" + e.toString()); } return xml.toString(); } private String prepareXMLResponse(Document xmlDoc) { NodeList langNodes = xmlDoc.getElementsByTagName("langs"); String lang = langNodes.item(0).getFirstChild().getTextContent(); StringBuffer xml = new StringBuffer(); xml.append("<techs>"); String[] techs = (String[])inMemoryDB.get(lang); for (int i = 0; i < techs.length; i++) { xml.append("<tech>"); xml.append(techs[i]); xml.append("</tech>"); } xml.append("</techs>"); return xml.toString(); } }
因為XML也是字串資料,所以我們先用reader讀入
BufferedReader reader = request.getReader();
String line = null;
while ((line = reader.readLine()) != null) {
xml.append(line);
}
接著利用 DocumentBuilder 來解析每個tag的資料
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
xmlDoc = builder.parse(new ByteArrayInputStream(xml.getBytes()));
最後也是利用 StringBuffer 將查詢到的資料組成XML格式的字串資料回傳。
沒有留言:
張貼留言