1、ajax介紹
1.1、什么是ajax
全稱:Asynchronous JavaScript And XML(異步 JavaScript 及 XML)
Ajax的作用:實現異步請求的技術。
什么是同步請求?
場景:頁面上有一個a標簽,用戶點擊a標簽,瀏覽器發出一個請求,然后服務器給出一個響應。
(請求,其實是用戶的操作,觸發的)
什么是異步(不同步)請求?
場景:在用戶注冊的時候,用戶首先輸入用戶名,接下來用戶繼續填寫其他注冊信息,與此同時,瀏覽器自動發送了一個請求,將用戶輸入的用戶名發送給服務器,去校驗是否可用.
(請求,是瀏覽器自己發送的,與用戶沒有關系)
同步與異步區別的理解:
1.同步請求:之前我們寫的注冊案例,依次寫用戶名,密碼,等等所有信息之后,手動按提交按鈕,才會把瀏覽器上的數據傳到服務器進行校驗用戶名是否重復,然后在瀏覽器上提示用戶名是否重復的信息,這種方式一速度較慢,需要將全部信息寫完之后刷新整個頁面提交到服務器,如果沒有通過驗證還得重新填寫信息再提交,比較浪費流量,二則是如果沒有通過驗證所有的信息都沒有了還得重新填寫,太麻煩
2.異步請求:使用ajax的話,將用戶名文本框綁定一個鼠標離焦事件,事件里用ajax提交用戶名到服務器校驗,這個驗證是我們鼠標離開用戶名文本框瀏覽器自動向服務器發出請求校驗的,我們在填寫別的信息時,服務器會將校驗信息發送給瀏覽器提示是否重復信息,這樣既省流量,又可以只修改用戶名即可,最后驗證通過才可以提交全部信息;
為什么需要異步請求,或者說那些功能必須使用異步請求技術來實現?
在不刷新頁面(使用a標簽發送請求和使用form表單發送請求,這兩種請求都會,刷新頁面)的情況下,發送請求,接收響應,然后修改部分的頁面,這樣的需求需要異步請求實現。
總結:在不使用a標簽和form表單發送請求的情況下,使用異步請求。
在這個需求中,發送請求應該誰來做?
瀏覽器。
讓瀏覽器來幫助發送這個請求,那么程序員如何與瀏覽器溝通,讓它幫助我們發送請求?
Javascript技術。
企業為什么特別喜歡使用ajax?
錢。企業的網絡通信費用,按流量計費,那么使用ajax它的數據量小,所以省錢。
ajax它的數據量小——因為他不重新加載整個頁面(加載部分)
Ajax因為數據量小,響應速度快,用戶體驗好。
1.2、ajax運行機制
在頁面不刷新的情況下,向服務器發送請求,達到頁面和后台的異步交互。
現在主流(IE、谷歌、火狐,其他的國產瀏覽器一般都是使用谷歌瀏覽器內核)的瀏覽器都有ajax引擎實現——現在ajax技術,都被主流瀏覽器實現,我們自己不用去寫Ajax引擎,這個引擎已經存在在瀏覽器中。我們可以理解為瀏覽器都內置有ajax的核心對象,我們不需要自己創建核心對象,只要獲取對象使用即可;
相當於大家已經有了法拉利,不用自己再造一個,只需學會使用就可以。
1.3、ajax快速入門案例
1)百度(官網)
2)下載jar和API文檔
3)測試
4)筆記
注意:ajax沒有jar包,所有不需要在項目中導入jar包;
1.3.1、獲取XMLHttpRequest對象(ajax核心對象,引擎對象)
演示一: jsp代碼: <script type="text/javascript"> //演示1:獲取ajax的核心對象 //此為固定代碼,因為瀏覽器不同則獲取對象的方式處理也是不同的; function getXHR(){ var xmlhttp; if(window.XMLHttpRequest){ //如果使用的瀏覽器是 IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); }else{ //如果使用的瀏覽器是 IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } //演示效果 //alert(getXHR()); </script>
效果:
1.3.2、向服務器發送請求使用open方法和send方法
演示二: jsp代碼: //演示2,使用 ajax 向服務器發送請求 function test1(){ //先獲取 ajax 核心對象(這個方法我們上面寫過了,調用即可) var xhr = getXHR(); //使用open(method,url,async)方法發送請求 //參數一,method:請求的類型;GET 或 POST //參數二,url:文件在服務器上的位置 //參數三:async:true(異步)或 false(同步) xhr.open("get","${root}/ajax",true); //使用send()方法發送請求 //注意;此處是get提交,所以使用send方法沒有參數 xhr.send(); } //test1();
效果:
注意:我們演示時還沒有創建發送到服務器端的servlet,所有找不到資源;
1.3.2、接收服務器響應
演示三: jsp代碼: //演示3,使用ajax,從服務器接收響應 function test2(){ //先獲取ajax核心對象 var xhr = getXHR(); //參數一,method:請求的類型;GET 或 POST //參數二,url:文件在服務器上的位置 //參數三:async:true(異步)或 false(同步) //注意:此處的get提交,在url中添加了參數,發送到服務器 xhr.open("get","${root}/ajax?username=haha",true); //將請求發送到服務器。 xhr.send(); //接收響應,獲取響應的內容 //接收服務器端的響應使用的是核心對象的 responseText屬性 var data = xhr.responseText; //打印從服務器端發來的響應,"測試ajax響應成功!" alert(data); /** 瀏覽器:在上海 服務器:在北京 發送請求,請求到服務器,必然有網路延遲。 發送響應,響應到瀏覽器,必然有網路延遲。 必須等待服務器響應。所以還需要設置ajax等待服務器。 事件:用來啟動js函數,調用js中方法,動態操作(增刪改查Element)頁面。 基於響應的任務? 注冊:寫用戶名, 可用:表單可以提交 不可用:表單不能提交 */ } //演示效果 //test2();
AjaxServlet:這就是ajax發送請求到的服務器文件
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //獲取 ajax 發送的參數 String parameter = request.getParameter("username"); //System.out.println(parameter); //准備一個響應,給瀏覽器(ajax核心對象) response.setContentType("text/html;charset=utf-8"); //注意:內容不會直接顯示到瀏覽器頁面上,從ajax發送的請求到服務器,從服務器返回的響應也會傳到ajax中,由ajax做出處理 response.getWriter().write("測試ajax響應成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:
瀏覽器效果應該是打印 "測試ajax響應成功!",但是什么都沒有打印,所以出錯了
控制台接收到了參數,說明服務器也響應了,出錯的原因則一定是ajax沒有接收到服務器的響應
所以還需要設置ajax等待服務器。如何設置呢?
1.3.3、設置onreadystatechange事件執行函數(等待服務器響應)
演示四: jsp代碼: //演示4,設置等待服務器響應 function test3(){ //先獲取ajax核心對象 var xhr = getXHR(); //第一,method:請求的類型;GET 或 POST //第二,url:文件在服務器上的位置 //第三:async:true(異步)或 false(同步) xhr.open("get","${root}/ajax",true); //將請求發送到服務器。 xhr.send(); //在接收響應前,設置等待服務器響應 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ //保證請求已經完成,且響應已經就緒 //接受響應 var data = xhr.responseText ; alert(data); } }; } //test3();
AjaxServlet:這就是ajax發送請求到的服務器文件
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //准備一個響應,給瀏覽器(ajax核心對象) response.setContentType("text/html;charset=utf-8"); //注意:內容不會直接顯示到瀏覽器頁面上,從ajax發送的請求到服務器,從服務器返回的響應也會傳到ajax中,由ajax做出處理 response.getWriter().write("測試ajax響應成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:成功
1.3.4.Ajax總結
Aja代碼步驟:
1.獲取核心對象 2.發送請求,使用open和send方法 3.設置等待服務器響應,給onreadystatechange屬性設置函數,並且,在函數中做判斷,保證readyState== 4 && status == 200,才是請求已經完成,響應已經就緒 4.獲取響應的數據,根據需求,做Dom操作
最終版ajax代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="root" value="${pageContext.request.contextPath}"/> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> //獲取ajax的核心對象的方法 function getXHR(){ var xmlhttp; if(window.XMLHttpRequest){ //如果使用的瀏覽器是 IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); }else{ //如果使用的瀏覽器是 IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } function test(){ //1.先獲取ajax核心對象 var xhr = getXHR(); //第一,method:請求的類型;GET 或 POST //第二,url:文件在服務器上的位置 //第三:async:true(異步)或 false(同步) xhr.open("get","${root}/ajax",true); //2.將請求發送到服務器。 xhr.send(); //3.在接收響應前,設置等待服務器響應 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ //保證請求已經完成,且響應已經就緒 //4.接受響應 var data = xhr.responseText ; alert(data); } }; } test(); </script> </head> <body> </body> </html>
注意事項:
內容不會直接顯示到瀏覽器頁面上,從ajax發送的請求到服務器,從服務器返回的響應也會傳到ajax中,由ajax做出處理
友情提示:
以后再工作中,一般不使用原生(今天學習的)的ajax代碼,一般使用的是js框架(Jquery、ext js 、node js)發送ajax請求
問題:
Get發送請求與post發送請求的代碼不同,我們還沒有具體的分析,后文繼續;
1.4、XMLHttpRequest API 詳解
1.4.1、onreadystatechange屬性
是什么:存儲函數(或函數名),每當 readyState 屬性改變時,就會調用該函數
執行機制圖解:
1.4.2、open方法
是什么:做發送請求之前准備工作的方法
一般使用post方式還是get方式?
官方建議:
我推薦:POST
POST,沒有數據長度限制(注意:很多時候,提供功能給用戶使用,用戶輸入的數據長度,有時是沒法控制的)
POST,解決亂碼比較簡單
POST,方式更加安全
演示五: ajax代碼: //演示5.使用post方式發送ajax請求 /** 測試js代碼:firebug,會直接將出錯的js代碼位置,顯示出來 如果firebug頁也無法解決,使用alert(); */ function test4(){ var xhr = getXHR(); xhr.open("post","${root}/ajax",true); //模擬表單發送數據 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //js代碼,如果代碼中的某一行錯了,它是不報錯的, xhr.send("username=haha"); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ var data = xhr.responseText ; alert(data); } }; } test4();
AjacServlet:
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //獲取post提交的參數 String parameter = request.getParameter("username"); System.out.println(parameter); //准備一個響應,給瀏覽器(ajax核心對象) response.setContentType("text/html;charset=utf-8"); //注意:內容不會直接顯示到瀏覽器頁面上,從ajax發送的請求到服務器,從服務器返回的響應也會傳到ajax中,由ajax做出處理 response.getWriter().write("測試ajax響應成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); } }
效果:post提交成功
1.4.3、setRequestHeader方法
注意:這個方法相當於,設置了表單的enctype屬性的默認值,來模擬表單發送數據
1.4.4、send方法
是什么:發送請求的方法
注意:Post方式提交請求,請求參數寫在send方法中。如果是get請求,參數,直接寫在url中
1.4.5、總結:Get請求與post請求的對比
Post請求格式:
xhr.open("post","${root}/ajaxTest",true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send("username=張三");
Get請求格式:
xhr.open("get","${root}/ajax?username=haha",true); xhr.send();
區別:
1.post提交的url中不可以帶參數
2.Post提交需要設置:xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
3.Post提交的send方法參數就是post提交的參數,而get提交的send方法不可以有參數;
1.4.5、readyState屬性
是什么:存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化
注意:我們只需要關注狀態==4的時候,請求已經完成,而且響應已經就緒
1.4.6、status屬性
是什么:存有響應狀態碼的屬性
響應狀態碼:
404:請求找不到
500:服務器異常
302:重定向
200:ok
401:權限不足,做應用,對用戶的界面(使用淘寶的時候買家看到的頁面),對管理員界面(只有擁有管理員權限的用戶,才能看到——賣家的頁面),如果用戶訪問了管理員界面,那么就需要返回響應碼為:401,表示當前用戶權限不足。
管理員的頁面:賣家(上傳商品),客服(用戶信息,用戶的記錄,電商,用戶訂單),運維(當前服務器的運行狀態),老板(錢,當前系統的資金管理)
Shiro安全框架,權限
1.4.7、responseText屬性
是什么:獲取響應的數據,以字符串的形式
1.5、案例:驗證用戶名是否重復(重點:必須掌握)
需求:當用戶輸入完用戶名的時候,瀏覽器發送用戶輸入的數據(用戶名),給服務器,服務器校驗用戶名,並且給出反饋(用戶名可以使用,用戶名重復,用戶名不能為空,服務器忙)。
思路:
1) 當用戶輸入完用戶名的時候?oblur事件,啟動js函數,發送ajax請求
2) 瀏覽器發送用戶輸入的數據(用戶名),給服務器?Ajax
3) 服務器校驗用戶名?查詢數據庫
4) 並且給出反饋。Servelt給出響應,js處理這個響應,具體就是是否限制表單提交和提示用戶錯誤信息
分析案例實現的步驟:
頁面上提供功能:
1) 輸入框,讓用戶輸入用戶名,表單提交數據
2) 提交按鈕,提交數據
Ajax:
1) 獲取用戶輸入的用戶名
2) 發送請求
3) 等待響應
4) 根據響應做不同處理(可以提交表單和不可以提交)
Servlet:
1) 校驗請求參數
2) 調用service方法查詢
Service:
調用dao查詢數據
Dao:
操作數據;
Select * from user where username = ?
畫圖分析:
功能實現:
頁面修改:設置表單、輸入框、提交按鈕和js實現:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="root" value="${pageContext.request.contextPath}"/> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> //獲取ajax核心對象 function getXHR() { var xmlhttp; if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } //_this 是綁定此事件的對象,注意因為參數是具體的標簽對象,所以不可以使用關鍵字this function _check(_this){ //獲取輸入的用戶名值 var username = _this.value; //發送到服務器校驗是否有重名 //1.獲取核心對象 var xhr = getHXR(); //2.發送請求 xhr.open("post","${root }/check",true); //模擬表單發送數據 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //注意:js代碼,如果代碼中的某一行錯了,它是不報錯的 xhr.send("username=" + username); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ var data = xhr.responseText; //注意:為了防止和js內置的全局變量,重名,所以加_ var _msg = document.getElementById("msg"); var _f = document.getElementById("_f"); if(data == 1){ //提示用戶名可以注冊 _msg.innerHTML = "用戶名可以注冊"; //onsubmit:表單提交事件 //只要onsubmit的值為true,表單才可以提交 _f.onsubmit = function (){ return true; }; } else if(data == -1){ _msg.innerHTML = "重復"; _f.onsubmit = function (){ return false; }; }else if(data == -3){ _msg.innerHTML = "用戶名不能為空"; _f.onsubmit = function (){ return false; }; }else{ _msg.innerHTML = "服務器忙"; _f.onsubmit = function (){ return false; }; } } }; } </script> </head> <body> <form id="_f" action="${root }/register" method="post"> <!-- this:表示當前標簽對象 --> 用戶名:<input type="text" name="username" onblur="_check(this);"><span id="msg"></span> <br> <input type="submit" value="注冊"> </form> </body> </html>
CheckNameServlet:
import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import cn.itcast.domain.User; import cn.itcast.utils.JDBCUtils; public class CheckNameServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { request.setCharacterEncoding("utf-8"); //獲取請求參數 String username = request.getParameter("username"); //獲取輸出流 PrintWriter writer = response.getWriter(); //先校驗用戶名的格式 //用戶名不能不寫,也不能寫空字符串 if(username == null || username.trim().equals("")){ //返回-3 writer.write("-3"); return; } //再校驗用戶名是否重復 //我們這里演示,就不使用service和dao,方法直接在servlet中實現,僅供演示使用 QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from user where name = ?"; try { User user = qr.query(sql, new BeanHandler<User>(User.class), username); if(user == null){ writer.write("1"); return; }else { writer.write("-1"); return; } } catch (SQLException e) { e.printStackTrace(); writer.write("-2"); return; } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2、Ajax的缺陷
<!-- 使用JavaScript的標簽解決,訪問其他項目,獲取響應數據 --> <!-- 解決ajax跨域問題 --> <script type="text/javascript"> function _response(data){ alert(data); } //_response('haha'); //_response('測試ajax成功day1802!'); </script> <%-- <script type="text/javascript" src="${root }/test.js"></script> --%> <script type="text/javascript" src="http://127.0.0.1:8080/day1802/ajax"></script>
//ajax缺陷演示 /** ajax,他可以訪問其他項目的資源,但是,接受不到響應。這個是ajax設計的時候,為了考慮安全因素,專門設計的限制 實際的工作中,需要使用ajax發送請求,訪問其他項目(例子:淘寶,買東西,選好了之后,支付,買東西的時候,你訪問的是www.taobao.com ,支付,www.zhifubao.com) 那怎么解決呢? 使用JavaScript的標簽解決。 */ /* function test5() { var xhr = getXHR(); xhr.open("post", "http://127.0.0.1:8080/day1802/ajax", true); xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send("username=張三"); xhr.onreadystatechange = function() { //接受響應,readyState == 4 並且 status == 200 if (xhr.readyState == 4 && xhr.status == 200) { var data = xhr.responseText; alert(data); } }; } test5(); */