摘要:AJAX即“Asynchronous Javascript And XML”(異步JavaScript和XML),是指一種建立互動式網頁應用的網頁開發技術。AJAX 是一種用于建立快速動态網頁的技術。通過在背景與伺服器進行少量資料交換,AJAX 可以使網頁實作異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。解決傳統的網頁(不使用 AJAX)如果需要更新内容,必須重載整個網頁頁面。
一、Ajax技術與原理
1.1、Ajax
AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
AJAX 不是新的程式設計語言,而是一種使用現有标準的新方法。
AJAX 是與伺服器交換資料并更新部分網頁的藝術,在不重新加載整個頁面的情況下。
1.2、Ajax所包含的技術
大家都知道ajax并非一種新的技術,而是幾種原有技術的結合體。它由下列技術組合而成。
1.使用CSS和XHTML來表示。
2. 使用DOM模型來互動和動态顯示。
3.使用XMLHttpRequest來和伺服器進行異步通信。
4.使用javascript來綁定和調用。
AJAX 的要點是 XMLHttpRequest 對象。
不同的浏覽器建立 XMLHttpRequest 對象的方法是有差異的。
IE 浏覽器使用
ActiveXObject
,而其他的浏覽器使用名為
XMLHttpRequest
的 JavaScript 内建對象
1.3、Ajax的工作原理
Ajax的核心是JavaScript對象XmlHttpRequest。該對象在Internet Explorer 5中首次引入,它是一種支援異步請求的技術。簡而言之,XmlHttpRequest使您可以使用JavaScript向伺服器提出請求并處理響應,而不阻塞使用者。
來看看和傳統方式的差別
再來看看它們各自的互動
浏覽器的普通互動方式
浏覽器的Ajax互動方式
在建立Web站點時,在用戶端執行螢幕更新為使用者提供了很大的靈活性。下面是使用Ajax可以完成的功能:
動态更新購物車的物品總數,無需使用者單擊Update并等待伺服器重新發送整個頁面。
提升站點的性能,這是通過減少從伺服器下載下傳的資料量而實作的。例如,在Amazon的購物車頁面,當更新籃子中的一項物品的數量時,會重新載入整個頁面,這必須下載下傳32K的資料。如果使用Ajax計算新的總量,伺服器隻會傳回新的總量值,是以所需的帶寬僅為原來的百分之一。
消除了每次使用者輸入時的頁面重新整理。例如,在Ajax中,如果使用者在分頁清單上單擊Next,則伺服器資料隻重新整理清單而不是整個頁面。
直接編輯表格資料,而不是要求使用者導航到新的頁面來編輯資料。對于Ajax,當使用者單擊Edit時,可以将靜态表格重新整理為内容可編輯的表格。使用者單擊Done之後,就可以發出一個Ajax請求來更新伺服器,并重新整理表格,使其包含靜态、隻讀的資料。
1.4、XMLHttpRequest 對象的三個常用的屬性
1. onreadystatechange 屬性
onreadystatechange 屬性存有處理伺服器響應的函數。
下面的代碼定義一個空的函數,可同時對 onreadystatechange 屬性進行設定:
[html]
view plain
copy
- xmlHttp.onreadystatechange=function()
- {
- // 我們需要在這裡寫一些代碼
- }
2.readyState 屬性
readyState 屬性存有伺服器響應的狀态資訊。每當 readyState 改變時,onreadystatechange 函數就會被執行。
readyState 屬性可能的值:
狀态 描述
0 請求未初始化(在調用 open() 之前)
1 請求已提出(調用 send() 之前)
2 請求已發送(這裡通常可以從響應得到内容頭部)
3 請求進行中(響應中通常有部分資料可用,但是伺服器還沒有完成響應)
4 請求已完成(可以通路伺服器響應并使用它)
我們要向這個 onreadystatechange 函數添加一條 If 語句,來測試我們的響應是否已完成(意味着可獲得資料):
- if(xmlHttp.readyState==4)
- // 從伺服器的response獲得資料
3.responseText 屬性
可以通過 responseText 屬性來取回由伺服器傳回的資料。
在我們的代碼中,我們将把時間文本框的值設定為等于 responseText:
- document.myForm.time.value=xmlHttp.responseText;
其它屬性如下:
1.5、xmlhttprequst的方法
1.open() 方法
open() 有三個參數。第一個參數定義發送請求所使用的方法,第二個參數規定伺服器端腳本的URL,第三個參數規定應當對請求進行異步地處理。具體看博文後面還有細講
- xmlHttp.open("GET","test.php",true);
2.send() 方法
send() 方法将請求送往伺服器。如果我們假設 HTML 檔案和 PHP 檔案位于相同的目錄,那麼代碼是這樣的:
- xmlHttp.send(null);
具體看博文後面還有細講。
其它方法如下:
二、Ajax程式設計步驟
為了友善了解,我給AJAX統一了一個流程,要想實作AJAX,就要按照以後步驟走:
(1)建立XMLHttp對象。
(2)設定請求方式。
(3)調用回調函數。
(4)發送請求。
下面來看下具體步驟:
2.1、建立XMLHttp對象
建立XMLHttp對象的文法是:
- var xmlHttp=new XMLHttpRequest();
如果是IE5或者IE6浏覽器,則使用ActiveX對象,建立方法是:
- var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
一般我們手寫AJAX的時候,首先要判斷該浏覽器是否支援XMLHttpRequest對象,如果支援則建立該對象,如果不支援則建立ActiveX對象。JS代碼如下:
- //第一步:建立XMLHttpRequest對象
- var xmlHttp;
- if (window.XMLHttpRequest) {//分浏覽器建立XMLHttp對象
- xmlHttp = new XMLHttpRequest();
- } else if (window.ActiveXObject) {
- xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
- }
2.2、設定請求方式
在WEB開發中,請求有兩種形式,一個是get 一個是post,是以在這裡需要設定一下具體使用哪個請求,XMLHttpRequest對象的open()方法就是來設定請求方式的。
open():
功能:規定請求的類型、URL 以及是否異步處理請求。
參數:參數1,設定請求類型(GET 或 POST),GET與POST的差別請自己百度一下,這裡不做解釋;
參數2,檔案在伺服器上的位置;
參數3,是否異步處理請求,是為true,否為false。
如下:
- //第二步:設定和伺服器端互動的相應參數 ,向路徑http://localhost:8080/JsLearning3/getAjax準備發送資料
- var url="http://localhost:8080/JsLearning3/getAjax";
- xmlHttp.open("POST",url,true);
open方法如下:
GET 還是 POST?
與 POST 相比,GET 更簡單也更快,并且在大部分情況下都能用。然而,在以下情況中,請使用 POST 請求:
無法使用緩存檔案(更新伺服器上的檔案或資料庫)
向伺服器發送大量資料(POST 沒有資料量限制)
發送包含未知字元的使用者輸入時,POST 比 GET 更穩定也更可靠
異步 - True 或 False?
AJAX 指的是異步 JavaScript 和 XML(Asynchronous JavaScript and XML)。XMLHttpRequest 對象如果要用于 AJAX 的話,其 open() 方法的 async 參數必須設定為 true:對于 web 開發人員來說,發送異步請求是一個巨大的進步。很多在伺服器執行的任務都相當費時。AJAX 出現之前,這可能會引起應用程式挂起或停止。
通過 AJAX,JavaScript 無需等待伺服器的響應,而是:
在等待伺服器響應時執行其他腳本
當響應就緒後對響應進行處理
2.3、調用回調函數
如果在上一步中open方法的第三個參數選擇的是true,那麼目前就是異步請求,這個時候需要寫一個回調函數,xmlHttp對象有一個onreadystatechange屬性,這個屬性傳回的是一個匿名的方法,是以回調函數就在這裡寫xmlHttp.onreadystatechange=function{},function{}内部就是回調函數的内容。所謂回調函數,就是請求在背景處理完,再傳回到前台所實作的功能。在這個例子裡,我們的回調函數要實作的功能就是接收背景處理後回報給前台的資料,然後将這個資料顯示到指定的div上。因為從背景傳回的資料可能是錯誤的,是以在回調函數中首先要判斷背景傳回的資訊是否正确,如果正确才可以繼續執行。代碼如下:
- //第三步:注冊回調方法
- xmlHttp.onreadystatechange = function(){
- if (xmlHttp.readyState == 4) {
- if (xmlHttp.status == 200) {
- var obj=document.getElementById(id);
- obj.innerHTML = xmlHttp.responseText;
- } else {
- alert("AJAX伺服器傳回錯誤!");
- }
- }
在上面代碼中,xmlHttp.readyState是存有XMLHttpRequest 的狀态。從 0 到 4 發生變化。0: 請求未初始化。1: 伺服器連接配接已建立。2: 請求已接收。3: 請求進行中。4: 請求已完成,且響應已就緒。是以這裡我們判斷隻有當xmlHttp.readyState為4的時候才可以繼續執行。
xmlHttp.status是伺服器傳回的結果,其中200代表正确。404代表未找到頁面,是以這裡我們判斷隻有當xmlHttp.status等于200的時候才可以繼續執行。
- var obj=document.getElementById("testid");
- obj.innerHTML = xmlHttp.responseText;
這段代碼就是回調函數的核心内容,就是擷取背景傳回的資料,然後将這個資料指派給id為testid的div。xmlHttp對象有兩個屬性都可以擷取背景傳回的資料,分别是:responseText和responseXML,其中responseText是用來獲得字元串形式的響應資料,responseXML是用來獲得 XML 形式的響應資料。至于選擇哪一個是取決于背景給傳回的資料的,這個例子裡我們隻是顯示一條字元串資料是以選擇的是responseText。responseXML将會在以後的例子中介紹。
AJAX狀态值與狀态碼差別
AJAX狀态值是指,運作AJAX所經曆過的幾種狀态,無論通路是否成功都将響應的步驟,可以了解成為AJAX運作步驟。如:正在發送,正在響應等,由AJAX對象與伺服器互動時所得;使用“ajax.readyState”獲得。(由數字1~4機關數字組成)
AJAX狀态碼是指,無論AJAX通路是否成功,由HTTP協定根據所送出的資訊,伺服器所傳回的HTTP頭資訊代碼,該資訊使用“ajax.status”所獲得;(由數字1XX,2XX三位數字組成,詳細檢視RFC)
這就是我們在使用AJAX時為什麼采用下面的方式判斷所獲得的資訊是否正确的原因。
- if(ajax.readyState == 4 && ajax.status == 200) {。。。。);}
AJAX運作步驟與狀态值說明
在AJAX實際運作當中,對于通路XMLHttpRequest(XHR)時并不是一次完成的,而是分别經曆了多種狀态後取得的結果,對于這種狀态在AJAX中共有5種,分别是。
0 - (未初始化)還沒有調用send()方法
1 - (載入)已調用send()方法,正在發送請求
2 - (載入完成)send()方法執行完成,
3 - (互動)正在解析響應内容
4 - (完成)響應内容解析完成,可以在用戶端調用了
對于上面的狀态,其中“0”狀态是在定義後自動具有的狀态值,而對于成功通路的狀态(得到資訊)我們大多數采用“4”進行判斷。
AJAX狀态碼說明
1**:請求收到,繼續處理
2**:操作成功收到,分析、接受
3**:完成此請求必須進一步處理
4**:請求包含一個錯誤文法或不能完成
5**:伺服器執行一個完全有效請求失敗
再具體就如下:
100——客戶必須繼續送出請求
101——客戶要求伺服器根據請求轉換HTTP協定版本
200——交易成功
201——提示知道新檔案的URL
202——接受和處理、但處理未完成
203——傳回資訊不确定或不完整
204——請求收到,但傳回資訊為空
205——伺服器完成了請求,使用者代理必須複位目前已經浏覽過的檔案
206——伺服器已經完成了部分使用者的GET請求
300——請求的資源可在多處得到
301——删除請求資料
302——在其他位址發現了請求資料
303——建議客戶通路其他URL或通路方式
304——用戶端已經執行了GET,但檔案未變化
305——請求的資源必須從伺服器指定的位址得到
306——前一版本HTTP中使用的代碼,現行版本中不再使用
307——申明請求的資源臨時性删除
400——錯誤請求,如文法錯誤
401——請求授權失敗
402——保留有效ChargeTo頭響應
403——請求不允許
404——沒有發現檔案、查詢或URl
405——使用者在Request-Line字段定義的方法不允許
406——根據使用者發送的Accept拖,請求資源不可通路
407——類似401,使用者必須首先在代理伺服器上得到授權
408——用戶端沒有在使用者指定的餓時間内完成請求
409——對目前資源狀态,請求不能完成
410——伺服器上不再有此資源且無進一步的參考位址
411——伺服器拒絕使用者定義的Content-Length屬性請求
412——一個或多個請求頭字段在目前請求中錯誤
413——請求的資源大于伺服器允許的大小
414——請求的資源URL長于伺服器允許的長度
415——請求資源不支援請求項目格式
416——請求中包含Range請求頭字段,在目前請求資源範圍内沒有range訓示值,請求也不包含If-Range請求頭字段
417——伺服器不滿足請求Expect頭字段指定的期望值,如果是代理伺服器,可能是下一級伺服器不能滿足請求
500——伺服器産生内部錯誤
501——伺服器不支援請求的函數
502——伺服器暫時不可用,有時是為了防止發生系統過載
503——伺服器過載或暫停維修
504——關口過載,伺服器使用另一個關口或服務來響應使用者,等待時間設定值較長
505——伺服器不支援或拒絕支請求頭中指定的HTTP版本
2.4、發送請求
[html]
- //第四步:設定發送請求的内容和發送報送。然後發送請求
- var params ="userName="+document.getElementsByName("userName")[0].value+"&userPass="+document.getElementsByName("userPass")[0].value+"&time="+ Math.random(); // 增加time随機參數,防止讀取緩存
- xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded;charset=UTF-8"); // 向請求添加 HTTP 頭,POST如果有資料一定加加!!!!
- xmlHttp.send(params);
如果需要像 HTML 表單那樣 POST 資料,請使用 setRequestHeader() 來添加 HTTP 頭。然後在 send() 方法中規定您希望發送的資料:
三、應用執行個體
Ajax+SpringMVC來實作實時資料的傳遞
工程免費下載下傳
整個工程目錄如下:
用到的JAR包如下:
下面再來具體講清楚
1、首先是web.xml的配置,放在WEB-INF檔案夾下
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
- <display-name>JsLearning3</display-name>
- <welcome-file-list>
- <welcome-file>index.html</welcome-file>
- <welcome-file>index.htm</welcome-file>
- <welcome-file>index.jsp</welcome-file>
- <welcome-file>default.html</welcome-file>
- <welcome-file>default.htm</welcome-file>
- <welcome-file>default.jsp</welcome-file>
- </welcome-file-list>
- <!-- 統一設定編碼,防止出現中文亂碼 -->
- <filter>
- <filter-name>Set Character Encoding</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <!-- SpringMVC的前端控制器 -->
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <!-- 設定自己定義的控制器xml檔案 -->
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:spring-servlet.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- Spring MVC配置檔案結束 -->
- <!-- 攔截設定 -->
- <servlet-mapping>
- <!-- 由SpringMVC攔截所有請求 -->
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <!-- webAppRootKey:值預設為webapp.root,當tomcat下部署多個應用時(每個都用到了log4j), 每個應用的web.xml中都要配置該參數,該參數與Log4j.xml檔案中的${webapp.root}
- 否則每個應用的webAppRootKey值都相同,就會引起沖突
- -->
- <context-param>
- <param-name>webAppRootKey</param-name>
- <param-value>webApp.root</param-value>
- </context-param>
- <!-- log4jConfigLocation:log4j配置檔案存放路徑 -->
- <param-name>log4jConfigLocation</param-name>
- <param-value>classpath:log4j.properties</param-value>
- <!-- 3000表示 開一條watchdog線程每60秒掃描一下配置檔案的變化;這樣便于日志存放位置的改變 -->
- <context-param>
- <param-name>log4jRefreshInterval</param-name>
- <param-value>3000</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
- </listener>
- </web-app>
2、接着配置SpringMVC的攔截規則spring-servlet.xml,放在src檔案夾下
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 把标記了@Controller注解的類轉換為bean -->
- <context:component-scan base-package="com.lin.controller" />
- <!-- 啟動Spring MVC的注解功能,完成請求和注解POJO的映射 -->
- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
- <!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前字尾 -->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
- p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>
- </beans>
3、使用是日記列印功能log4j,在src檔案夾下建立log4j.properties,如果不需要,這一步也可以跳過
内容如下:
[plain]
- log4j.rootLogger =DEBEG,stdout
- log4j.appender.stdout = org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target = System.out
- log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
4、Ajax的使用
在WEB-INF下建立view檔案夾,然後建立一個first.jsp檔案,内容如下:
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- <script language="javascript">
- /*
- *擷取工程的路徑
- */
- function getRootPath() {
- var pathName = window.location.pathname.substring(1);
- var webName = pathName == '' ? '' : pathName.substring(0, pathName
- .indexOf('/'));
- return window.location.protocol + '//' + window.location.host + '/'
- + webName + '/';
- *送出Ajax請求并處理傳回資料
- */
- function sendAjax(id) {
- //第一步:建立XMLHttpRequest對象
- //第二步:設定和伺服器端互動的相應參數 ,向路徑http://localhost:8080/JsLearning3/getAjax準備發送資料
- var url=getRootPath()+"getAjax";
- xmlHttp.open("POST",url,true);
- //第三步:注冊回調方法
- xmlHttp.onreadystatechange = function(){
- if (xmlHttp.readyState == 4) {
- if (xmlHttp.status == 200) {
- var obj=document.getElementById(id);
- obj.innerHTML = xmlHttp.responseText;
- } else {
- alert("AJAX伺服器傳回錯誤!");
- }
- }
- //第四步:設定發送請求的内容和發送報送。然後發送請求
- var params ="userName="+document.getElementsByName("userName")[0].value+"&userPass="+document.getElementsByName("userPass")[0].value+"&time="+ Math.random(); // 增加time随機參數,防止讀取緩存
- xmlHttp.send(params);
- }
- </script>
- </head>
- <body>
- <h3>使用者注冊</h3>
- 名稱<input type="text" name="userName" id="" onblur="sendAjax('txtHintName')"/>你輸入的使用者名是:<span id="txtHintName"></span><br>
- 密碼<input type="password" name="userPass" onblur="sendAjax('txtHintPass')"/> 你輸入的密碼是:<span id="txtHintPass"></span><br>
- </body>
- </html>
5、Controler控制器
[java]
- package com.lin.controller;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import net.sf.json.JSONArray;
- import org.apache.log4j.Logger;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- @Controller
- public class firstController {
- private static Logger logger = Logger.getLogger(firstController.class);
- @RequestMapping({"/first","/"})
- public String getFirst(){
- return "first";
- @RequestMapping({"/getAjax/**"})
- public String getAjax(HttpServletRequest request, HttpServletResponse response) throws IOException{
- String userName=(String)request.getParameter("userName");
- String userPass=(String)request.getParameter("userPass");
- System.out.println(userName);
- System.out.println(userPass);
- List<String> list=new ArrayList<String>();
- list.add(userName);
- list.add(userPass);
- JSONArray json = JSONArray.fromObject(list);
- response.setCharacterEncoding("UTF-8");
- response.flushBuffer();
- response.getWriter().write(json.toString());
- return null;
這裡用到了将送出過來的資料轉到Json中去儲存,處理各種請求,并設定Ajax的傳回參數。
這裡設定成了名稱或密碼輸入欄隻要一失去焦點事件,立馬向服務端發送一個請求。
全設定好了,就可以運作了。