本节内容来自沈泽刚等Javaweb编程技术一书的十五章。
一、XMLHttpRequest对象
1.创建对象。
function createXMLHttpRequest(){ if(window.ActiveXObject){ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xmlHttp = new XMLHttpRequest(); }
onreadystatechange:为异步请求设置事件处理程序来响应。当请求的状态改变时都会触发这个事件处理器,通常会调用一个javaScript函数,称为回调函数。
readyState:该属性表述请求的状态。0表示未初始化,1表示正在加载,2表示已加载,3表示交互中,4表示完成。
responseText:检索服务器响应,表示为文本。
responseXML:检索服务器响应,表示为XML
status:服务器的HTTP状态。
open(stringmethod,stringurl,booleanasych):指定使用的HTTP方法和请求的资源(服务器的URL,可以是动态资源或者是静态资源),确定这个调用时异步还是同步。将readyState属性设置1,正在加载。这样就打开了HTTP请求。
send(data):向服务器发送请求,并检索响应。此方法的返回值根据open()方法的asych参数是同步或异步有所不同。同步的话,只有在接收到全部响应之后才返回,异步的话立即返回。调用此方法后readyState属性设置为2,已加载,当请求完成时,该属性设置为4.
3.一般的Ajax具体过程
3.1.客户触发事件。
3.2创建XMLHttpRequest对象
3.3向服务器发出请求
3.4服务器处理请求并返回响应
3.5通过回调函数处理结果
3.6更新HTMLDOM对象
4.几个例子
4.1使用XMLHttpRequest对象的responseText属性,显示静态文本的内容。
a)写xml文件。(simpleResponse.xml)
<?xml version = "1.0" encoding = "utf-8" standalone ="no"?> <greetings> <haha>aha!</haha> <hello>world !</hello> </greetings>
b)写表单
<form action="#"> <input type = "button" value = "started asynchronuos " onclick = "startRequest();"> </form>
c)处理单击事件
createXMLHttpRequest();//生成XMLHttpRequest对象 //alert("start sure? " ); xmlHttp.onreadystatechange = handleStateChange;//写回调函数处理请求的状态改变时的响应事件。 //alert("end start sure? " ); xmlHttp.open("GET","simpleResponse.xml",true); xmlHttp.send(null); } function handleStateChange(){ //alert("hand start sure? " ); if(xmlHttp.readyState == 4){ //alert(xmlHttp.status); if(xmlHttp.status == 200){ alert("server returned with: " + xmlHttp.responseText); } } }
4.2使用XMLHttpRequest对象的responseText属性和HTML元素的innerHTML属性,创建动态内容。
a)写xml文件。(innerHTML.xml)
<?xml version="1.0" encoding="UTF-8"?> <xml-body> <table border= "1"> <tr> <td>学号</td> <td>姓名</td> <td>性别</td> <td>年龄</td> </tr> <tr> <td>20080101</td> <td>li ming</td> <td>male</td> <td>21</td> </tr> <tr> <td>20080102</td> <td>zhang ming</td> <td>male</td> <td>21</td> </tr> <tr> <td>20080111</td> <td>wang ming</td> <td>female</td> <td>23</td> </tr> </table> </xml-body>
<form > <input type = "button" value ="search student" onclick = "startRequest();"> </form> <div id="results"></div>
c)处理单击事件
function startRequest(){ createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.open("get","innerHTML.xml",true); xmlHttp.send(null); } function handleStateChange(){ if (xmlHttp.readyState == 4) if(xmlHttp.status == 200) { document.getElementById("results").innerHTML = xmlHttp.responseText; } }
二、DOM文档对象类型。
用于处理XML文档的DOM元素属性和方法
childNodes:返回当前元素所有子元素的数组
firstChild:返回当前元素的第一个下级子元素
nodeValue:返回结点值
getElementById(id):返回文档中由id指定的元素
getElementsByTagName(name):返回当前元素中由指定标记名的子元素的数组
hasChildNodes():返回一个布尔值,指示元素是否有子元素
getAttribute(name):返回指定名称的元素的属性值
用于动态常见内容的DOM属性和方法
document.createElement(tagName):创建由tagName指定的元素
document.creatTextNode(text):创建一个包含静态文本的节点
<element>.appendChild(childNode):将指定的节点添加到当前元素的子节点列表,作为一个新的子节点
<element>.hasChildNodes():返回一个布尔值,判断该元素是否有子元素
<element>.getAttribute(name):获得元素中name属性的值
<element>.setAttribute(name,value):设置元素中name属性的值
<element>..removeAttribute(name)从元素中删除属性
<element>.removeChild(chileNode):从元素中删除子元素
1.几个例子
1.1使用XMLHttpRequest对象的responseXML属性,将结果获取为xml文档,然后使用DOM方法遍历XML文档中的元素,实现静态读取xml节点元素值。
a)写xml文件.(library.xml)
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <library> <books> <book id ="100" > <name>Database System Concept</name> <author>Abraham Silberschatz</author> <year>2006.10</year> <price>69.50</price> </book> <book id ="103" > <name>A Instruction Of Database System </name> <author>Wang Shan</author> <year>2006.5</year> <price>33.80</price> </book> </books> <magazines> <magazine> <name>Application Research Of Computers</name> <author>chengcheng</author> <year no ="1">2004.10</year> <volume>21</volume> <price>147</price> </magazine> </magazines> </library>
b)写表单。
<body> <h4>Processing XML Document of Publishing</h4> <form action="#"> <input type ="button" value ="search book" onclick = "startRequest('books');"/> <input type ="button" value ="search magazine" onclick = "startRequest('magazines');"/> </form> </body>
c)处理单击事件
<script type="text/javascript"> var xmlHttp; var requestType =""; function createXMLHttpRequest(){ if(window.ActiveXObject){ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xmlHttp = new XMLHttpRequest(); } } function startRequest(requestedList){ requestType = requestedList; createXMLHttpRequest(); xmlHttp.onreadystatechange = handlerRequest; xmlHttp.open("get","library.xml",true); xmlHttp.send(null); } function handlerRequest(){ if(xmlHttp.readyState == 4){ if(xmlHttp.status == 200){ if(requestType == "books"){ listBooks();//显示book标签的信息 } else if(requestType == "magazines"){ listMagazines();//显示magazines标签的信息 } } } } function listBooks(){ var xmlDoc = xmlHttp.responseXML; //alert("xml "+xmlDoc); var bookNode = xmlDoc.getElementsByTagName("books")[0]; var allBook = bookNode.getElementsByTagName("book"); outputList("All Books",allBook);//输出当前books标签第一个子元素book的第一个子元素的值 } function listMagazines(){ var xmlDoc = xmlHttp.responseXML; var magazineNode = xmlDoc.getElementsByTagName("magazines")[0]; var allMagazine = magazineNode.getElementsByTagName("magazine"); outputList("AllMagazine",allMagazine); } function outputList(title,items){ var out = title;//out存放的是初始定值。 var currentItem = null; for(var i = 0; i < items.length; i++){ currentItem = items[i]; //alert(currentItem.childNodes[0].firstChild.nodeValue) out = out +"\n-"+currentItem.childNodes[0].firstChild.nodeValue; } alert(out); } </script>
1.2使用DOM和Javascript动态的创建内容
a)写xml文件.(library.xml)
b)写表单和动态显示的表格
<body> <h4>Search Books And Magazines</h4> <form action="#"> <input type ="button" value="search books" onclick="startSearch('books')"> <input type ="button" value="search magazines" onclick="startSearch('magazines')"> </form> <span id = "header"></span> <table id = "resultsTable" border = "0"> <tbody id = "resultsBody"> </tbody> </table> </body>
c)处理单击事件
<script type="text/javascript"> var xmlHttp ; var requestType =""; function createXMLHttpRequest(){ if(window.ActiveXObject){ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xmlHttp = new XMLHttpRequest(); } } function startSearch(requestedList){ requestType = requestedList; createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.open("get",true); xmlHttp.send(null); } function handleStateChange(){ if(xmlHttp.readyState == 4 && xmlHttp.status == 200){ clearResults();//清空上次生成的表格 parseResults();//生成表格 } } function clearResults(){ var header = document.getElementById("header"); if(header.hasChildNodes()){ header.removeChild(header.childNodes[0]); } var tableBody = document.getElementById("resultsBody"); while(tableBody.childNodes.length > 0){ tableBody.removeChild(tableBody.childNodes[0]); } } function parseResults(){ var results = xmlHttp.responseXML;//results变量获得xml文档内容 var items = null; var item = null; var name =""; var author = ""; var year= ""; var price =""; var books = null; var magazines = null; if (requestType == "books"){ books = results.getElementsByTagName("books"); items = books[0].getElementsByTagName("book"); } else if(requestType =="magazines"){ magazines = results.getElementsByTagName("magazines"); items = magazines[0].getElementsByTagName("magazine"); } for(var i =0; i <items.length; i++){ item = items[i]; name = item.getElementsByTagName("name")[0].firstChild.nodeValue; author = item.getElementsByTagName("author")[0].firstChild.nodeValue; year = item.getElementsByTagName("year")[0].firstChild.nodeValue; price = item.getElementsByTagName("price")[0].firstChild.nodeValue; addTableRow(name,author,year,price);//创建表格中一行 } var header = document.createElement("h4"); var headerText = document.createTextNode("Results:"); header.appendChild(headerText); document.getElementById("header").appendChild(header); document.getElementById("resultsTable").setAttribute("border","1"); } function addTableRow(name,price){ var row = document.createElement("tr"); var cell = createCellWithText(name);//创建表格中一列 row.appendChild(cell); var cell = createCellWithText(author); row.appendChild(cell); var cell = createCellWithText(year); row.appendChild(cell); var cell = createCellWithText(price); row.appendChild(cell); document.getElementById("resultsBody").appendChild(row); } function createCellWithText(text){ var cell = document.createElement("td"); var textNode = document.createTextNode(text); cell.appendChild(textNode); return cell; } </script>
三、几个应用例子
1.实现表单数据验证
1.1写表单
<body> <h4>Ajax 数据验证示例</h4> 用户名:<input type= "text" size = "10" id= "username"> <input type = "button" value ="检测" onclick ="validate();"> <div id = "results"></div> </body>
1.2编写服务器端的代码。(ValidationServlet.java,自动生成web,xml相关的配置)
public class ValidationServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException { resp.setContentType("text/xml");//由于XMLHttpRequest对象只能处理text/html类型的结果,请求的是动态资源,必须将Content-type响应头设置为text/html。 resp.setHeader("Cache-Control","no-cache");//避免浏览器再本地缓存结果 String username= req.getParameter("username"); //System.out.println(username); String message = "The name has not been used"; PrintWriter out = resp.getWriter(); if(username.equals("hacker")){ message ="The name has been used"; } out.println("<response>");//生成response标签 out.println("<message>"+message+"</message>");//生成message元素 out.println("</response>"); } }
1.3处理单击事件
function validate(){ createXMLHttpRequest(); var username = document.getElementById("username"); //alert(username.value); var url ="ValidationServlet?username="+ escape(username.value);//请求的是动态资源(servlet) //alert(url); xmlHttp.open("get",url,true); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.send(null); } function handleStateChange(){ if(xmlHttp.readyState == 4 && xmlHttp.status ==200){ var message = xmlHttp.responseXML.getElementsByTagName("message")[0].firstChild.data; var messageArea = document.getElementById("results"); messageArea.innerHTML ="<h4>" + message +"</h4>"; } }
2.动态加载列表框
2.1.写表单
<body> <h4>请选择着入学年份和班级</h4> <form action="#"> 入学年份: <select id = "syear" onchange ="refreshNameList();"> <option value= "">请选择</option> <option value ="2008">2008</option> <option value = "2009">2009</option> </select> 班级: <select id = "sclass" onchange ="refreshNameList();"> <option value = "">请选择</option> <option value ="class1">一班</option> <option value ="class2">二班</option> </select> <br/><br/> 姓名: <br/> <select id ="snames" size ="6" style ="width:270px;"></select> </form> </body>
2.2编写服务器端的代码。(refreshNameServlet.java)
public class refreshNameServlet extends HttpServlet { private static class Student{ private int syear; private String sclass; private String sname; public Student(int syear,String sclass,String sname){ this.syear=syear; this.sclass=sclass; this.sname=sname; } } private static List<Student> student = new ArrayList<Student>(); @Override public void init() throws ServletException {//此处姓名如果写成中文就乱码。没有解决,tbc student.add(new Student(2008,"class1","jerry")); student.add(new Student(2008,"peter")); student.add(new Student(2008,"tomcat")); student.add(new Student(2008,"ketty")); student.add(new Student(2008,"too")); student.add(new Student(2008,"class2","wuet")); student.add(new Student(2008,"wute")); student.add(new Student(2008,"atat")); student.add(new Student(2008,"luews")); student.add(new Student(2008,"Htnry Jordon")); student.add(new Student(2008,"karta")); student.add(new Student(2008,"LuSmitn")); } @Override protected void doGet(HttpServletRequest req,IOException { processRequest(req,resp); } protected void processRequest(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException { int syear =Integer.parseInt(req.getParameter("syear")); String sclass = req.getParameter("sclass"); StringBuffer results = new StringBuffer("<snames>");//生成snames标签 Student stud = null; for(Iterator it = student.iterator();it.hasNext();){ stud =(Student)it.next(); if(syear == stud.syear){ if(stud.sclass.equals(sclass)){//生成sname标签,不断追加sname值 results.append("<sname>"); results.append(stud.sname); results.append("</sname>"); } } } results.append("</snames>"); resp.setContentType ("text/xml"); resp.getWriter().println(results.toString()); } } }
web.xml配置servlet如下:
<servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>refreshNameServlet</servlet-name> <servlet-class>com.smg.domain.refreshNameServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>refreshNameServlet</servlet-name> <url-pattern>/go</url-pattern> </servlet-mapping>
2.3.处理单击事件
<script type="text/javascript"> var xmlHttp; function createXMLHttpRequest(){ if(window.ActiveXObject){ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xmlHttp = new XMLHttpRequest(); } } function refreshNameList(){ var syear = document.getElementById("syear").value; var sclass = document.getElementById("sclass").value; if(sclass =="" || syear == ""){//如果没有选班级或者入学年份,下拉列表清空 clearNameList();//清空下拉列表 return; } var url = "go?"+createQueryString(sclass,syear) + "&ts=" + new Date().getTime(); // alert(url); createXMLHttpRequest(); xmlHttp.open("get",true); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.send(null); } function createQueryString(sclass,syear){//返回请求资源键值对 var queryString = "sclass="+sclass +"&syear="+syear; return queryString; } function handleStateChange(){ if(xmlHttp.readyState == 4 && xmlHttp.status ==200){ updateNameList(); //匹配入学年份和班级相同的学生的姓名,并显示出来。 } } function updateNameList(){ clearNameList(); var snames = document.getElementById("snames"); var results = xmlHttp.responseXML.getElementsByTagName("sname"); var option = null; for(var i = 0; i < results.length; i++){ option = document.createElement("option"); option.appendChild(document.createTextNode(results[i].firstChild.nodeValue)); snames.appendChild(option); } } function clearNameList(){ var snames = document.getElementById("snames"); while(snames.childNodes.length > 0){ snames.removeChild(snames.childNodes[0]); } } </script>
3.动态更新web页面
3.1写表单
<body> <h3>请输入客户信息</h3> <form action="#"> <table border ="0"> <tr> <td>客户名:</td> <td><input type="text" id ="custName"></td> </tr> <tr> <td>Email地址:</td> <td><input type="text" id ="email"></td> </tr> <tr> <td>电话:</td> <td><input type="text" id ="phone"></td> </tr> <tr><td><input type ="button" value="添加" onclick="addCustomer();"></td></tr> </table> </form> <span id = "customerListSpan" stytle ="display:none;"> <h3>客户信息如下:</h3> <table border ="1"> <tbody id ="customerList"> </tbody> </table> </span> </body>
3.2编写服务器端的代码。(CustomerServlet.java,自动生成web,xml相关的配置
public class CustomerServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req,IOException { String action = req.getParameter("action"); if(action.equals("add")){ addCustomer(req,resp); } else if(action.equals("delete")){ deleteCustomer(req,resp); } } protected void addCustomer(HttpServletRequest req,IOException { String uniqueID = storeCustomer(); StringBuffer xml = new StringBuffer("<result><uniqueID>");//生成result和uniqueID标签。创建响应XML xml.append(uniqueID); xml.append("</uniqueID>"); xml.append("<status>1</status>");//生成status标签 值设为1,恰好与请求状态为正加载的吻合 xml.append("</result>"); sendResponse(resp,xml.toString());//向浏览器发送响应 } private String storeCustomer() { String uniqueID = ""; Random randomizer = new Random(System.currentTimeMillis());//通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字。 for(int i = 0; i <8;i++){ uniqueID += randomizer.nextInt(9);//通过Random对象获取获取[0,9)之间的int整数 } return uniqueID;//获取8位不重复随机数,作为uniqueID。http://www.cnblogs.com/skywang12345/p/3341423.html } private void sendResponse(HttpServletResponse resp,String responseText) throws IOException { resp.setContentType("text/xml"); resp.getWriter().println(responseText); } protected void deleteCustomer(HttpServletRequest req,IOException { String id =req.getParameter("id"); StringBuffer xml = new StringBuffer("<result>");//生成result标签 xml.append("<status>1</status>");//生成status标签 值设为1,恰好与请求状态为正加载的吻合 xml.append("</result>"); sendResponse(resp,xml.toString()); } }
3.3处理单击事件
<script type="text/javascript"> var xmlHttp; var custName; var email; var phone; var deleteID; var PREFIX="cust-"; function createXMLHttpRequest(){ if(window.ActiveXObject){ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xmlHttp = new XMLHttpRequest(); } } function addCustomer(){ custName = document.getElementById("custName").value; email = document.getElementById("email").value; phone = document.getElementById("phone").value; action = "add"; if(custName == "" || email == "" || phone == ""){//如果输入的客户信息为空,不操作 return; } var url ="CustomerServlet?" + createAddQueryString(custName,email,phone,action)+"&ts="+new Date().getTime(); createXMLHttpRequest(); xmlHttp.onreadystatechange = handleAddStateChange;//添加按钮的回调函数 xmlHttp.open("get",true); xmlHttp.send(null); } function createAddQueryString(custName,action){//返回请求资源键值对 var queryString = "custName=" +custName+"&email="+email+"&phone="+phone+"&action="+action; return queryString; } function handleAddStateChange(){ if (xmlHttp.readyState == 4) if(xmlHttp.status == 200) { updateCustomerList();//添加客户信息到下拉列表 clearInputBoxes();//添加完客户信息到列表之后,清空之前输入的客户信息 } else { alert("添加客户错误!"); } } function updateCustomerList(){ var responseXML = xmlHttp.responseXML; var status = responseXML.getElementsByTagName("status")[0].firstChild.nodeValue; status = parseInt(status); if(status != 1){//表示响应的xml还没有成功生成。 return; } var row = document.createElement("tr");//创建列表中的行 var uniqueID = responseXML.getElementsByTagName("uniqueID")[0].firstChild.nodeValue; row.setAttribute("id",PREFIX+uniqueID); row.appendChild(createCellWithText(custName));//追加行中的值 row.appendChild(createCellWithText(email)); row.appendChild(createCellWithText(phone)); var deleteButton = document.createElement("input");//创建删除按钮 deleteButton.setAttribute("type","button"); deleteButton.setAttribute("value","删除"); deleteButton.onclick=function(){ deleteCustomerID(uniqueID); } cell =document.createElement("td"); cell.appendChild(deleteButton); row.appendChild(cell);//在行尾追加删除按钮这一列 document.getElementById("customerList").appendChild(row);//在HTML中添加新增加的客户信息这一列 updateCustomerListVisibility(); } function createCellWithText(text){//创建一列元素 var cell = document.createElement("td"); cell.appendChild(document.createTextNode(text)); return cell; } function deleteCustomerID(id){ deleteID = id; var url = "CustomerServlet?action=delete"+"&id="+id+"&ts="+new Date().getTime(); createXMLHttpRequest(); xmlHttp.onreadystatechange = handleDeleteStateChange;//删除按钮的回调函数 xmlHttp.open("get",true); xmlHttp.send(null); } function handleDeleteStateChange(){ if (xmlHttp.readyState == 4) if(xmlHttp.status == 200) { deleteCustomerFromSList();//处理删除一列 } else { alert("删除客户错误!"); } } function deleteCustomerFromSList(){ var status = xmlHttp.responseXML.getElementsByTagName("status")[0].firstChild.nodeValue; status = parseInt(status); if(status != 1){ return; } var rowToDelete = document.getElementById(PREFIX +deleteID); var customerList = document.getElementById("customerList"); customerList.removeChild(rowToDelete); updateCustomerListVisibility(); } function updateCustomerListVisibility(){ var customerList = document.getElementById("customerList"); if(customerList.childNodes.length > 0){ document.getElementById("customerListSpan").style.display ="";//当该列有元素时清除display样式 } else{ document.getElementById("customerListSpan").style.display ="none";//当该列无元素时,不显示表示元素将隐藏 } } function clearInputBoxes(){ document.getElementById("custName").value= ""; document.getElementById("email").value=""; document.getElementById("phone").value=""; } </script>