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格式的字串資料回傳。
沒有留言:
張貼留言