1. 級聯下拉列表
例1.1 級聯下拉列表。
(1)編寫AjaxRequest.js文件,並將其保存到JS文件夾中。AjaxRequest.js的具體代碼如下:
var net = new Object(); //定義一個全局變量net //編寫構造函數 net.AjaxRequest=function(url,onload,onerror,method,params){ this.req = null; this.onload = onload; this.onerror=(onerror)?onerror:this.defaultError; this.loadDate(url,method,params); } //編寫用於初始化XMLHttpRequest對象並指定處理函數,最后發送HTTP請求的方法 net.AjaxRequest.prototype.loadDate=function(url,method,params){ if(!method){ method="GET"; } if(window.XMLHttpRequest){ this.req=new XMLHttpRequest(); }else if(window.ActiveXObject){ this.req = new ActiveXObject("Microsoft.XMLHTTP"); } if(this.req){ try{ var loader = this; this.req.onreadystatechange=function(){ net.AjaxRequest.onReadyState.call(loader); } this.req.open(method,url,true); //建立對服務器的調用 if(method=="POST"){ this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //設置請求頭 } this.req.send(params); }catch(err){ this.onerror.call(this); } } } //重構回調函數 net.AjaxRequest.onReadyState = function(){ var req=this.req; var ready=req.readyState; if(ready==4){ if(req.status==200){ this.onload.call(this); }else{ this.onerror.call(this); } } } //重構默認的錯誤處理函數 net.AjaxRequest.prototype.defaultError = function(){ alert("錯誤數據\n\n回調狀態:"+this.req.readyState+"\n狀態:"+this.req.status); }
(2)編寫index.jsp文件,並在該文件中包含AjaxRequest.js文件,具體代碼如下:
<script language="javascript" src="JS/AjaxRequest.js"></script>
(3)在index.jsp頁面中編寫錯誤處理的函數、實例化Ajax對象的方法和回調函數。在本例中,涉及兩次異步操作,所以需要編寫兩個實例化Ajax對象的方法和回調函數。
編寫實例化用於異步獲取省份和直轄市的Ajax對象的方法和回調函數。具體代碼如下:
function getProvince(){ var loader=new net.AjaxRequest("ZoneServlet?action=getProvince&nocache="+new Date().getTime(), deal_getProvince, onerror, "GET"); } function deal_getProvince(){ //通過循環將數組中的省份名稱添加到下拉列表中 provinceArr=this.req.responseText.split(","); //將獲取的省份名稱字符串分割為數組 for(i=0;i<provinceArr.length;i++){ document.getElementById("province").options[i]=new Option(provinceArr[i],provinceArr[i]); } if(provinceArr[0]!=""){ getCity(provinceArr[0]); //獲取市縣 } } window.onload=function(){ getProvince(); }
編寫實例化用於異步獲取市縣的Ajax對象的方法和回調函數,以及錯誤處理函數。具體代碼如下:
function getCity(selProvince){ var loader=new net.AjaxRequest("ZoneServlet?action=getCity&parProvince="+selProvince+"&nocache="+new Date().getTime(), deal_getCity, onerror, "GET"); } function deal_getCity(){ cityArr=this.req.responseText.split(","); //將獲取的市縣名稱字符串分割為數組 document.getElementById("city").length=0; //清空下拉列表 for(i=0;i<cityArr.length;i++){ document.getElementById("city").options[i]=new Option(cityArr[i],cityArr[i]); } } function onerror(){} //錯誤處理函數
(4) 在頁面中添加設置省份和直轄市的下拉列表,名稱為province和設置市縣的下拉列表,名稱為city,並在省份和直轄市下拉列表的onchange事件中,調用getCity()方法獲取省份對應的市縣。具體代碼如下:
<select name="province" id="province" onchange="getCity(this.value)"></select> <select name="city" id="city"></select>
(5)編寫獲取居住地的Servlet實現類ZoneServlet,在該Servlet中的doGet()方法中,編寫以下代碼用於根據傳遞的action參數,執行不同的處理方法。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); //獲取action參數的值 if("getProvince".equals(action)){ //獲取省份和直轄市信息 this.getProvince(request,response); }else if("getCity".equals(action)){ //獲取市縣信息 this.getCity(request,response); } }
(6)在ZoneServlet中,編寫getProvince()方法。在該方法中,將省份信息連接為一個以逗號分隔的字符串輸出到頁面上(本例比較簡單實際當中應采用Map存放省份與市縣信息)。具體代碼如下:
/** * 獲取省份和直轄市 * @param request * @param response * @throws ServletException * @throws IOException */ public void getProvince(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("GBK"); String result="吉林"; response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.print(result); //輸出獲取的省份字符串 out.flush(); out.close(); }
(7)在ZoneServlet中,編寫個getCity()方法。在該方法中,中獲取指定省份對應的市縣信息,並將獲取的是市縣信息連接成一個以逗號分隔的字符串輸出到頁面上。具體代碼如下:
/** * 獲取市縣 * @param request * @param response * @throws ServletException * @throws IOException */ public void getCity(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("GBK"); String result="長春,延邊,白山,白城,四平,遼源"; response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.print(result); //輸出獲取的市縣字符串 out.flush(); out.close(); }
(8) 為了在頁面載入后顯示默認的省份,還需要在頁面的onload事件中調用獲取省份的方法getProvince()。具體代碼如下:
window.onload=function(){
getProvince(); //獲取省份和直轄市
}
運行本實例index.jsp,結果如下所示:
2. 顯示進度條
文件上傳是一個很費時的任務,經常需要用戶進行長時間等待,為了讓用戶在等待的過程中,即使了解上傳的進度,可以在進行文件上傳時,顯示上傳進度條。下面將介紹如何實現帶進度條的文件上傳。
例2.1 顯示進度條。
(1) 編寫index.jsp頁面,在該頁面中添加用於獲取上傳文件所需信息的表單及表單元素。由於要實現文件上傳,所以需要將表單的enctype屬性設置為multipart/form-data。關鍵代碼如下:
<form name="form1" enctype="multipart/form-data" method="post" action="UpLoad?action=uploadFile">
<div align="center">
請選擇要上傳的文件:<input type="file" name="file" size="42"><br>
<input type="button" name="shangchuan" value="上傳" width="61" height="23" onClick="deal(form1)">
<input type="button" name="chongzhi" value="重置" width="61" height="23" onClick="form1.reset();">
</div>
</form>
(2)在index.jsp頁面的合適位置添加用於顯示進度條的<div>標記和顯示百分比的<span>標記。具體代碼如下:
<div id="progressBar" class="prog_border" align="left"><img src="images/progressBar.png" width="0" height="13" id="imgProgress"> </div> ?<span id="progressPercent" style="width:40px;display:none">0%</span>
(3)在CSS樣式表文件style.css中,添加用於控制進度條樣式的CSS樣式。具體代碼如下:
.prog_border{ height:15px; //高度 widht:255px; //寬度 background:#9ce0fd; //背景顏色 border:1px solid #FFFFFF; //邊框樣式 margin:0; padding:0; display:none; position:relative left:25px; float:left; //居左對齊 }
(4)在index.jsp頁面的<head>標記中,編寫自定義的JavaScript函數deal(),用於提交表單並設置每隔500毫秒獲取一次上傳進度。deal()函數的具體代碼如下:
<script type="text/javascript"> function deal(form){ form.submit(); //提交表單 timer=window.setInterval("getProgress()", 500); //每隔500毫秒獲取一次上傳進度 }
</script>
(5)編寫上傳文件的Servlet實現類UpLoad。在該Servlet中編寫實現文件上傳的方法uploadFile()。在uploadFile()方法中,將調用Common-FileUpload組件分段上傳文件,並計算上傳百分比,將其實時保存到Session中。
Apache commons-fileupload 的使用:
1) 去 http://commons.apache.org/fileupload/ 下載fileupload jar包
同時下載 commons-fileupload 和 commons-io 兩個包 -------- 因為fileupload依賴io包
2) 將jar包導入 web 工程WEB-INF/lib下
uploadFile()方法的具體代碼如下:
package com.cn.Ajax; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UpLoad extends HttpServlet { public void uploadFile(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=GBK"); request.setCharacterEncoding("GBK"); HttpSession session=request.getSession(); session.setAttribute("progressBar", 0); //定義上傳進度的Session變量 String error = ""; int maxSize = 50*1024*1024; //單個文件上傳大小的上限 DiskFileItemFactory factory = new DiskFileItemFactory(); //基於磁盤文件項目創建一個工廠對象 ServletFileUpload upload = new ServletFileUpload(factory); //創建一個新的文件上傳對象 try { List items = upload.parseRequest(request); //解析上傳請求 Iterator itr = items.iterator(); //枚舉方法 while(itr.hasNext()){ FileItem item =(FileItem) itr.next(); //獲取FileItem對象 if(!item.isFormField()){ //判斷是否為文件域 if(item.getName()!=null&&!item.getName().equals("")){ //判斷是否選擇了文件 long upFileSize = item.getSize(); //上傳文件的大小 String fileName = item.getName(); //獲取文件名 if(upFileSize>maxSize){ error="您上傳的文件太大,請選擇不超過50MB的文件"; break; } //此時文件暫存在服務器的內存中 File tempFile = new File(fileName); //構造臨時對象 //獲取根目錄對應的真實物理路徑 File file = new File(request.getRealPath("/upload"),tempFile.getName()); InputStream is = item.getInputStream(); int buffer=1024; int length =0; byte[] b=new byte[buffer]; double percent=0; FileOutputStream fos = new FileOutputStream(file); while((length=is.read(b))!=-1){ percent += length/(double)upFileSize*100D; //計算上傳文件的百分比 fos.write(b,0,length); //向文件輸出流寫讀取的數據 session.setAttribute("progressBar", Math.round(percent)); //將上傳百分比保存到Session中 } fos.close(); Thread.sleep(1000); //線程休眠1秒 }else { error="沒有選擇上傳文件!"; } } } } catch (Exception e) { e.printStackTrace(); error = "上傳文件出現錯誤:"+e.getMessage(); } if(!"".equals(error)){ request.setAttribute("error", error); request.getRequestDispatcher("error.jsp").forward(request, response); }else { request.setAttribute("result", "文件上傳成功!"); request.getRequestDispatcher("upFile_deal.jsp").forward(request, response); } } }
(6)由於要使用Ajax,所以需要創建一個封裝Ajax必須實現功能的對象AjaxRequest,並將其代碼保存為AjaxRequest.js,
AjaxRequest.js
var net = new Object(); //定義一個全局變量net //編寫構造函數 net.AjaxRequest=function(url,onload,onerror,method,params){ this.req = null; this.onload = onload; this.onerror=(onerror)?onerror:this.defaultError; this.loadDate(url,method,params); } //編寫用於初始化XMLHttpRequest對象並指定處理函數,最后發送HTTP請求的方法 net.AjaxRequest.prototype.loadDate=function(url,method,params){ if(!method){ method="GET"; } if(window.XMLHttpRequest){ this.req=new XMLHttpRequest(); }else if(window.ActiveXObject){ this.req = new ActiveXObject("Microsoft.XMLHTTP"); } if(this.req){ try{ var loader = this; this.req.onreadystatechange=function(){ net.AjaxRequest.onReadyState.call(loader); } this.req.open(method,url,true); //建立對服務器的調用 if(method=="POST"){ this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //設置請求頭 } this.req.send(params); }catch(err){ this.onerror.call(this); } } } //重構回調函數 net.AjaxRequest.onReadyState = function(){ var req=this.req; var ready=req.readyState; if(ready==4){ if(req.status==200){ this.onload.call(this); }else{ this.onerror.call(this); } } } //重構默認的錯誤處理函數 net.AjaxRequest.prototype.defaultError = function(){ alert("錯誤數據\n\n回調狀態:"+this.req.readyState+"\n狀態:"+this.req.status); }
然后在index.jsp頁面中通過以下代碼包含該文件:
<script language="javascript" src="JS/AjaxRequest.js"></script>
說明:通常情況下,在處理POST請求時,需要將請求頭設置為application/x-www-form-urlencoded。但是,如果將表單的enctype屬性設置為multipart/form-data,在處理請求時,就需要將請求頭設置為multipart/form-data。
(7)在index.jsp頁面中,編寫自定義的JavaScript函數getProgress(),用於實例化Ajax對象。getProgress()函數的具體代碼如下:
function getProgress(){ var loader=new net.AjaxRequest("showProgress.jsp?nocache="+new Date().getTime(), deal_p, onerror, "GET"); }
在上面的代碼中一定要加代碼“?nocache="+new Date().getTime()”,否則將出現進度不更新的情況。
(8)編寫showProgress.jsp頁面,在該頁面中只需要應用EL表達式輸出保存上傳進度的Session變量。具體代碼如下:
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> ${progressBar}
(9)編寫Ajax的回調函數deal_p(),用於顯示上傳進度條及完成的百分比。deal_p()函數的具體代碼如下:
function deal_p(){ var h=this.req.responseText; h=h.replace(/\s/g,""); //去除字符串中的Unicode空白符 document.getElementById("progressPercent").style.display="";//現實百分比 progressPercent.innerHTML=h+"%"; //顯示完成的百分比 document.getElementById("progressBar").style.display="block"; //顯示進度條 document.getElementById("imgProgress").width=h*(255/100); //顯示完成的進度 }
(10)編寫Ajax的錯誤處理函數onerror(),在該函數中,添加彈出“出錯了”提示對話框的代碼。onerror()函數的具體代碼如下:
function onerror(){ alert("上傳文件出錯!"); }
(11)編寫error.jsp和upFile_deal.jsp代碼如下:
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!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=GB18030"> <title>Insert title here</title> </head> <body> ${error}<br> </body> </html>
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!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=GB18030"> <title>Insert title here</title> </head> <body> ${result}<br> </body> </html>
完整的index.jsp頁面代碼如下:
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!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=GB18030"> <title>Insert title here</title> <script type="text/javascript"> function deal(form){ form.submit(); //提交表單 timer=window.setInterval("getProgress()", 500); //每隔500毫秒獲取一次上傳進度 } function getProgress(){ var loader=new net.AjaxRequest("showProgress.jsp?nocache="+new Date().getTime(), deal_p, onerror, "GET"); } function deal_p(){ var h=this.req.responseText; h=h.replace(/\s/g,""); //去除字符串中的Unicode空白符 document.getElementById("progressPercent").style.display="";//現實百分比 progressPercent.innerHTML=h+"%"; //顯示完成的百分比 document.getElementById("progressBar").style.display="block"; //顯示進度條 document.getElementById("imgProgress").width=h*(255/100); //顯示完成的進度 } function onerror(){ alert("上傳文件出錯!"); } </script> </head> <body> <form name="form1" enctype="multipart/form-data" method="post" action="UpLoad"> <div align="center"> 請選擇要上傳的文件:<br> <input type="file" name="file" size="42"><br> 注:文件大小請控制在50M以內。 </div> <table align="center"> <tr> <td align="left"> <div id="progressBar" class="prog_border" align="left"><img src="images/progressBar.png" width="0" height="13" id="imgProgress"></div> </td> <td> <span id="progressPercent" style="width:40px;display:none">0%</span> </td> </tr> </table> <div align="center"> <input type="button" name="shangchuan" value="上傳" width="61" height="23" onClick="deal(form1)"> <input type="button" name="chongzhi" value="重置" width="61" height="23" onClick="form1.reset();"> </div> </form> <script language="javascript" src="JS/AjaxRequest.js"></script> </body> </html>
運行結果如下圖所示: