通過(guò)前面四章的介紹,相信讀者已經(jīng)掌握了Ajax核心技術(shù)的相關(guān)設(shè)計(jì)方法,如:核心對(duì)象XMLHttpRequest,與Ajax相關(guān)的JavaScript腳本技術(shù)、DOM文檔對(duì)象化模型、以及用于存儲(chǔ)、傳送數(shù)據(jù)的XML文檔,和控制顯示輸出的CSS及XHTL。
為了能夠讓讀者熟悉更加靈活的Ajax應(yīng)用方案,本章將通過(guò)若干實(shí)際案例的實(shí)現(xiàn)過(guò)程幫助讀者積累更多Ajax實(shí)戰(zhàn)的經(jīng)驗(yàn),體會(huì)更多Ajax應(yīng)用的魅力。本章將實(shí)現(xiàn)常見(jiàn)的表單數(shù)據(jù)驗(yàn)證、Web頁(yè)面中級(jí)聯(lián)菜單的效果、動(dòng)態(tài)加載列表框、自動(dòng)刷新頁(yè)面、Web頁(yè)面的局部動(dòng)態(tài)更新以及自動(dòng)完成功能等。相信豐富的實(shí)例一定可以幫助讀者在短時(shí)間內(nèi)體驗(yàn)Ajax的方便、靈活、人性化的交互方式。
5.1 實(shí)現(xiàn)表單數(shù)據(jù)驗(yàn)證
為保證數(shù)據(jù)的有效性,杜絕錯(cuò)誤、無(wú)效的信息存儲(chǔ)到數(shù)據(jù)庫(kù)中,對(duì)于接收到的瀏覽器客戶端提交的數(shù)據(jù),需要進(jìn)行基本的有效性、合理性的檢查。在傳統(tǒng)的Web應(yīng)用中,客戶端一般采用JavaScript腳本所聲明的函數(shù),對(duì)提交的表單數(shù)據(jù)進(jìn)行驗(yàn)證,但是這種方式并不能解決所有的驗(yàn)證問(wèn)題,例如,在進(jìn)行用戶信息注冊(cè)時(shí),客戶端只能實(shí)現(xiàn)類(lèi)似是否填寫(xiě)了必要的信息、長(zhǎng)度是否滿足需求等基本的有效性檢查,但是對(duì)于所填寫(xiě)的用戶信息是否已經(jīng)被占用等諸如此類(lèi)的檢查,在客戶端腳本中是沒(méi)有辦法實(shí)現(xiàn)的。
同時(shí),如果按照傳統(tǒng)的方式將此類(lèi)驗(yàn)證邏輯放在服務(wù)器端實(shí)現(xiàn),也會(huì)因?yàn)槊媾R需要整個(gè)頁(yè)面刷新的問(wèn)題而使得問(wèn)題不能以直觀的方式迅速顯示在用戶面前。借助Ajax技術(shù),在異步交互的前提下,調(diào)用服務(wù)器端事先編寫(xiě)好的驗(yàn)證邏輯可以很好地解決此問(wèn)題。
下面,我們實(shí)現(xiàn)一個(gè)對(duì)注冊(cè)用戶信息進(jìn)行驗(yàn)證的實(shí)例,該實(shí)例所實(shí)現(xiàn)的效果如圖5-1所示。用戶首先在表單中填寫(xiě)用戶注冊(cè)信息,當(dāng)用戶單擊“注冊(cè)”按鈕后,將對(duì)用戶所填寫(xiě)的信息進(jìn)行驗(yàn)證,如果用戶沒(méi)有填寫(xiě)用戶名,或者密碼輸入的不一致,都會(huì)在頁(yè)面中顯示對(duì)應(yīng)的提示信息,此外,當(dāng)用戶所填寫(xiě)的用戶名已經(jīng)被占用時(shí),Ajax所調(diào)用的服務(wù)器端處理程序同樣會(huì)返回提示信息。



圖5-1 表單數(shù)據(jù)驗(yàn)證的效果
首先在Eclipse中新建一個(gè)Web項(xiàng)目,項(xiàng)目名稱為P51_SignUp,對(duì)應(yīng)的瀏覽器端頁(yè)面代碼如下所示。在該頁(yè)面中提供了對(duì)應(yīng)的表單以供用戶填寫(xiě)注冊(cè)信息,當(dāng)用戶填寫(xiě)信息,單擊“注冊(cè)”按鈕后,將調(diào)用signUp()函數(shù),在該函數(shù)中首先借助DOM獲取對(duì)應(yīng)表單元素中用戶填寫(xiě)的數(shù)據(jù)信息,進(jìn)行基本的有效性驗(yàn)證,如果用戶沒(méi)有填寫(xiě)用戶名,將顯示“用戶名不能為空”的提示信息,如果用戶輸入的兩遍密碼不一致,將顯示“兩次輸入密碼不同”的提示信息。如果瀏覽器端的數(shù)據(jù)有效性檢查通過(guò),此后,再借助Ajax提交請(qǐng)求,并同時(shí)提交用戶填寫(xiě)的信息,到服務(wù)器端,等待服務(wù)器端的處理。當(dāng)服務(wù)器端后續(xù)處理完成后,將返回對(duì)應(yīng)的響應(yīng)信息,在瀏覽器客戶端進(jìn)行顯示。
源文件:login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head>
<META http-equiv=Content-Type content="text/html; charset=UTF-8">
</head>
<script language="javascript">
var XMLHttpReq;
//創(chuàng)建XMLHttpRequest對(duì)象
function createXMLHttpRequest() {
if(window.XMLHttpRequest) { //Mozilla 瀏覽器
XMLHttpReq = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE瀏覽器
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}
//發(fā)送請(qǐng)求函數(shù)
function sendRequest(url) {
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
XMLHttpReq.onreadystatechange = processResponse;//指定響應(yīng)函數(shù)
XMLHttpReq.send(null); // 發(fā)送請(qǐng)求
}
// 處理返回信息函數(shù)
function processResponse() {
if (XMLHttpReq.readyState == 4) { // 判斷對(duì)象狀態(tài)
if (XMLHttpReq.status == 200) { // 信息已經(jīng)成功返回,開(kāi)始處理信息
var res=XMLHttpReq.responseXML.getElementsByTagName("res")[0]. firstChild.data;
window.alert(res);
} else { //頁(yè)面不正常
window.alert("您所請(qǐng)求的頁(yè)面有異常。");
}
}
}
// 注冊(cè)函數(shù)
function signUp() {
var uname = document.myform.uname.value;
var psw = document.myform.psw.value;
var psw2 = document.myform.psw2.value;
if (uname=="") {
window.alert("用戶名不能為空。");
document.myform.uname.focus();
return false;
}
elseif(psw!=psw2) {
window.alert("兩次輸入密碼不同。");
document.myform.psw.focus();
return false;
}
else {
sendRequest('signUp?uname='+ uname + '&psw=' + psw);
}
}
</script>
<body vLink="#006666" link="#003366" bgColor="#E0F0F8">
<img height="33" src="enter.gif" width="148">
<form action="" method="post" name="myform">
用戶名: <input size="15" name="uname"><p>
密 碼: <input type="password" size="15" name="psw"><p>
重輸密碼: <input type="password" size="20" name="psw2"><p>
<input type="button" value="注冊(cè)" onclick="signUp()" >
</form>
該Web應(yīng)用的配置文件web.xml對(duì)應(yīng)的代碼如下所示。從該配置文件中可以了解到,當(dāng)瀏覽器端提交“signUp”請(qǐng)求時(shí),將由服務(wù)器端的類(lèi)名為“classmate.SignUpAction”的Servlet程序進(jìn)行處理。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>ms1</servlet-name>
<servlet-class>classmate.SignUpAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ms1</servlet-name>
<url-pattern>/signUp</url-pattern>
</servlet-mapping>
<!-- The Welcome File List -->
<welcome-file-list>
<welcome-file>signUp.jsp</welcome-file>
</welcome-file-list>
</web-app>
下面我們關(guān)注一下服務(wù)器端Servlet程序SignUpAction.java中對(duì)應(yīng)的程序代碼??梢钥吹皆诮邮盏綖g覽器端提交的請(qǐng)求后,Servlet程序?qū)⑹紫全@取瀏覽器端提交的用戶名及密碼信息,然后借助封裝了數(shù)據(jù)庫(kù)操作的JavaBean完成依據(jù)數(shù)據(jù)庫(kù)中存儲(chǔ)的注冊(cè)用戶信息進(jìn)行驗(yàn)證的目的。
package classmate;
……
public class SignUpAction extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
}
/*
* 處理<GET> 請(qǐng)求方法
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//設(shè)置接收信息的字符集
request.setCharacterEncoding("UTF-8");
//接收瀏覽器端提交的信息
String uname = request.getParameter("uname");
String psw = request.getParameter("psw");
//設(shè)置輸出信息的格式及字符集
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
//創(chuàng)建輸出流對(duì)象
PrintWriter out = response.getWriter();
//依據(jù)驗(yàn)證結(jié)果輸出不同的數(shù)據(jù)信息
out.println("<response>");
//數(shù)據(jù)庫(kù)操作
DB db = new DB();
ResultSet rs;
int insRes = 0;
String strSql=null;
//判斷用戶名是否重復(fù)
strSql = "select * from classuser where username='"
+ uname + "'";
rs = db.executeQuery(strSql);
boolean bnoRepeat = false;
try {
if ( !rs.next()) {
bnoRepeat = true;
}
} catch (SQLException e) {
e.printStackTrace();
}
//用戶名不重復(fù),插入記錄
if(bnoRepeat){
strSql = "Insert Into classuser values('"+ uname + "','" + psw + "')";
insRes = db. executeUpdate(strSql);
}
System.out.println(uname);
if(!bnoRepeat){
out.println("<res>" + "注冊(cè)失敗!用戶名已存在,重新輸入用戶名" + "</res>");
}elseif(insRes>0){
out.println("<res>" + "注冊(cè)成功!" + "</res>");
}else{
out.println("<res>" + "注冊(cè)失敗!" + "</res>");
}
out.println("</response>");
out.close();
}
}
在進(jìn)行服務(wù)器端驗(yàn)證時(shí),如果用戶名沒(méi)有被占用,會(huì)將對(duì)應(yīng)的用戶信息插入到數(shù)據(jù)庫(kù)中去,并返回“注冊(cè)成功”的信息,如果用戶名已經(jīng)被占用,將返回“注冊(cè)失敗!用戶名已占用,請(qǐng)重新輸入用戶信息”的提示,其他原因的注冊(cè)不成功,將顯示“注冊(cè)失敗”的信息,信息都是以XML文檔的格式返回客戶端的。
采用Ajax技術(shù),可以看到頁(yè)面并沒(méi)有進(jìn)行完全的刷新,這無(wú)疑會(huì)給注冊(cè)信息的用戶帶來(lái)更好的感受,同時(shí)數(shù)據(jù)信息的有效性問(wèn)題也得到了很好的解決。