`

读书笔记: JavaWeb从入门到精通 第13章: Ajax 技术

 
阅读更多

通过阅读本章, 你可以:

  • 了解 Ajax 开发模式与传统开发模式的比较

  • 掌握如何使用 XMLHttpRequest 对象

  • 通过 Ajax 向服务器发送请求

  • 通过 Ajax 处理服务器的响应

  • 通过 Ajax 实现检测用户名是否唯一

  • 进行 Ajax 重构

  • 通过 Ajax 实现实时显示公告信息

  • 通过 Ajax 实现无刷新的级联下拉列表

  • 通过 Ajax 实现上传文件时显示进度条

13.1 当下谁在用 Ajax

13.1.1 百度搜索提示

13.1.2 淘宝新会员免费注册

13.1.3 明日科技编程词典服务网

 

13.2 Ajax 开发模式与传统开发模式的比较

对于每个用户的请求, 在传统的 Web应用 模式中, 将生成一次HTTP请求, 而在 Ajax 应用 开发模式中, 将变成对 Ajax 引擎的一次 JavaScript 调用. 在  Ajax 应用开发模式中 通过 JavaScript 实现在不刷新整个页面的情况下, 对部分数据进行更新, 从而降低了网络流量, 给用户带来更好的体验.

 

13.3 Ajax 使用的技术

Ajax (Asynchronous JavaScript and XML) 是 XMLHttpRequest 对象 和 JavaScript, XML, CSS, DOM 等多种技术的组合. 其中, 只有 XMLHttpRequest 对象是新技术, 其他的均为已有技术. 

XMLHttpRequest 对象

它是一个具有应用程序接口的 Javascript 对象, 能够使用 超文本传输协议(HTTP) 连接服务器, 是微软公司为了满足开发者的需要, 与1999年在 IE5.0 浏览器中率先推出的.

XML

XML 是 eXtensible Markup Language (可扩展的标记语言) 的缩写, 它提供了用于描述结构化数据的格式, 适用于不同应用程序间的数据交换, 而且这种交换不以预先定义的一组数据结构为前提, 增强了可扩展性. XMLHttpRequest 对象与服务器交换的数据通常采用XML格式.

[例13.1] (略)

注意: 在XML文档中, 必须有一个根元素,  所有其他的元素必须嵌入到根元素中.

JavaScript

Ajax 就是利用 JavaScript 将 DOM, XHTML (或 HTML), XML 以及 CSS 等技术综合起来, 并控制它们的行为的. 因为要开发一个复杂高效的 Ajax 应用程序, 就必须对 JavaScript 有深入的了解.

CSS

CSS 是 Cascading Style Sheet ( 层叠样式表) 的缩写, 用于(增强) 控制网页样式并允许将样式信息与网页内容分离的一种标记性语言. 

DOM

DOM 是文档对象模型的简称, 是表示文本(如HTML文档)和访问, 操作构成文档的各种元素(如 HTML标记和文本串) 的应用程序接口. W3C 定义了 标准的 文档对象模型, 它以树形结构表示 HTML 和 XML 文档, 并且定义了 遍历树 和 添加, 修改, 查找树的节点的方法和属性. 在 Ajax 应用中, 通过 JavaScript 操作 DOM, 可以达到在不刷新页面的情况下实时修改用户界面的目的.

 

13.4 使用 XMLHttpRequest 对象

13.4.1 初始化 XMLHttpRequest 对象

IE 浏览器

IE 浏览器把 XMLHttpRequest 实例化为一个 ActiveX 对象. 具体方法如下:

 

1
2
3
var http_request = new ActiveXObject("Msxml2.XMLHTTP");
// or
var http_request = new ActiveXObject("Microsoft.XMLHTTP");

在上面的语法中, Msxml2.XMLHTTP 和 Microsoft.XMLHTTP 是针对 IE 浏览器 的不同版本而进行设置的, 目前比较常用的是这两种.

非IE浏览器

非IE浏览器(如 Chrome, FireFox, Opera, Mozzila, Safari) 把 XMLHttpRequest 对象实例化为一个本地 JavaScript 对象. 具体方法如下:

1
var http_request = new XMLHttpRequest();

为了提高程序的兼容性, 可以创建一个跨浏览器的 XMLHttpRequest 对象. 

1
2
3
4
5
6
7
8
9
10
11
if(window.XMLHttpRequest){    // non-IE browser
    http_request = new XMLHttpRequest();
else if(window.ActiveXObject){    // IE browser
    try{
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
    catch(e){
        try{
            http_request = new ActiveXObject("Microsoft.XMLHTTP");
        }catch(e){}
    }
}

在上面的代码中, 调用 window.ActiveXObject 将返回一个对象, 或是 null. 在 if 语句中, 会把返回值看作是 true 或 false.

13.4.2 XMLHttpRequest 对象的常用方法

open方法

open 方法用于设置进行异步请求目标的 URL, 请求方法以及其他参数. 其具体语法如下:

open("method", "URL", [,asyncFlag,[,"username"[,"password"]]])

参数说明:

method: 指定请求的类型, 一般为 GET 或 POST.

URL: 指定请求地址, 可以是绝对地址或相对地址, 并且可以传递查询字符串.

asyncFlag: 为可选参数, 异步请求为 true, 同步请求为 false, 默认情况下为 true.

username: 为可选参数, 用于指定请求用户名, 没有时可省略.

password: 为可选参数, 用户指定请求密码, 没有时可省略.

[例13.2] 设置异步请求目标为 register.jsp, 请求方法为 GET, 请求方式为异步的代码如下:

 

1
http_request.open("GET""register.jsp"true);

send(content) 方法

send() 方法用于向服务器发送请求. 如果请求声明为异步, 该方法立即返回, 否则将等到接受到响应为止.

content: 用于指定发送的数据, 可以是 DOM 对象的实例, 输入流 或 字符串. 如果没有参数需要传递, 可以设置为null.

[例13.3] 向服务器发送一个不包含任何参数的请求, 可以使用下面的代码:

1
http_request.send(null);

setRequestHeader()方法, 用于为请求的 HTTP头 设置值. 

setRequestHeader("header", "value");

header: 用于指定 HTTP头

value: 用于为指定的 HTTP头 设置值.

注意: setReqeustHeader() 方法必须在调用 open() 方法之后才能调用.

[例13.4] 在发送POST请求时, 需要设置 Content-Type 请求头的值为 "application/x-www-form-urlencoded", 这是就可以通过 setRequestHeader() 方法进行设置. 具体代码如下:

1
http_request.setRequestHeader("Content-Type""application/x-www-form-urlencoded");

abort() 方法用于停止或放弃当前异步请求. 其语法格式如下:

abort()

getResponseHeader()方法, 用于以字符串形式返回指定的 HTTP头 信息.  其语法格式如下:

getResponseHeader("headerLabel")

参数说明:

headerLabel: 用于指定 HTTP头, 包括 Server, Content-Type 和 Date 等.

[例13.5] 要获取 HTTP头 Content-Type 的值, 可以使用以下代码:

1
http_request.getResponseHeader("Content-Type");

上面的代码将获取到类似以下内容:

text/html;charset=GB18030

 

getAllResponseHeaders() 方法, 用于以字符串形式返回完整的 HTTP头 信息, 其中包括 Server, Date, Content-Type 和 Content-Length.

[例13.6] 使用下面的代码调用 getAllResponseHeaders() 方法, 将弹出如图13.6 所示的对话框(省略)显示完整的 HTTP 头信息.

 

13.4.3 XMLHttpRequest 对象的常用属性

onreadystatechange 属性

onreadystatechange 属性用于指定状态改变时所触发的事件处理器. 在 Ajax 中, 每个状态改变时都会触发这个事件处理器, 通常会调用一个JavaScript 函数.

[例13.7] 指定状态改变时触发 JavaScript 函数 getResult 的代码如下:

1
http_request.onreadystatechange = getResult;

注意: 在指定所触发的事件处理器时, 所调用的 JavaScript 函数不能添加小括号以及指定参数名. 不过这里可以使用匿名函数. 例如, 要调用带参数的函数 getResult(), 可以使用下面的代码:

 

1
2
3
http_request.onreadystatechange = function(){
    getResult("添加的参数");  // 调用带参数的函数
};                            // 通过匿名函数来指定要带参数的函数

readyState 属性

 

用于获取请求的状态

表 13.1 readyState 属性的属性值及其意义

 

意义 意义
0
           
未初始化 3 交互中
1 正在加载 4 完成
2 已加载    

responseText 属性: 

用于获取服务器的响应, 表示为支付串.

responseXML 属性:

responseXML 属性用于获取服务器的响应, 表示为 XML. 这个对象可以解析为一个 DOM 对象.

status 属性:

用于返回服务器的 HTTP 状态码, 常用的状态码 如表13.2 所示.

表13.2 status 属性的状态码

 


           
意义 意义
200 表示成功 404 

文件未找                

202 表示请求被接受, 但尚未成功 500 内部服务器错误
400 错误的请求    

statusText 属性

statusText 属性用于返回 HTTP 状态码对应的文本, 如 OK 或 Not Found 等.

 

13.5 与服务器通信--发送请求与处理响应

13.5.1 发送请求

无论发送GET请求还是POST请求, 都需要经过以下 4 个步骤:

(1) 初始化 XMLHttpRequest 对象. 为了提高程序的兼容性, 需要创建一个跨浏览器的 XMLHttpRequst 对象, 并且判断 XMLHttpRequest 对象的实例是否创建成功, 如果不成功, 则给予提示.

[例13.8] 发送请求.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http_request = false;
if(window.XMLHttpRequest){ // non-IE browser
    http_request = new XMLHttpRequest();
}else if(window.ActiveXObject){ // IE browser
    try{
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){
        try{
            http_request = new ActiveXObject("Microsoft.XMLHTTP");
        }catch(e){}
    }
}
if(!http_request){
    alert("无法创建 XMLHttpRequest 对象实例!");
    return false;
}

(2) 为XMLHttpRequest 对象指定一个返回结果处理函数(即 回调函数), 用于对返回结果进行处理. 具体代码如下:

[例13.9] 设置回调函数.

1
http_request.onreadystatechange = getResult; //调用返回结果处理函数

注意: 使用 XMLHttpRequest 对象的 onreadystatechange 属性指定回调函数时, 不能指定要传递的参数.如果要指定传递的参数, 可以使用以下方法:

 

1
http_request.onreadystatechange = function(){ getResult(param) };

(3) 创建一个到服务器的连接. 在创建时, 需要指定发送请求的方式(即GET或POST), 以及设置是否采用异步方式发送请求.

[例13.10] 采用异步方式发送 GET 请求 的具体代码如下:

http_request.open('GET', url, true);

[例13.11] 采用异步方式发送 PSOT 请求的具体代码如下:

http_request.open('POST', url, true);

说明: 在 open() 方法中的 url 参数, 可以是一个 JSP页面的 URL 地址, 也可以是 Servlet 的映射地址.

技巧: 在指定 URL 参数时, 最好将一个时间戳追加到该 URL 参数的后面, 这样可以防止因浏览器缓存结果而不能实时得到最新的结果. 例如, 可以指定 URL参数 为以下代码:

1
String url="deal.jsp?nocache="+new Date().getTime();

(4) 向服务器发送请求. XMLHttpRequest 对象的 send() 方法 可以实现向 服务器发送请求, 该方法需要传递一个参数, 如果发送的是 GET 请求, 可以将该参数设置为null; 如果发送的是 POST 请求, 可以通过该参数指定要发送的 请求参数.

向服务器发送 GET 请求的代码如下:

1
http_request.send(null); // 向服务器发送 GET 请求

[例13.12] 向服务器发送POST请求的代码如下:

 

1
2
3
4
//需要注意的是, 在发送POST请求前,还需要设置正确的请求头
http_request.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
var param="user"+form1.user.value+"&pwd="+form1.pwd.value+&email="+form1.email.value; // 组合参数
http_request.send(param); // 向服务器发送请求

13.5.2 处理服务器响应

  1. 处理字符串响应

    [例13.13] 将字符串响应显示到提示对话框中的回调函数的具体代码如下:


           

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function getResult(){
        if(http_request.readyState == 4){    //判断请求状态
            if(http_request.status == 200){  //判断响应状态
                alert(http_request.responseText);
            else{
                alert("您所请求的页面有错误!");
            }
        }
    }

           

           

    如果需要将响应结果显示到页面的指定位置, 那么可以预先在页面的适当位置添加一个<div>或<span>标记, 并设置其id属性, 然后在回调函数中使用如下代码显示响应结果:


           

    1
    document.getElementById("div_result").innerHTML=http_request.responseText;

           

       

  2. 处理XML响应

[例13.14] 保存图书信息的 XML 文档. 具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<mr>
    <books>
        <book>
            <title>Java Web 程序开发范例宝典</title>
            <publisher>人们邮电出版社</publisher>
        </book>
        <book>
            <title>Java 范例完全自学手册</title>
            <publisher>人们邮电出版社</publisher>
        </book>
    </books>
<mr>

在回调函数中遍历图书信息的XML文档, 并将其显示到页面中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getResult{
    if(http_request.readyState == 4) {  //判断请求状态
        if(http_request.status == 200){ //判断响应状态
            var xmldoc = http_request.responseXML;
            var str="";
            for(i=0;i<xmldoc.getElementsByTagName("book").length;i++){
                var book=xmldoc.getElementsByTagName("book").item(i);
                str=str+" <<"+book.getElementsByTagName("title")[0].firstChild.data+">> 由 "+book.getElementsByTagName("publisher")[0].firstChild.data+" 出版<br>";
            }
            document.getElementById("book").innerHTML=str;
        }else{
            alert("您所请求的页面有错误!");
        }
    }
}
<div id="book"></div>

13.5.3 一个完整的实例 -- 检测用户名是否唯一

[例13.15]检测用户名是否唯一. (实例位置: disc\TM\sl\13\1)

(1)创建index.jsp文件, 在该文件中添加用于收集用户注册信息的表单及表单元素, 以及代表"检测用户名"按钮的图片, 并在该图片的onclick事件中调用 checkName() 函数, 检测用户名是否已被注册.

1
2
3
4
5
6
7
8
9
<form method="post" action="" name="form1">
 
用户名:<input name="username" type="text" id="username" size="32"></td>
        <img src="images/checkBt.jpg" width="104" height="23" style="cursor:hand;" onClick="checkUser(form1.username);"></td>
密码:<input name="pwd1" type="password" id="pwd1" size="35">
确认密码:<input name="pwd2" type="password" id="pwd2" size="35">
E-mail:<input name="email" type="text" id="email" size="45">
<input type="image" name="imageField" src="images/registerBt.jpg">
</form>

(2) 在页面的适当位置添加用于显示提示信息的<div>标记, 并通过CSS设置该<div>标记的样式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style type="text/css">
<!--
#toolTip {
    position:absolute; //设置为绝对路径
    left:331px;        //设置左边距
    top:39px;            //设置顶边距
    width:98px;        //设置宽度
    height:48px;        //设置高度
    padding-top:45px;    //设置文字与顶边的距离
    padding-left:25px;    //设置文字与左边的距离
    padding-right:25px;    //设置文字与右边的距离
    z-index:1;
    display:none;    //设置默认不显示
    color:red;        //设置文字的颜色
    background-image: url(images/tooltip.jpg);//设置背景图片
}
-->
</style>
<div id="toolTip"></div>

(3) 编写JavaScript函数 createRequest().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function createRequest(url) {
    http_request = false;
    if (window.XMLHttpRequest) {                                   // 非IE浏览器
        http_request = new XMLHttpRequest();                          //创建XMLHttpRequest对象
    else if (window.ActiveXObject) {                             // IE浏览器
        try {
            http_request = new ActiveXObject("Msxml2.XMLHTTP");    //创建XMLHttpRequest对象
        catch (e) {
            try {
                http_request = new ActiveXObject("Microsoft.XMLHTTP");  //创建XMLHttpRequest对象
           catch (e) {}
        }
    }
    if (!http_request) {
        alert("不能创建XMLHttpRequest对象实例!");
        return false;
    }
    http_request.onreadystatechange = getResult;                       //调用返回结果处理函数
    http_request.open('GET', url, true);                               //创建与服务器的连接
    http_request.send(null);                                       //向服务器发送请求
}

(4) 编写回调函数 getResult().

1
2
3
4
5
6
7
8
9
10
function getResult() {
    if (http_request.readyState == 4) {             // 判断请求状态
        if (http_request.status == 200) {           // 请求成功,开始处理返回结果
            document.getElementById("toolTip").innerHTML=http_request.responseText; //设置提示内容
            document.getElementById("toolTip").style.display="block";   //显示提示框
        else {                            // 请求页面有错误
            alert("您所请求的页面有错误!");
        }
    }
}

(5) 编写JavaScript函数 checkUser(), 用于检测用户名是否为空, 当用户名不为空时, 调用 createRequest() 函数发送异步请求检测用户名是否已被注册.

1
2
3
4
5
6
7
function checkUser(userName){
    if(userName.value==""){
        alert("请输入用户名!");userName.focus();return;
    }else{
        createRequest('checkUser.jsp?user='+userName.value);
    }
}

(6) 编写检测用户名是否已被注册的处理页checkUser.jsp.

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" import="java.util.*" pageEncoding="GB18030" %>
<%
    String[] userList={"明日科技","mr","mrsoft","wgh"};         //创建一个一维数组
    String user=new String(request.getParameter("user").getBytes("ISO-8859-1"),"GB18030");  //获取用户名
    Arrays.sort(userList);                                  //对数组排序
    int result=Arrays.binarySearch(userList,user);              //搜索数组
    if(result>-1){
        out.println("很抱歉,该用户名已经被注册!");          //输出检测结果
    }else{
        out.println("恭喜您,该用户名没有被注册!");          //输出检测结果
    }
%>

说明: 由于本实例比较简单, 这里没有从数据库中获取用户列表, 而是将用户列表保存在一个一维数组中. 在实际项目开发时, 通常情况下是从数据库中获取用户信息.

图13.7 检测用户名

 

13.6 解决中文乱码问题

Ajax 不支持多种字符集, 其默认的字符集是 UTF-8, 所以在使用 Ajax 技术的程序中, 应及时进行编码转换, 否则程序中出现的中文字符将变成乱码.

 

13.6.1 发送请求时出现中文乱码

(1) 当接收使用GET方法提交的数据时, 要将编码转换为 GBK 或 UTF-8.

1
2
String selProvince=request.getParameter("parProvince");
selProvince=new String(selProvince.getBytes("ISO-8859-1"),"UTF-8");

(2)用于使用POST方法提交数据时, 默认的字符编码是 UTF-8, 所以当接收使用 POST 方法提交的数据时, 要将编码转换为UTF-8.

1
2
String username=request.getParameter("user");
username=new String(username.getBytes("ISO-8859-1"),"UTF-8");

13.6.2 获取服务器的响应结果时出现中文乱码

由于 Ajax 在接收 responseText 或 responseXML 的值时是按照 UTF-8 的编码格式进行解码的, 所以如果服务器端传递的数据不是UTF-8格式, 在接收 responseText 或 responseXML 的值时, 就可能产生乱码. 解决的办法是 确保从服务器端传递的数据采用 UTF-8 的编码格式.

 

13.7 Ajax 重构

13.7.1 Ajax 重构的步骤

(1) AjaxRequest.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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") {// 如果提交方式为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) 在需要使用 Ajax 的页面中使用如下语句

1
<script language="javascript" src="AjaxRequest.js"></script>

 

(3) 在使用 Ajax的页面中编写错误处理方法, 实例化 Ajax 对象的方法和回调函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script language="javascript">
/**错误处理的方法**/
function onerror(){
    alert("您的操作有误!");
}
/**实例化Ajax对象的方法**/
function getInfo(){
    var loader=new net.AjaxRequest("getInfo.jsp?nocache="+new Date().getTime(), deal_getInfo, onerror, "GET");
}
/**回调函数**/
function deal_getInfo(){
    document.getElementById("showInfo").innerHTML=this.req.responseText;
}
</script>

 

131.7.2 使用 Ajax 重构实现实时显示公告信息

[例13.17] 实时显示公告信息. (实例位置: disc\TM\sl\13\2)

(1) AjaxRequest.js

(2) 在 index.jsp 中引用 AjaxRequest.js 文件

1
<script language="javascript" src="JS/AjaxRequest.js"></script>

 

 

(3) 在 index.jsp 页面中编写错误处理函数, 实例化Ajax对象的方法和回调函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script language="javascript">
/**错误处理的方法**/
function onerror(){
    alert("您的操作有误!");
}
/**实例化Ajax对象的方法**/
function getInfo(){
    var loader=new net.AjaxRequest("getInfo.jsp?nocache="+new Date().getTime(), deal_getInfo, onerror, "GET");
}
/**回调函数**/
function deal_getInfo(){
    document.getElementById("showInfo").innerHTML=this.req.responseText;
}
</script>

(4) 由于要实现滚动显示公告信息, 所以还添加了<marquee>标记.

1
2
3
4
5
<div style="border: 1px solid; height: 50px; width: 200px; padding: 5px;">
    <marquee direction="up" scrollamount="3">
        <div id="showInfo"></div>
    </marquee>
</div>

 

(5) getInfo.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding="GB18030"%>
<%@ page import="java.sql.*" %>
<jsp:useBean id="conn" class="com.wgh.core.ConnDB" scope="page"></jsp:useBean>
<ul>
<%
ResultSet rs=conn.executeQuery("SELECT title FROM tb_bbsInfo ORDER BY id DESC");    //获取公告信息
if(rs.next()){
    do{
        out.print("<li>"+rs.getString(1)+"</li>");
    }while(rs.next());
}else{
    out.print("<li>暂无公告信息!</li>");
}
%>
 
</ul>

(6) 实时获取公告信息

1
2
3
4
window.onload=function(){
    getInfo(); //调用getInfo()方法获取公告信息
    window.setInterval("getInfo()", 60*1000*10); //每隔10分钟调用一次getInfo()方法
}

图13.8 实时显示的公告信息

 



 

13.8 Ajax 常用实例

13.8.1 级联下拉列表

[例13.18] 级联下拉列表. (实例位置: disc\TM\sl\13\3)

(1) AjaxRequest.js

(2) index.jsp

1
<script language="javascript" src="JS/AjaxRequest.js"></script>

 

(3) 编写实例化用于异步获取省份和直辖市的 Ajax 对象的方法和回调函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//获取省份和直辖市
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 对象的方法和回调函数, 以及错误处理函数.

1
2
3
4
5
6
7
8
9
10
11
12
//获取市县
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) 在省份的下拉列表的 onchange 事件中, 调用 getCity() 方法获取该省份对应的市县.

1
<select name="province" id="province" onchange="getCity(this.value)"></select>
1
2
<select name="city" id="city">
</select>

(5) ZoneServlet 中的 doGet() 方法

1
2
3
4
5
6
7
8
9
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 中的 getProvice() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * 获取省份和直辖市
 * @param request
 * @param response
 * @throws ServletException
 * @throws IOException
 */
public void getProvince(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    response.setCharacterEncoding("GBK");       //设置响应的编码方式
    String result="";
    CityMap cityMap=new CityMap();//实例化保存省份信息的CityMap类的实例
    Map<String,String[]> map=cityMap.model;//获取省份信息保存到Map中
    Set<String> set=map.keySet();     //获取Map集合中的键,并以Set集合返回
    Iterator it=set.iterator();
    while(it.hasNext()){        //将获取的省份连接为一个以逗号分隔的字符串
        result=result+it.next()+",";
    }
    result=result.substring(0, result.length()-1);  //去除最后一个逗号
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.print(result);      //输出获取的省份字符串
    out.flush();
    out.close();
}

(7) ZoneServlet 中的 getCity() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * 获取市县
 * @param request
 * @param response
 * @throws ServletException
 * @throws IOException
 */
public void getCity(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    response.setCharacterEncoding("GBK");   //设置响应的编码方式
    String result="";
    String selProvince=request.getParameter("parProvince"); //获取选择的省份
    selProvince=new String(selProvince.getBytes("ISO-8859-1"),"GBK");
    CityMap cityMap=new CityMap();  //实例化保存省份信息的CityMap类的实例
    Map<String,String[]> map=cityMap.model;   //获取省份信息保存到Map中
    String[]arrCity= map.get(selProvince);  //获取指定键的值
    for(int i=0;i<arrCity.length;i++){       //将获取的市县连接为一个以逗号分隔的字符串
        result=result+arrCity[i]+",";
    }
    result=result.substring(0, result.length()-1);  //去除最后一个逗号
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.print(result);                              //输出获取的市县字符串
    out.flush();
    out.close();
}

(8) 省份的初始化

1
2
3
window.onload=function(){
    getProvince();
}

图13.9 级联下拉列表



 

 

 

 

13.8.2 显示进度条

 

[例13.19] 在进行文件上传时, 显示上传进度条. (实例位置: disc\TM\sl\13\4)

(1) index.jsp.  由于要实现文件上传, 需要将表单的 enctype 属性设置为 multipart/form-data.

1
2
3
4
5
<form name="form1" enctype="multipart/form-data" method="post" action="UpLoad?action=uploadFile">
请选择上传的文件:<input name="file" type="file" size="42">
<img src="images/shangchuan.gif" width="61" height="23" onClick="deal(form1)">
<img src="images/chongzhi.gif" width="61" height="23" onClick="form1.reset();">
</form>

(2) 添加用于显示进度条的<div>标记和显示百分比的<span>标记.

1
2
<div id="progressBar" class="prog_border" align="left"><img src="images/progressBar.jpg" width="0" height="13" id="imgProgress"></div>
<span id="progressPercent" style="width:40px;display:none">0%</span>

(3) 在 CSS样式表文件 style.css 中, 添加用于控制进度条样式的CSS样式.

1
2
3
4
5
6
7
8
9
10
11
12
.prog_border {
  height15px;     /*高度*/
  width255px;     /*宽度*/
  background#9ce0fd;      /*背景颜色*/
  border1px solid #FFFFFF;    /*边框样式*/
  margin0;
  padding0;
  display:none;         /*不显示*/
  position:relative;
  left:25px;
  float:left;           /*居左对齐*/
}

(4) index.jsp 中的 JavaScript 函数 deal()

1
2
3
function deal(form){
    form.submit(); //提交表单
    timer=window.setInterval("getProgress()",500); } //每隔500毫秒获取一次上传进度 

(5) 编写上传文件的Servlet 实现类 UpLoad.  在该Servlet 中编写实现文件上传的方法uploadFile(). 在该方法中, 调用 commons-fileupload 组件分段上传文件, 并计算上传百分比, 将其实时地保存到 Session 中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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(); // 获取文件名
                    // System.out.println("上传文件的大小:" + item.getSize());
                    if (upFileSize > maxSize) {
                        error = "您上传的文件太大,请选择不超过50M的文件";
                        break;
                    }
                    // 此时文件暂存在服务器的内存中
                    File tempFile = new File(fileName);// 构造临时对象
                    // String savePath=tempFile.getName();
                    // //返回上传文件在客户端的完整路径名称
                    // request.setAttribute("filename", savePath);
                    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)  AjaxRequest.js

说明: 通常情况下, 在处理POST请求时, 需要将请求头设置为 application/x-www-form-urlencoded. 但是, 如果将表单的 enctype 属性设置为 multipart/form-data, 则在处理请求时, 需要将请求头设置为 multipart/form-data.

(7) 函数 getProgres() 用于实例化 Ajax 对象.

1
2
3
function getProgress(){
    var loader=new net.AjaxRequest("showProgress.jsp?nocache="+new Date().Time(), deal_p, onerror, "GET");
}

(8) showProgress.jsp

1
2
<%@page contentType="text/html" pageEncoding="GB18030"%>
${progressBar}

(9) 回调函数

1
2
3
4
5
6
7
8
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().

1
2
3
function onerror(){
    alert("上传文件出错!");
}

图13.10 带进度条的文件上传

 



 

 

 

13.9 小结

XMLHttpRequest 对象是 Ajax 的核心技术, 需要重点掌握.

如何进行 Ajax 重构需要读者重点掌握, 这在以后的项目开发中比较常用.

13.10 实践与练习

  1. 编写JSP程序, 在网页中显示实时走动的系统时钟. (disc\TM\sl\13\5)

  2. 编写JSP程序, 实时显示新闻信息. (disc\TM\sl\13\6)

  3. 编写JSP程序, 使用 Ajax 实现工具提示. (disc\TM\sl\13\7)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 68.3 KB
  • 大小: 4.7 KB
  • 大小: 2.9 KB
  • 大小: 217.7 KB
分享到:
评论

相关推荐

    javaweb从入门到精通教程视频&PPT;&案例源码

    javaweb从入门到精通教程视频&PPT;&案例源码 javaweb从入门到精通教程视频&PPT;&案例源码 javaweb从入门到精通教程视频&PPT;&案例源码

    JavaWeb从入门到精通实例源程序

    这个压缩包"JavaWeb从入门到精通实例源程序"显然是为了帮助学习者通过实际的代码示例来深入理解JavaWeb开发。 1. **HTML**: HTML(HyperText Markup Language)是网页的基础,用于定义网页结构。在JavaWeb开发中,...

    javaweb从入门到精通精简PPT学习

    这份“javaweb从入门到精通精简PPT学习”资料是针对初学者和进阶者的一份宝贵教程,旨在帮助读者全面理解和掌握JavaWeb的核心技术。 1. **基础篇** - **Servlet**:JavaWeb的基础,用于处理HTTP请求和响应,是动态...

    JavaWeb从入门到精通教学PPT

    JavaWeb从入门到精通这本书的教学PPT ,里面共有21章内容,从H5、XML、JSP、EL表达式、JSTL标准标签库和连接数据库的JDBC再到Spring,SpringMVC、MyBatis和Struts2、Hibernate常用框架的详细讲解。

    Javaweb从入门到精通随书资源

    Javaweb从入门到精通随书资源,无法设置免费下载,希望大家关注关注其他资源

    javaweb 入门到精通答案

    Java Web 是一种基于Java技术构建Web应用程序的框架,它提供了丰富的功能和工具,使得开发者能够构建动态、交互式的Web应用。本章将深入探讨Java Web的相关知识点,包括其历史、主要特点、核心技术以及开发中常用的...

    JAVA WEB从入门到精通 随书源码

    本资源包含"JAVA WEB从入门到精通"这本书随书附带的第2到第10章的源代码,这些章节通常涵盖了Web开发的基础到进阶内容。 1. **基础概念**:Java Web开发首先涉及Servlet和JSP(JavaServer Pages),它们是构建动态...

    JavaWeb 从入门到精通PPT

    这份“JavaWeb 从入门到精通PPT”很可能是提供了一个系统化的学习路径,帮助初学者掌握这一技术栈。以下是对JavaWeb核心概念、技术和工具的详细解释: 1. **Servlet与JSP**: Java Servlet是JavaEE规范的一部分,它...

    Java Web从入门到精通光盘17-1

    【Java Web从入门到精通光盘17-1】是一个针对初学者的教育资源,旨在帮助读者全面理解并掌握Java Web开发技术。Java Web是使用Java语言进行Web应用程序开发的领域,它涵盖了诸如Servlet、JSP(JavaServer Pages)、...

    JavaWeb从入门到精通(实例源程序2-16章)

    这个压缩包文件包含的是"JavaWeb从入门到精通"教程的实例源程序,覆盖了第2至第16章的学习内容。每个章节对应的源代码文件,可能代表着一个特定的主题或技术点,下面我们将逐一探讨这些章节可能涵盖的知识点。 1. ...

    Javaweb从入门到精通资源分享

    Javaweb从入门到精通中所有的代码,项目,资源库,PPT等在里面,因文件过大,无法上传,此文件为百度云链接,请放心下载,无法使用请在评论区留言,看到会立即回复

    JavaWeb从入门到精通(实例源程序17-21章)

    在这个"JavaWeb从入门到精通(实例源程序17-21章)"的压缩包中,包含了一系列章节的源代码,可以帮助初学者和进阶者深入理解JavaWeb开发的核心概念。 第17章通常会涵盖Servlet技术,这是JavaWeb应用的基础。Servlet...

    JavaWeb从入门到精通PPT.zip

    《JavaWeb从入门到精通》是一本全面介绍JavaWeb开发技术的教程,涵盖了从基础知识到高级应用的全方位内容。这份PPT合集包含了从第1章到第21章的全部教学材料,旨在帮助初学者逐步掌握JavaWeb编程,并提升至精通水平...

    Java Web编程宝典-十年典藏版.pdf.part2(共2个)

    第13章 简化企业开发瑰宝之二 第14章 程序员的伴侣 第2篇 范例演练篇 第15章 学以致用 第16章 幕后英雄的用武之地 第17章 Web开发的制胜法宝 第18章 数据分析大师 第19章 体验完美视觉盛宴 第3篇 项目实战篇 第20...

    java web入门到精通的光盘源码

    "Java Web入门到精通的光盘源码"是一份宝贵的资源,它包含了从初学者到高级开发者在学习过程中可能会遇到的各种示例代码,旨在帮助读者快速理解和掌握Java Web开发。 1. **Servlet**:Servlet是Java Web的核心组件...

    Java Web从入门到精通光盘源码1-15

    这个"Java Web从入门到精通光盘源码1-15"提供了学习者深入理解和实践Java Web应用开发的资源。以下是一些核心知识点的详细说明: 1. **Servlet与JSP**:Servlet是Java Web的基础,用于处理HTTP请求并生成动态响应。...

    JAVA WEB编程宝典 十年典藏版

    总的来说,《JAVA WEB编程宝典 十年典藏版》是一本全面深入的教程,涵盖了从基础到高级的Java Web开发技术,旨在帮助读者从理论到实践,掌握构建高效、稳定、可扩展的Web应用程序所需的知识和技能。通过阅读并实践书...

    Java从入门到精通.pdf

    十四万字总结,PDF包含了十四个大模块:Java基础知识,数据结构,算法,Java集合框架,Java8新特性,操作系统,网络原理,Java多线程及并发编程,Java的IO模型及网络编程,JVM,Mysql,JavaWeb和一个仿Tomcat实现的...

Global site tag (gtag.js) - Google Analytics