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



圖5-1 表單數據驗證的效果
首先在Eclipse中新建一個Web項目,項目名稱為P51_SignUp,對應的瀏覽器端頁面代碼如下所示。在該頁面中提供了對應的表單以供用戶填寫注冊信息,當用戶填寫信息,單擊“注冊”按鈕后,將調用signUp()函數,在該函數中首先借助DOM獲取對應表單元素中用戶填寫的數據信息,進行基本的有效性驗證,如果用戶沒有填寫用戶名,將顯示“用戶名不能為空”的提示信息,如果用戶輸入的兩遍密碼不一致,將顯示“兩次輸入密碼不同”的提示信息。如果瀏覽器端的數據有效性檢查通過,此后,再借助Ajax提交請求,并同時提交用戶填寫的信息,到服務器端,等待服務器端的處理。當服務器端后續處理完成后,將返回對應的響應信息,在瀏覽器客戶端進行顯示。
源文件: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;
//創建XMLHttpRequest對象
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) {}
}
}
}
//發送請求函數
function sendRequest(url) {
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
XMLHttpReq.onreadystatechange = processResponse;//指定響應函數
XMLHttpReq.send(null); // 發送請求
}
// 處理返回信息函數
function processResponse() {
if (XMLHttpReq.readyState == 4) { // 判斷對象狀態
if (XMLHttpReq.status == 200) { // 信息已經成功返回,開始處理信息
var res=XMLHttpReq.responseXML.getElementsByTagName("res")[0]. firstChild.data;
window.alert(res);
} else { //頁面不正常
window.alert("您所請求的頁面有異常。");
}
}
}
// 注冊函數
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="注冊" onclick="signUp()" >
</form>
該Web應用的配置文件web.xml對應的代碼如下所示。從該配置文件中可以了解到,當瀏覽器端提交“signUp”請求時,將由服務器端的類名為“classmate.SignUpAction”的Servlet程序進行處理。
<?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>
下面我們關注一下服務器端Servlet程序SignUpAction.java中對應的程序代碼。可以看到在接收到瀏覽器端提交的請求后,Servlet程序將首先獲取瀏覽器端提交的用戶名及密碼信息,然后借助封裝了數據庫操作的JavaBean完成依據數據庫中存儲的注冊用戶信息進行驗證的目的。
package classmate;
……
public class SignUpAction extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
}
/*
* 處理<GET> 請求方法
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//設置接收信息的字符集
request.setCharacterEncoding("UTF-8");
//接收瀏覽器端提交的信息
String uname = request.getParameter("uname");
String psw = request.getParameter("psw");
//設置輸出信息的格式及字符集
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
//創建輸出流對象
PrintWriter out = response.getWriter();
//依據驗證結果輸出不同的數據信息
out.println("<response>");
//數據庫操作
DB db = new DB();
ResultSet rs;
int insRes = 0;
String strSql=null;
//判斷用戶名是否重復
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();
}
//用戶名不重復,插入記錄
if(bnoRepeat){
strSql = "Insert Into classuser values('"+ uname + "','" + psw + "')";
insRes = db. executeUpdate(strSql);
}
System.out.println(uname);
if(!bnoRepeat){
out.println("<res>" + "注冊失敗!用戶名已存在,重新輸入用戶名" + "</res>");
}elseif(insRes>0){
out.println("<res>" + "注冊成功!" + "</res>");
}else{
out.println("<res>" + "注冊失敗!" + "</res>");
}
out.println("</response>");
out.close();
}
}
在進行服務器端驗證時,如果用戶名沒有被占用,會將對應的用戶信息插入到數據庫中去,并返回“注冊成功”的信息,如果用戶名已經被占用,將返回“注冊失敗!用戶名已占用,請重新輸入用戶信息”的提示,其他原因的注冊不成功,將顯示“注冊失敗”的信息,信息都是以XML文檔的格式返回客戶端的。
采用Ajax技術,可以看到頁面并沒有進行完全的刷新,這無疑會給注冊信息的用戶帶來更好的感受,同時數據信息的有效性問題也得到了很好的解決。