AJAX
一、介紹
AJAX : Asychronous Javascript And XML,指異步JavaScript及XML。是指一種創(chuàng)建交互式網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù)。
AJAX 是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁的技術(shù)。
通過在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,AJAX 可以使網(wǎng)頁實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁的情況下,對(duì)網(wǎng)頁的某部分進(jìn)行更新。
傳統(tǒng)的網(wǎng)頁(不使用 AJAX)如果需要更新內(nèi)容,必須重載整個(gè)網(wǎng)頁頁面。
二、使用AJAX
1. JS原生AJAX[了解]
通過查詢W3C文檔使用JS原生AJAX。
一般可分為五步:
1. 創(chuàng)建AJAX對(duì)象
2. 綁定監(jiān)聽事件---監(jiān)聽服務(wù)器是否響應(yīng)數(shù)據(jù)了
3. 綁定請(qǐng)求的服務(wù)器地址
4. 發(fā)送請(qǐng)求
5. 服務(wù)器響應(yīng)成功執(zhí)行的函數(shù)
//1.創(chuàng)建對(duì)象
xmlhttp = new XMLHttpRequest();
//2.綁定監(jiān)聽事件---監(jiān)聽服務(wù)器是否響應(yīng)
xmlhttp.onreadystatechange = function() {
//5.服務(wù)器響應(yīng)成功執(zhí)行的函數(shù)
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
alert(xmlhttp.responseText);
}
}
//3.綁定請(qǐng)求路徑
xmlhttp.open("GET", "${pageContext.request.contextPath}/demo", true);
//4.發(fā)送請(qǐng)求
xmlhttp.send();
-
服務(wù)器狀態(tài)碼(readyState、status):
readyState : 0 : XMLHttpRequest對(duì)象沒有完成初始化。即:剛剛創(chuàng)建。 1 : XMLHttpRequest對(duì)象開始發(fā)送請(qǐng)求.調(diào)用了open方法,但還沒有調(diào)用send方法,請(qǐng)求還未發(fā)出。 2 : XMLHttpRequest對(duì)象的請(qǐng)求發(fā)送完成。但服務(wù)器還未響應(yīng) 3 : XMLHttpRequest對(duì)象開始讀取響應(yīng),還沒有結(jié)束收到了所有的響應(yīng)消息頭,但正文還沒有完全收到 4 : XMLHttpRequest對(duì)象讀取響應(yīng)結(jié)束 status : 200 : OK .服務(wù)器接收到請(qǐng)求并已響應(yīng)。 400 : 無法找到請(qǐng)求的資源。 403 : 沒有訪問權(quán)限 404 : 訪問的資源不存在 500 : 服務(wù)器內(nèi)部錯(cuò)誤
2. JQurey的AJAX【重點(diǎn)】
2.1 get方式
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
<script type = "text/javascript">
$.get(
url, //請(qǐng)求的地址路徑
params, //發(fā)送到服務(wù)器的參數(shù)
function(){}, //回調(diào)函數(shù),服務(wù)器響應(yīng)成功后執(zhí)行的函數(shù)
type //一般為json和text,默認(rèn)text。服務(wù)器返回的數(shù)據(jù)格式
);
</script>
例如:
$.get(
"${pageContext.request.contextPath}/demo2",//url,請(qǐng)求訪問的路徑
{name:"zhangsan",age:20},//要傳遞到服務(wù)器的參數(shù)
function(data) { //響應(yīng)成功后執(zhí)行的函數(shù),data是服務(wù)器返回的數(shù)據(jù)
alert(data);
},
"text"http://服務(wù)器返回的數(shù)據(jù)格式
);
2.2 post方式
與get方式一樣,只需要把$.get()改為$.post()即可
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
<script type = "text/javascript">
$.post(
url, //請(qǐng)求的地址路徑
params, //發(fā)送到服務(wù)器的參數(shù)
function(){}, //回調(diào)函數(shù),服務(wù)器響應(yīng)成功后執(zhí)行的函數(shù)
type //一般為json和text,默認(rèn)text。服務(wù)器返回的數(shù)據(jù)格式
);
</script>
例如:
$.post(
"${pageContext.request.contextPath}/demo2",//url,請(qǐng)求訪問的路徑
{"name":"yom","age":10},//要傳遞到服務(wù)器的參數(shù)
function(data) { //響應(yīng)成功后執(zhí)行的函數(shù),data是服務(wù)器返回的數(shù)據(jù)
alert(data);
},
"text"http://服務(wù)器返回的數(shù)據(jù)格式
);
2.3 ajax方式
get與post是ajax方式的簡(jiǎn)化,用get和post方式可以節(jié)省不少代碼。
但ajax的功能更多,他可以指定是否同步或異步,而get和post方式就不能改變,只能異步請(qǐng)求。
- JQuery的包的路徑一定要導(dǎo)入并且要正確否則就會(huì)失敗,js文件放在web-content下新建的js文件夾中,路徑前不要加'/'
- ajax方式和get與post的異步請(qǐng)求格式有個(gè)小區(qū)別,就是ajax的格式是json格式,前后都有大括號(hào),中間為key:value的鍵值對(duì)形式。兩個(gè)鍵值對(duì)之間以逗號(hào)隔開。
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
<input type="button" value="ajax(ajax方式異步請(qǐng)求)" onclick="fn()" />
<script type="text/javascript">
function fn() {
$.ajax({
type : "POST",//請(qǐng)求方式
async : true,//是否異步,true為異步,false為同步
url : "${pageContext.request.contextPath}/demo3",//請(qǐng)求的服務(wù)器路徑
data : "name=小明",//請(qǐng)求傳遞的參數(shù)
success : function(data) {//響應(yīng)成功后執(zhí)行的函數(shù),這里的data是指服務(wù)器傳遞回來的數(shù)據(jù)
alert(data.name);
alert(data.age);
},
dataType : "json" //服務(wù)器響應(yīng)的數(shù)據(jù)格式
});
}
</script>
三、案例
1. 案例一:異步校驗(yàn)用戶名是否已經(jīng)存在
思路:
1. 準(zhǔn)備用戶數(shù)據(jù)庫,與注冊(cè)頁面。
2. 搭建開發(fā)環(huán)境,數(shù)據(jù)庫相關(guān)的jar包:驅(qū)動(dòng),c3p0,配置文件,dbutils。
3. 新建工程,創(chuàng)建包結(jié)構(gòu):web-service-dao
4. 具體實(shí)現(xiàn)。servlet---service---dao數(shù)據(jù)庫查詢并返回結(jié)果.
1. 在jsp頁面獲取到用戶輸入的用戶名
2. 用異步請(qǐng)求的技術(shù)AJAX將用戶輸入的用戶名提交到服務(wù)器。
3. dao層查詢,返回一個(gè)User對(duì)象。
4. 新建ResultBean的bean類,servlet判斷User對(duì)象是否為空設(shè)置ResultBean的值。
這個(gè)對(duì)象存儲(chǔ)了返回的消息。將其封裝成json響應(yīng)回客戶端。
5. 客戶端解析json數(shù)據(jù)。
代碼實(shí)現(xiàn):
1. 準(zhǔn)備數(shù)據(jù)庫與注冊(cè)頁面
2. 準(zhǔn)備開發(fā)需要的jar包與配置文件,工具類JDBCUtils
public class JDBCUtils {
private static DataSource ds = new ComboPooledDataSource();// c3p0默認(rèn)配置獲取連接池
// 可以認(rèn)為是與線程綁定的獲取連接的Map集合
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
// 獲取連接池的方法
public static DataSource getDataSource() {
return ds;
}
// 通過連接池獲取連接的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
// 從ThreadLocal中獲取與線程綁定的連接Connection
public static Connection getConnectionTL() throws SQLException {
Connection connection = threadLocal.get();
if (connection == null) {
threadLocal.set(getConnection());
connection = threadLocal.get();
}
return connection;
}
// 開啟事務(wù)的方法
public static void startTransaction() throws SQLException {
Connection connection = getConnectionTL();
connection.setAutoCommit(false);
}
// 提交事務(wù)并釋放資源的方法
public static void commitAndRelease() throws SQLException {
Connection connection = getConnectionTL();
connection.rollback();
if (connection != null) {
connection.close();
// 這里為什么connection關(guān)閉后還要設(shè)置為null呢?
// 因?yàn)樵陉P(guān)閉close的時(shí)候可能出現(xiàn)了異常導(dǎo)致關(guān)閉失敗,這個(gè)時(shí)候connection就處于一種未知的狀態(tài),這種情況下垃圾回收器gc就不能將他回收
// 因此在后面將它設(shè)為null,這樣即使出現(xiàn)異常也能被垃圾回收器關(guān)閉
connection = null;
}
threadLocal.remove();
}
// 回滾事務(wù)并釋放資源的方法
public static void rollbackAndRelease() throws SQLException {
Connection connection = getConnectionTL();
if (connection != null) {
connection.close();
connection = null;
}
threadLocal.remove();
}
}
3. 新建工程,創(chuàng)建包結(jié)構(gòu):web-service-dao
4. 后臺(tái)功能的具體實(shí)現(xiàn)
1. 在jsp頁面獲取用戶輸入框,綁定失去焦點(diǎn)事件,用異步請(qǐng)求將獲取到的用戶名發(fā)送到服務(wù)器端。
使用jquery的ajax前一定要導(dǎo)入jquery。
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(function(){ //頁面加載完成時(shí)間
//獲取輸入用戶名的輸入框?qū)ο蟛槠浣壎╫nblur事件
$("#username").blur(function() {
//獲取到用戶輸入的用戶名
var $username = $("#username").val();
//使用AJAX技術(shù)將獲取到的用戶名傳到服務(wù)器后臺(tái)進(jìn)行查詢
$.post(
"${pageContext.request.contextPath}/checkUsername",//url,發(fā)送請(qǐng)求到服務(wù)器的地址
"username="+$username,//請(qǐng)求的參數(shù)
function(data) {//服務(wù)器響應(yīng)成功后執(zhí)行的函數(shù)
//data為服務(wù)器響應(yīng)回的json數(shù)據(jù),將其解析在用戶名輸入框的下方,獲取到該div標(biāo)簽對(duì)象
$("#checkUsername").html(data.message);
if(data.isExist) {
$("#checkUsername").css("color","red");
}else {
$("#checkUsername").css("color","green");
}
},
"json"http://服務(wù)器響應(yīng)的數(shù)據(jù)格式
);
});
});
</script>
2. 服務(wù)器端servlet接收異步請(qǐng)求發(fā)送過來的參數(shù)(用戶輸入的用戶名),將它傳到service層處理,返回查詢到的用戶User。
在servlet層對(duì)User進(jìn)行判斷,根據(jù)User的是否為null設(shè)置bean類ResultBean中的isExsit與message值。將bean類寫回客戶端。
// 編碼
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 獲取異步請(qǐng)求AJAX傳遞的參數(shù)username
String username = request.getParameter("username");
// 調(diào)用業(yè)務(wù)層
try {
CheckNameService service = new CheckNameService();
User user = service.checkUsername(username);
// 在這里使用一個(gè)存儲(chǔ)用戶是否存在boolean和傳回客戶端信息的bean內(nèi)來封裝數(shù)據(jù)
ResultBean resultBean = new ResultBean();
// 判斷用戶名為username的用戶是否存在,給resultBean賦值
if (user == null) {
resultBean.setExist(false);// 說明用戶名不存在
resultBean.setMessage("用戶名不存在,可以使用");
} else {
resultBean.setExist(true);// 說明用戶存在
resultBean.setMessage("用戶名已存在!");
}
// 將封裝后的resultBean轉(zhuǎn)化成json格式的字符串,這里要使用到Gson工具包
Gson gson = new Gson();
String json = gson.toJson(resultBean);
System.out.println(json);
// 將封裝好的json字符串寫回客戶端解析
response.getWriter().write(json);
} catch (SQLException e) {
e.printStackTrace();
}
3. 創(chuàng)建servlet層用到的兩個(gè)bean類:User與ResultBean
4. service層調(diào)用dao層。
CheckNameDAO dao = new CheckNameDAO();
return dao.checkUsername(username);
5. dao層連接數(shù)據(jù)庫查詢是否存在該用戶名的用戶。
QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
String sql = "select * from user where name=?";
return runner.query(sql, new BeanHandler<User>(User.class),username);
6. dao層返回值為User,servlet層判斷是否存在設(shè)置ResultBean的值,客戶端接收resultBean的json值進(jìn)行解析,添加到對(duì)應(yīng)要顯示的位置即可。
這在前面的代碼中也已經(jīng)顯示了。
5. 效果圖

img01.png

img02.png
2. 案例二: 站內(nèi)異步搜索
需求:模仿淘寶搜索寶貝,每次輸入一個(gè)關(guān)鍵字時(shí),異步請(qǐng)求服務(wù)器,去數(shù)據(jù)庫進(jìn)行模糊查詢,將查詢到的商品名返回到客戶端顯示。
分析:
1. 在要添加該功能的div標(biāo)簽后添加一個(gè)div標(biāo)簽,完成布局。
2. 獲取到搜索框的對(duì)象,對(duì)其進(jìn)行mouseup監(jiān)聽,每次觸發(fā)都發(fā)起異步請(qǐng)求,異步請(qǐng)求將搜索框內(nèi)的數(shù)據(jù)傳送到服務(wù)器查詢。
3. 服務(wù)器servlet接收到異步請(qǐng)求ajax發(fā)送過來的參數(shù),將其傳遞到service--dao進(jìn)行模糊查詢,返回查詢到的商品集合,
將其封裝成json字符串響應(yīng)回客戶端。
4. 客戶端接收到響應(yīng)的數(shù)據(jù),解析json并將其添加到添加的div標(biāo)簽內(nèi)。
2.1 jsp布局
在用戶的search搜索輸入框的div中添加一個(gè)div,為搜索聯(lián)想框.
css屬性:
1. display為none,不可見,當(dāng)輸入關(guān)鍵字keyup監(jiān)聽時(shí)將其設(shè)置為block可見。
2. position:absolute。設(shè)置該div是獨(dú)立的,防止對(duì)父標(biāo)簽div的布局影響。
3. z-index:999.設(shè)置z軸上的優(yōu)先級(jí),數(shù)字越大布局越在上方。
<div id="returnKey" style="display:none;width: 196px;height: 80px;position:
absolute;background-color: white;z-index: 999" ></div>
獲取到搜索輸入框元素,為搜索輸入框添加鍵盤監(jiān)聽事件:
通過監(jiān)聽事件,用戶每次輸入關(guān)鍵字,松開鍵時(shí)觸發(fā)searchKeyWords()方法。
該方法獲取到用戶輸入的關(guān)鍵字?jǐn)?shù)據(jù),利用異步請(qǐng)求ajax技術(shù)將其發(fā)送到服務(wù)器查詢數(shù)據(jù)庫。
function中的data為服務(wù)器返回的商品List集合,遍歷集合,在添加的搜索聯(lián)想框div中添加div標(biāo)簽,將商品的名字一一添加進(jìn)去。
//用戶輸入搜索關(guān)鍵字產(chǎn)生的聯(lián)想
function searchKeyWords() {
$("#returnKey").css("display","block");
//獲取搜索框的輸入的關(guān)鍵字
var $keyWords = $("#searchWords").val();
//使用異步請(qǐng)求將獲取到的關(guān)鍵字發(fā)送到服務(wù)器進(jìn)行查詢
if($keyWords!="") {
$.post(
"${pageContext.request.contextPath}/searchWords",//url
"keyWords="+$keyWords,//請(qǐng)求發(fā)送的參數(shù)
function(data) {//服務(wù)器響應(yīng)成功后執(zhí)行的函數(shù)
//將服務(wù)器響應(yīng)回的數(shù)據(jù)解析寫到id為returnKey的div中
var resultString = "";
for (var i = 0; i < data.length; i++) {
resultString += "<div onclick='insertContent(this)' onmouseover='changeColor(this)' onmouseout='backColor(this)' style='margin-left: 5px;margin-top: 3px'>"+data[i].pname+"</div>";
}
$("#returnKey").html(resultString);
},
"json"http://服務(wù)器返回的數(shù)據(jù)格式
);
}
}
</script>
2.2 服務(wù)器Servlet處理異步請(qǐng)求發(fā)送過來的關(guān)鍵字
servlet將請(qǐng)求的參數(shù)keyWords傳至service層/dao層在數(shù)據(jù)庫中模糊查詢,將查詢到的商品數(shù)據(jù),轉(zhuǎn)換為json字符串寫回客戶端。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//編碼
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//獲取ajax傳遞過來的參數(shù)keywords
String keyWords = request.getParameter("keyWords");
try {
//調(diào)用業(yè)務(wù)邏輯層,將獲取到的keywords傳遞到service---dao
SearchKeyWordsService service = new SearchKeyWordsService();
List<Product> list = service.searchKeyWords(keyWords);
//將返回的list商品數(shù)據(jù)轉(zhuǎn)化為json格式的字符串傳回客戶端
Gson gson = new Gson();
String json = gson.toJson(list);
//寫回客戶端
response.getWriter().write(json);
} catch (Exception e) {
e.printStackTrace();
}
2.3 service層
SearchKeyWordsDAO dao = new SearchKeyWordsDAO();
return dao.searchKeyWords(keyWords);
2.4 dao層
sql語句limit限制查詢的條數(shù),這樣就能控制顯示的聯(lián)想數(shù)量
QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
String sql = "select * from products where pname like ? limit 3";
return runner.query(sql, new BeanListHandler<Product>(Product.class), "%"+keyWords.trim()+"%");
2.5 jsp界面優(yōu)化
- 用戶選擇關(guān)鍵字后,將該關(guān)鍵字添加到輸入框中
- 關(guān)鍵字添加到輸入框后,聯(lián)想框的display屬性再次設(shè)置為none
- 用戶將鼠標(biāo)移至聯(lián)想條目時(shí),變色,移出時(shí),恢復(fù)
<script type="text/javascript">
//鼠標(biāo)移到條目上方時(shí)給搜索條目增加背景色
function changeColor(obj) {
$(obj).css("background-color","#ccc");
}
//鼠標(biāo)移出條目上方時(shí)給搜索條目還原背景色
function backColor(obj) {
$(obj).css("background","white");
}
//用戶點(diǎn)擊聯(lián)想商品名稱時(shí),將該商品名添加到搜索框中
function insertContent(obj) {
var $pname = $(obj).html();//獲得搜索聯(lián)想的商品名
//點(diǎn)擊時(shí)將該商品名加入到搜索輸入框中
$("#searchWords").val($pname);
//隱藏聯(lián)想框
$("#returnKey").css("display","none");
}
</script>
***
####~~~歡迎指正交流...