1. 程式人生 > >Ajax入門與應用

Ajax入門與應用

一、Ajax介紹

1. ajax是什麼?
  * asynchronous javascript and xml:非同步的js和xml
  * 它能使用js訪問伺服器,而且是非同步訪問!
  * 伺服器給客戶端的響應一般是整個頁面,一個html完整頁面!但在ajax中因為是區域性重新整理,那麼伺服器就不用再響應整個頁面!而只是資料!
    > text:純文字
    > xml:大家都熟悉!!!
    > json:它是js提供的資料互動格式,它在ajax中最受歡迎!

2. 非同步互動和同步互動
  * 同步:
    > 發一個請求,就要等待伺服器的響應結束,然後才能發第二個請求!中間這段時間就是一個字“卡”
    > 重新整理的是整個頁面!
  * 非同步:
    > 發一個請求後,無需等待伺服器的響應,然後就可以發第二個請求!
    > 可以使用js接收伺服器的響應,然後使用js來區域性重新整理!

3. ajax應用場景
  * 百度的搜尋框
  * 使用者註冊時(校驗使用者名稱是否被註冊過)

4. ajax的優缺點
  優點:
  * 非同步互動:增強了使用者的體驗!
  * 效能:因為伺服器無需再響應整個頁面,只需要響應部份內容,所以伺服器的壓力減輕了!

  缺點:
  * ajax不能應用在所有場景!
  * ajax無端的增多了對伺服器的訪問次數,給伺服器帶來了壓力!

 二、非同步請求四步操作

ajax傳送非同步請求(四步操作)

1. 第一步(得到XMLHttpRequest)
  * ajax其實只需要學習一個物件:XMLHttpRequest,如果掌握了它,就掌握了ajax!!!
  * 得到XMLHttpRequest
    > 大多數瀏覽器都支援:var xmlHttp = new XMLHttpRequest();
    > IE6.0:var xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    > IE5.5以更早版本的IE:var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

  * 編寫建立XMLHttpRequest物件的函式
  function createXMLHttpRequest() {
      try {
          return new XMLHttpRequest();
      } catch(e) {
          try {
	      return new ActiveXObject("Msxml2.XMLHTTP");
	  } catch(e) {
	      try {
	          return new ActiveXObject("Microsoft.XMLHTTP");
	      } catch(e) {
	          alert("哥們兒,你用的是什麼瀏覽器啊?");
	          throw e;
	      }
	  }
      }
  }

2. 第二步(開啟與伺服器的連線)
  * xmlHttp.open():用來開啟與伺服器的連線,它需要三個引數:
    > 請求方式:可以是GET或POST
    > 請求的URL:指定伺服器端資源,例如;/day23_1/AServlet
    > 請求是否為非同步:如果為true表示傳送非同步請求,否則同步請求!
  * xmlHttp.open("GET", "/day23_1/AServlet", true);

3. 第三步(傳送請求)
  * xmlHttp.send(null):如果不給可能會造成部份瀏覽器無法傳送!
    > 引數:就是請求體內容!如果是GET請求,必須給出null。

4. 第四步()
  * 在xmlHttp物件的一個事件上註冊監聽器:onreadystatechange
  * xmlHttp物件一共有5個狀態:
    > 0狀態:剛建立,還沒有呼叫open()方法; 
    > 1狀態:請求開始:呼叫了open()方法,但還沒有呼叫send()方法
    > 2狀態:呼叫完了send()方法了;
    > 3狀態:伺服器已經開始響應,但不表示響應結束了!
    > 4狀態:伺服器響應結束!(通常我們只關心這個狀態!!!)
  * 得到xmlHttp物件的狀態:
    > var state = xmlHttp.readyState;//可能是0、1、2、3、4
  * 得到伺服器響應的狀態碼
    > var status = xmlHttp.status;//例如為200、404、500
  * 得到伺服器響應的內容1
    > var content = xmlHttp.responseText;//得到伺服器的響應的文字格式的內容
    > var content = xmlHttp.responseXML;//得到伺服器的響應的xml響應的內容,它是Document物件了!

  xmlHttp.onreadystatechange = function() {//xmlHttp的5種狀態都會呼叫本方法
      if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {//雙重判斷:判斷是否為4狀態,而且還要判斷是否為200
          // 獲取伺服器的響應內容
	  var text = xmlHttp.responseText;
      }
  };

5. 傳送POST請求(如果傳送請求時需要帶有引數,一般都用POST請求)
  * open:xmlHttp.open("POST" ....);
  * 新增一步:設定Content-Type請求頭:
  > xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  * send:xmlHttp.send("username=zhangSan&password=123");//傳送請求時指定請求體

 三、案例

 案例一、驗證使用者名稱是否存在

============================Ajax.jsp
<script type="text/javascript">
window.onload = function(){
	//獲取文字
	var username = document.getElementById("usernameEle");
	//聚焦事件監聽
	username.onblur = function(){
		//建立非同步更新物件
		var xmlHttp = createXMLHttpRequest();
		//與伺服器建立連線
		xmlHttp.open("POST","<c:url value='/ValidateUsernameJudge'/>",true);
		//設定請求頭
		xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); 
		//傳送請求
		xmlHttp.send("username="+username.value);
		//設定事件監聽
		xmlHttp.onreadystatechange = function(){
		//雙重判斷
			if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
				//狀態正確獲取響應內容
			 	 var text = xmlHttp.responseText;
			 	 var span = document.getElementById("errorusername");
			 	 if(text == "1"){
			 	 	span.innerHTML = "使用者名稱已存在,請重新輸入!";
			 	 }else{
			 		 span.innerHTML = "";
			 	 }
			}		
		};
	};
};
function createXMLHttpRequest(){
	try{
		return new XMLHttpRequest();
	}catch(e){
		try{
			return new ActiveXObject("Msxml2.XMLHTTP");
		}catch(e){
			try{
				return new ActiveXObject("Microsoft.XMLHTTP");
			}catch(e){
				alert("非同步物件建立失敗");
				throw e ;
			}
		}
	}
}

    <h2>  非同步判斷使用者名稱是否存在   </h2>
    <form action="/ValidateUsernameJudge" method="post">
    	username:<input type="text" id="usernameEle" name="username"/><span id="errorusername"></span><br>
    	password:<input type="password" id="passwordEle" name="password"/><br>
    	<input type="submit" value="註冊"/>
    </form>

============================ValidateUsernameJudge.java
public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	request.setCharacterEncoding("utf-8");
	response.setContentType("text/html;charset=utf-8");
	/*
	 * 1. 獲取引數username
	 * 2. 判斷是否為itcast
	 *   3. 如果是:響應1
	 *   4. 如果不是:響應0
	 */
	String username = request.getParameter("username");
	if(username.equalsIgnoreCase("itcast")) {
		response.getWriter().print("1");
	} else {
		response.getWriter().print("0");
	}
}

 案例二、省市聯動china.xml

===============================ajax.jsp
<script type="text/javascript">
function createXMLHttpRequest() {
	try {
		return new XMLHttpRequest();//大多數瀏覽器
	} catch (e) {
		try {
			return ActvieXObject("Msxml2.XMLHTTP");//IE6.0
		} catch (e) {
			try {
				return ActvieXObject("Microsoft.XMLHTTP");//IE5.5及更早版本	
			} catch (e) {
				alert("哥們兒,您用的是什麼瀏覽器啊?");
				throw e;
			}
		}
	}
}
/*
 * 1. 在文件載入完畢時傳送請求,得到所有省份名稱,顯示在<select name="province"/>中
 * 2. 在選擇了新的省份時,傳送請求(引數為省名稱),得到xml文件,即<province>元素
 *   解析xml文件,得到其中所有的<city>,再得到每個<city>元素的內容,即市名,使用市名生成<option>,插入到<select name="city">元素中
 */

window.onload = function() {
	/*
	ajax四步,請求ProvinceServlet,得到所有省份名稱
	使用每個省份名稱建立一個<option>元素,新增到<select name="province">中
	*/
	var xmlHttp = createXMLHttpRequest();
	xmlHttp.open("GET", "<c:url value='/ProvinceServlet'/>", true);
	xmlHttp.send(null);
	xmlHttp.onreadystatechange = function() {
		if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
			// 獲取伺服器的響應
			var text = xmlHttp.responseText;
			// 使用逗號分隔它,得到陣列
			var arr = text.split(",");
			// 迴圈遍歷每個省份名稱,每個名稱生成一個option物件,新增到<select>中
			for(var i = 0; i < arr.length; i++) {
				var op = document.createElement("option");//建立一個指名名稱元素
				op.value = arr[i];//設定op的實際值為當前的省份名稱
				var textNode = document.createTextNode(arr[i]);//建立文字節點
				op.appendChild(textNode);//把文字子節點新增到op元素中,指定其顯示值
				
				document.getElementById("p").appendChild(op);
			}
		}
	};
	
	
	/*
	第二件事情:給<select name="province">新增改變監聽
	使用選擇的省份名稱請求CityServlet,得到<province>元素(xml元素)!!!
	獲取<province>元素中所有的<city>元素,遍歷之!獲取每個<city>的文字內容,即市名稱
	使用每個市名稱建立<option>元素新增到<select name="city">
	*/
	var proSelect = document.getElementById("p");
	proSelect.onchange = function() {
		var xmlHttp = createXMLHttpRequest();
		xmlHttp.open("POST", "<c:url value='/CityServlet'/>", true);
		xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xmlHttp.send("pname=" + proSelect.value);//把下拉列表中選擇的值傳送給伺服器!
		xmlHttp.onreadystatechange = function() {
			if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
				/*
				把select中的所有option移除(除了請選擇)
				*/
				var citySelect = document.getElementById("c");
				// 獲取其所有子元素
				var optionEleList = citySelect.getElementsByTagName("option");
				// 迴圈遍歷每個option元素,然後在citySelect中移除
				while(optionEleList.length > 1) {//子元素的個數如果大於1就迴圈,等於1就不迴圈了!
					citySelect.removeChild(optionEleList[1]);//總是刪除1下標,因為1刪除了,2就變成1了!
				}
				
				
				var doc = xmlHttp.responseXML;
				// 得到所有名為city的元素
				var cityEleList = doc.getElementsByTagName("city");
				// 迴圈遍歷每個city元素
				for(var i = 0; i < cityEleList.length; i++) {
					var cityEle = cityEleList[i];//得到每個city元素
					var cityName;
					// 獲取市名稱
					if(window.addEventListener) {//處理瀏覽器的差異
						cityName = cityEle.textContent;//支援FireFox等瀏覽器
					} else {
						cityName = cityEle.text;//支援IE
					}
					
					// 使用市名稱建立option元素,新增到<select name="city">中
					var op = document.createElement("option");
					op.value = cityName;
					// 建立文字節點
					var textNode = document.createTextNode(cityName);
					op.appendChild(textNode);//把文字節點追加到op元素中
					
					//把op新增到<select>元素中
					citySelect.appendChild(op);
				}
			}
		};		
	};
};
</script>

<h1>省市聯動</h1>
<select name="province" id="p">
  <option>===請選擇省===</option>
</select>
   
<select name="city" id="c">
  <option>===請選擇市===</option>
</select>

===============================ProvinceServlet.java
public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		/*
		 * 響應所有省份名稱,使用逗號分隔!
		 */
		/*
		 * 1. Document物件
		 *   * 建立解析器物件
		 *   * 呼叫解析器的讀方法,傳遞一個流物件,得到Document
		 */
		try {
			SAXReader reader = new SAXReader();
			InputStream input = this.getClass().getResourceAsStream("/china.xml");
			Document doc = reader.read(input);
			
			/*
			 * 查詢所有province的name屬性,得到一堆的屬性物件
			 * 迴圈遍歷,把所有的屬性值連線成一個字串,傳送給客戶端
			 */
			List<Attribute> arrList = doc.selectNodes("//province/@name");
			StringBuilder sb = new StringBuilder();
			for(int i = 0; i < arrList.size(); i++) {
				sb.append(arrList.get(i).getValue());//把每個屬性的值存放到sb中。
				if(i < arrList.size() - 1) {
					sb.append(",");
				}
			}
			response.getWriter().print(sb);
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

===============================CityServlet.java
public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/xml;charset=utf-8");//注意:傳送xml這裡要修改!!!
		
		/*
		 * 獲取省份名稱,載入該省對應的<province>元素!
		 * 把元素轉換成字串傳送給客戶端
		 */
		/*
		 * 1. 獲取省份的名稱
		 * 2. 使用省份名稱查詢到對應的<province>元素
		 * 3. 把<province>元素轉換成字串,傳送!
		 */
		try {
			/*
			 * 得到Document
			 */
			SAXReader reader = new SAXReader();
			InputStream input = this.getClass().getResourceAsStream("/china.xml");
			Document doc = reader.read(input);
			
			/*
			 * 獲取引數
			 */
			String pname = request.getParameter("pname");//獲取省份名稱
			Element proEle = (Element) doc.selectSingleNode("//province[@name='" + pname + "']");
			String xmlStr = proEle.asXML();//把元素轉換成字串
			response.getWriter().print(xmlStr);
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}