您的位置:首页 > 其它

AJAX聊天室无刷新技术方案

2010-04-13 20:05 344 查看
聊天室在网上很常见,它给人们提供了在线聊天的机会。聊天室在功能上类似论坛,但是论坛上的信息可以保存较长的时间,而聊天室主要用于在线聊天,所以对存储信息方面的要求不高,另外还要经常删除一些信息,避免数据库存储的内容过多,影响显示的速度。聊天室主要提供三种功能:一是现实自己可以看到的信息,这包括针对所有人的聊天信息、自己发的信息以及发给自己的信息;二是要能够看到在线的人员名单,从而从中选择聊天的对象;三是输入聊天信息。

1.方案分析

Ajax的核心是JavaScript XmlHttpRequest对象。该对象在Internet Explorer 5中首次引入,它是一种支持异步请求的技术。简而言之,XmlHttpRequest对象可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户。
在创建Web站点时,在客户端执行屏幕更新为用户提供了很大地灵活性。下面是Ajax可以完成的功能:
l 动态检测网页中的数据,无需页面重复加载。例如,动态检测网络考试系统倒记时时间,无需页面重复加载,并等待服务器重新发送整个页面。
l 提升站点的性能,这是通过减少从服务器下载的数据量而实现的。例如,在电子商城网的购物车页面,当更新购物车中的一项物品的数量时,通常会重新载入整个页面。如果使用Ajax计算新物品的总数量,服务器只会返回新物品总数量,而无须重新载入整个页面。
传统的聊天室基于客户端网页的自动刷新技术而实现,它的主要缺点是不断刷新页面造成屏幕的闪动,而经过了Ajax改造后的聊天室,每次只获取最新的发言信息,并将获取结果动态写入页面,不会有以上的缺点。

2.实施过程


实例位置:光盘/ mr/07/7.6/01
在***基于Ajax的无刷新聊天室时,通过一个登录页面进入聊天室的主页面。在登录页面中输入用户名和密码进入聊天室的主页面ChatRoom.aspx中,聊天室的主页面如图7.51所示。



图7.51 啸天聊天室的主页面
程序实现具体步骤:
(1)新建一个网站命名为01,将首页命名为Login.aspx。
(2) 再新建一个在页面,命名为ChatRoom.aspx。其中添加3个DropDownList控件,1个CheckBox控件,1个TextBox控件和1个Button控件。3个DropDownList控件分别用来设置发送聊天信息的颜色、表情和聊天的对象。CheckBox控件用来设置是否和选中的聊天对象进行私聊,TextBox控件用来输入聊天信息,Button控件用来提交聊天信息。
(3)本例中用到的存储过程如下。
存储过程GetNewMsg用于获取聊天信息。
CREATE PROCEDURE GetNewMsg
@username varchar(50)
AS
--获取用户已经列出的消息id最大值
DECLARE @last int
SET @last = ( SELECT lastchatinfo FROM UserInfo WHERE username = @username )
--获取最新的消息列表
SELECT id, user_from, user_to, content, expression, color, ispublic, sendtime FROM ChatInfo
WHERE ( id > @last ) AND ( ( ispublic = 1 ) OR ( user_to = @username ) OR ( user_from = @username ) OR ( user_to = '大家' ) ) AND ( sendtime > GETDATE() - '00:05:00' )
ORDER BY sendtime DESC
GO
存储过程GetOnlineUsers用于获取当前的在线人数。
CREATE PROCEDURE GetOnlineUsers
AS
--选取所有在线的用户
SELECT id, username FROM UserInfo WHERE isonline = 1
GO
存储过程SendMsg用于发送聊天信息。
CREATE PROCEDURE SendMsg
@user_from varchar(50),
@user_to varchar(50),
@content varchar(255),
@expression varchar(50),
@color varchar(50),
@ispublic bit
AS
--发送消息
INSERT INTO ChatInfo (user_from, user_to, content, expression, color, ispublic, sendtime)
VALUES ( @user_from, @user_to, @content, @expression, @color, @ispublic, GETDATE() )
GO
存储过程SetMsgPos用于记录已经阅读过的消息ID。
CREATE PROCEDURE SetMsgPos
@username varchar(50)
AS
--记录已经阅读过的消息id
UPDATE UserInfo SET lastchatinfo = ( SELECT MAX(id) FROM ChatInfo )
WHERE username = @username
GO
存储过程UserLogin用于判断登录的各个信息。
CREATE PROCEDURE UserLogin
@username varchar(50),
@password varchar(50)
AS
--用户名密码正确
IF EXISTS ( SELECT id FROM UserInfo WHERE username = @username AND password = @password )
BEGIN
UPDATE UserInfo SET isonline = 1, lastchatinfo = ( SELECT ISNULL(MAX(id), 0) FROM ChatInfo )
WHERE username = @username AND password = @password
--发布公告
INSERT INTO ChatInfo (user_from, user_to, content, expression, color, ispublic, sendtime)
VALUES ( '', '', '【聊天室公告】:欢迎' + @username + '来到聊天室!', '', 'ff0000', 1, GETDATE() )
RETURN 0
END
--用户名存在,密码不正确
IF EXISTS ( SELECT id FROM UserInfo WHERE username = @username )
RETURN 1
--用户名不存在,则根据输入创建新用户
INSERT INTO UserInfo (username, password, isonline) VALUES ( @username, @password, 1 )
UPDATE UserInfo SET lastchatinfo = ( SELECT ISNULL(MAX(id), 0) FROM ChatInfo )
WHERE username = @username AND password = @password
--发布公告
INSERT INTO ChatInfo (user_from, user_to, content, expression, color, ispublic, sendtime)
VALUES ( '', '', '【聊天室公告】:欢迎新人' + @username + '来到聊天室!', '', 'ff0000', 1, GETDATE() )
RETURN 2
GO
存储过程UserLogout用于退出聊天室。
CREATE PROCEDURE UserLogout
@username varchar(50)
AS
UPDATE UserInfo
SET isonline = 0, lastchatinfo = ( SELECT ISNULL(MAX(id), 0) FROM ChatInfo )
WHERE username = @username
--发布公告
INSERT INTO ChatInfo (user_from, user_to, content, expression, color, ispublic, sendtime)
VALUES ( '', '', '【聊天室公告】:' + @username + '已经离开聊天室!', '', 'ff0000', 1, GETDATE() )
GO
(4)程序主要代码如下。
下面是ChatRoom.aspx页面中通过JavaScript创建的几个函数,这些函数通过调用服务器端的方法来实现指定的功能,具体代码如下。
当用户单击【发送】按钮时会出发send方法,首先读取当前页面中用户输入的各项信息,如:用于输入聊天内容文本框中的信息、聊天的对象、字体的颜色、用户使用的表情和是否选择密谈。然后调用服务器端的SendMsg方法,并将读取的这些信息以参数的形式传递过去。同时,显示聊天的内容。这一步是通过调用服务器端的GetNewMsgString方法实现的,具体代码如下。
function send()
{
var txtContent = document.all("content").value; //文本框输入内容
if (txtContent == "") return;
var user_to = document.all("userlist").value; //聊天对象
var textcolor = document.all("textcolor").value; //颜色
var expression = document.all("expression").value; //表情
var isPublic = !(document.all("isSecret").checked); //是否密谈
//调用服务器端方法发送消息
ChatRoom.SendMsg(txtContent, user_to, textcolor, expression, isPublic);
//更新聊天内容显示
var div = document.all("chatcontent");
div.innerHTML = ChatRoom.GetNewMsgString().value + div.innerHTML;
//清空输入框
document.all("content").value = "";
}
自定义的refresh_chatcontent方法用于定时的更新聊天内容。首先获取当前页面中的所有聊天内容,然后通过调用服务器端的GetNewMsgString方法得到最新消息的HTML字符串。之后判断获得的字符串是否为空,如果不为空就不需要更新,这样避免了不必要的更新,节省了资源的消耗。最后通过window.setTimeout对内容做定时的更新,本例中更新的时间间隔为1000毫秒,具体代码如下。
//定时更新聊天内容
function refresh_chatcontent()
{
//调用服务器方法获取最新消息的HTML字符串
var div = document.all("chatcontent");
var strNewMsg = ChatRoom.GetNewMsgString().value;
//判断是否为空,避免不必要的更新
if (strNewMsg != "")
div.innerHTML = strNewMsg + div.innerHTML;
//定时更新
window.setTimeout(refresh_chatcontent, 1000);
}
refresh_onlineusers方法用于更新用户列表,其中包括左侧在线人数的列表以及聊天对象的下拉列表,具体代码如下。
//更新用户列表(左侧和下拉列表)
function refresh_onlineusers()
{
//发送对象列表
var userlist = document.all("userlist");
//调用服务器端方法获取用户列表字符串(用逗号分隔)
var strUserlist = ChatRoom.GetOnlineUserString().value;
//获取客户端显示的用户列表字符串
var strUserlistClient = "";
for (var i = 1;i < userlist.options.length;i++)
{
if (i != userlist.options.length - 1)
{
strUserlistClient += userlist.options[i].value + ",";
}
else
{
strUserlistClient += userlist.options[i].value;
}
}
if (strUserlistClient != strUserlist) //在线用户列表发生变化
{
var userArr = strUserlist.split(',');
//在线用户数
var usercount = document.all("usercount");
usercount.innerHTML = "在线名单:(" + userArr.length + "人)";
//左边用户列表
var tableHTML = "<table>";
for (var i = 0;i < userArr.length;i++)
{
tableHTML += "<tr><td><label onmouseover=/"this.style.cursor='hand'/" onmouseout=/"this.style.cursor='default'/" onclick=/"setObj('" + userArr[i] + "')/">" + userArr[i] + "</label></td></tr>";
}
tableHTML += "</table>";
var div = document.all("onlineusers");
div.innerHTML = tableHTML;
//初始化
while (userlist.options.length > 0)
{
userlist.removeChild(userlist.options[0]); //清空所有选项
}
//增加“所有的人”选项
var oOption = document.createElement("OPTION");
oOption.text = "所有的人";
oOption.value = "大家";
userlist.add(oOption);
//下拉列表中增加在线用户的选项
for (var i = 0;i < userArr.length;i++)
{
var oOption = document.createElement("OPTION");
oOption.text = userArr[i];
oOption.value = userArr[i];
userlist.add(oOption);
}
}
//每隔秒更新
window.setTimeout(refresh_onlineusers, 1000);
}
当ChatRoom.aspx页面被关闭之前将会调用logout方法,页面是在<Body></Body>中调用logout方法的,代码如下。
<body bottomMargin="0" onbeforeunload="logout()" leftMargin="0" topMargin="0" rightMargin="0" style="text-align: center">
logout方法的主要作用就是当有用户离开聊天室时,更新当前的再线用户,去除离线的用户这一功能是通过调用服务器端的Logout方法实现的,具体代码如下。
//退出聊天室
function logout()
{
ChatRoom.Logout();
}
setObj方法用于设置聊天对象,通过选择对象的下拉列表设置聊天的对象,例如想和某个人进行私聊,就可以通过下拉列表进行选择,然后选中“密谈”就可以进行私聊了,具体代码如下。
//设置聊天对象
function setObj(str)
{
var userlist = document.all("userlist");
for (var i = 0;i < userlist.options.length;i++)
{
if (str == userlist.options[i].value)
{
userlist.selectedIndex = i;
break;
}
}
}
当单击“退出聊天”时会触发Close方法用于清除登录信息并关闭浏览器,具体代码如下。
//关闭浏览器窗口
function Close()
{
var ua = navigator.userAgent;
var ie = navigator.appName == "Microsoft Internet Explorer" ? true:false;
if (ie)
{
var IEversion=parseFloat(ua.substring(ua.indexOf("MSIE ")+5,ua.indexOf(";",ua.indexOf("MSIE "))));
if (IEversion< 5.5)
{
var str = '<object id=noTipClose classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">';
str += '<param name="Command" value="Close"></object>';
document.body.insertAdjacentHTML("beforeEnd", str);
document.all.noTipClose.Click();
}
else
{
window.opener = null;
window.close();
}
}
else
{
window.close();
}
}
下面介绍本方案用到的几个服务器端的方法,首先将Ajax.dll组件引用到项目当中,然后在ChatRoom.aspx页的Page_Load事件中添加如下代码注册Ajax类型。
protected void Page_Load(object sender, System.EventArgs e)
{
Ajax.Utility.RegisterTypeForAjax(typeof(ChatRoom));
}
当单击【发送】按钮发表聊天信息时,会调用客户端的send方法将文本框中输入的文字显示出来,实现了发送聊天信息的无刷新技术,在客户端的send方法中调用了服务器端的SendMsg方法,下面就介绍一下SendMsg方法。
首先连接数据库,然后通过调用存储过程“SendMsg”将ChatRoom.aspx页面中发表的聊天信息插入数据库相应的字段中,具体代码如下。
[Ajax.AjaxMethod()]
public void SendMsg(string strMsg, string strUserTo, string strColor, string strExpression, bool bIsPublic)
{
SqlConnection conn = new SqlConnection(
ConfigurationSettings.AppSettings["ConnectionString"]);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "SendMsg";
cmd.Parameters.Add("@user_from", UserName);
cmd.Parameters.Add("@user_to", strUserTo);
cmd.Parameters.Add("@content", strMsg);
cmd.Parameters.Add("@expression", strExpression);
cmd.Parameters.Add("@color", strColor);
cmd.Parameters.Add("@ispublic", bIsPublic);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
在客户端的send方法中也调用了服务器端的GetNewMsgString方法,其主要的功能是将存储到数据库中的聊天信息查询出来并且显示到页面上。
首先连接数据库,然后调用存储过程GetNewMsg。然后通过数据阅读器读取数据库中的聊天信息,再将数据赋值给字符串strMsgHTML,具体代码如下。
[Ajax.AjaxMethod()]
public string GetNewMsgString()
{
string strMsgHTML = "";
//连接数据库
SqlConnection conn = new SqlConnection(
ConfigurationSettings.AppSettings["ConnectionString"]);
SqlCommand cmd = conn.CreateCommand();
//调用存储过程GetNewMsg
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetNewMsg";
cmd.Parameters.Add("@username", UserName);
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
if (dr.GetString(1) != "")
{
strMsgHTML += string.Format(
"<span class='chatmsg' style='COLOR: #{0}'>{1} {2} {3} {4} >> {5}</span><br>",
dr.GetString(5),
dr.GetString(1),
TestIsPublic(dr.GetBoolean(6)),
TestYourself(dr.GetString(2)),
dr.GetString(4),
Replace_GTLT(dr.GetString(3)));
}
else
{
strMsgHTML += string.Format("<span class='chatmsg' style='COLOR: #{0}'>{1}</span><br>",dr.GetString(5),dr.GetString(3));
}
}
}
conn.Close();
SetMsgPos();
return strMsgHTML;
}
在ChatRoom.aspx页面的HTML代码中通过JavaScript建立一个refresh_onlineusers方法用来获取当前的在线人数,并且定时的更新当前在线人数,在 refresh_onlineusers方法中调用了服务器端的GetOnlineUserString方法,下面介绍GetOnlineUserString方法。
服务器端的GetOnlineUserString方法通过调用存储过程GetOnlineUsers将当前的在线人数从数据库中读取出来,具体代码如下。
[Ajax.AjaxMethod()]
public string GetOnlineUserString()
{
string strUserlist = "";
SqlConnection conn = new SqlConnection(
ConfigurationSettings.AppSettings["ConnectionString"]);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetOnlineUsers";
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
strUserlist += dr.GetString(1) + ",";
}
}
conn.Close();
return strUserlist.TrimEnd(',');
}
在当前的聊天室页面关闭时会出发HTML代码中的logout方法,此方法通过调用服务器端的Logout方法更新在线人数,具体代码如下。
[Ajax.AjaxMethod()]
public void Logout()
{
SqlConnection conn = new SqlConnection(
ConfigurationSettings.AppSettings["ConnectionString"]);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "UserLogout";
cmd.Parameters.Add("@username", UserName);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
注意:Ajax.AjaxMethod()定制属性,属性服务会告知ajax封装类为此方法创建一个javascript代理,这样才能被客户端调用。
——摘自《C#编程词典》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: