使用ExtJS创建前端WebQQ界面,使用ASP.NET处理数据存取,为了演示方便用Sqlite3存储数据。
功能概述:
实现了最基础的一对一的通讯功能,实时收发信息,离线保存信息。来信自动弹出窗口。
实现思路:
借鉴了早些年的聊天室思想。
获取聊天信息是客户端定时向服务器请求,按照发送的用户名来查询此用户是否有新信息。有信息则返回信息。如何获取?思路如下:
数据库中为每个用户设置一个LastID,获取信息的时候比较聊天信息表中最大的ChatID。如果ChatID大于LastID,则表明有新的聊天信息,接着从对应数据库获取聊天信息( ChatID-LastID表明新信息条数), 返回给客户端。客户端再根据不同的用户名,将信息追加到相应的聊天窗口。这里还有一步,设置LastID,将这个最大的ChatID保存为LastID。
发送聊天信息比较好理解,POST数据至服务器端的处理页面,进行保存即可。
实现细节:
客户端:
主要有4个处理函数:
双击用户名节点创建聊天窗口:webQQDblClick()
来信动态创建聊天窗口:autoshowQQWindow()
定时从服务器获取聊天消息:loadMessage()
向聊天窗口追加聊天信息:addMessage()
发送聊天信息的处理语句分别在webQQDblClick()和autoshowQQWindow()里面都有。当然这样处理是不符合一些设计思想的,多敲了很多代码。我是懒得封装成一个方法。
服务器端:
有两个处理页面:
一个保存提交的聊天信息页面:SendChatMessage.aspx
一个获取聊天信息的页面:GetChatMessage.aspx
主要的获取数据和保存信息的处理方法是在Chat类中定义的。


申明一下:我仅仅是实现了WebQQ的部分功能。并非实现合理。首先我的编码不是很规范。请谅解。其次WebQQ界面是ExtJS的Desktop例子中的那个。稍稍把代码改一下,就可以独立了!还有QQ好友不是异步动态获取的。 我为每个用户都创建了一个数据库文件,这是因为Sqlite操作方便。还有每个用户都有很多不同的数据要存储,不仅仅是保存了聊天信息,所以才这样的。其实你可以把Sqlite看成是一个文本文件,只不过是用关系数据库的方式来思考和存取。想象一下,如果你的一个文本文件,有10M大小。你用文本编辑器打开时什么感觉。我宁可把它分解成50个,500个文本进行读取。这是我的看法!
还有使用Sqlite是为了演示方便,不需要任何安装、配置、管理。
(其他数据库估计就不能这样了!如果我用MSSQL也绝不会像处理Sqlite这样为每个用户创建一个数据库,因时因地而异。)
我还是先贴个图,诱惑一下。^_^


这里也有全部源代码地址:http://download.csdn.net/source/499268 下面贴部分代码:
服务器端消息处理页面:
GetChatMessage.aspx
public partial class GetChatMessage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string userinfoPath = Request.MapPath(@"\\db\userinfo.db3");
string userPath = Request.MapPath(@"\db\userdb\");
string username = Request.Params["username"];
if (username != null)
{
IChat chat = new Chat(userinfoPath, userPath);
string str = chat.GetChatMessage(username);
Response.Write(str);
}
Response.End();
}
}
SendChatMessage.aspx
public partial class SendChatMessage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string userinfoPath = Request.MapPath(@"\db\userinfo.db3");
string userPath = Request.MapPath(@"\db\userdb\");
string fromusername = Request.Params["fromusername"];
string tousername = Request.Params["tousername"];
string message = Request.Params["message"];
if (fromusername != null && tousername != null && message != null)
{
IChat chat = new Chat(userinfoPath,userPath);
chat.SendChatMessage(fromusername, tousername, message);
Response.Write("{success:true}");
}
else
Response.Write("{success:false}");
Response.End();
}
}
聊天消息处理接口:
interface IChat
{
string GetChatMessage(string userName);
void SendChatMessage(string toUserName, string fromUserName, string message);
}
聊天消息处理类:
(数据库,我临时使用Sqlite3,创建了一个userinfo.db3存储全部用户的信息,并且创建chatlastid表,存储每个用户的LastChatID。我为每个用户都创建了一个个人的数据库文件,如snail.db3,oo.db3.存储他自己的消息(chatmsg表).)
public class Chat: IChat
{
private string userinfoDBPath = "";
private string userDBPath = "";
public Chat(string userinfoStr,string userStr)
{
this.userinfoDBPath = userinfoStr;
this.userDBPath = userStr;
}
/// <summary>
/// 根据用户名获取最后一次发送或接受消息的ID
/// </summary>
/// <param name="userName">欲获取其LastChatID的用户</param>
private int GetLastChatID(string userName)
{
int returnValue = -1;
using(SQLiteConnection conn = new SQLiteConnection("Data Source=" + userinfoDBPath))
{
try
{
conn.Open();
string strsql = "select [lastchatid] from [chatlastid] where username = @userName";
SQLiteCommand cmd = new SQLiteCommand(strsql, conn);
cmd.Parameters.AddWithValue("@userName", userName);
object result = cmd.ExecuteScalar();
conn.Clone();
if (result == null)
SetDefaultLastChatID(userName);
else
returnValue = Convert.ToInt32(result);
}
catch (Exception ex)
{
}
finally
{
}
}
return returnValue;
}
/// <summary>
/// 如果用户在ChatLastID表中没有值,则设置其为默认值-1
/// </summary>
/// <param name="userName">用户名</param>
private void SetDefaultLastChatID(string userName)
{
int defaultLastID = -1;
using(SQLiteConnection conn = new SQLiteConnection("Data Source=" + userinfoDBPath))
{
try
{
conn.Open();
string strsql = "insert into chatlastid(username,lastchatid) values(@userName,@lastchatid)";
SQLiteCommand cmd = new SQLiteCommand(strsql, conn);
cmd.Parameters.AddWithValue("@userName", userName);
cmd.Parameters.AddWithValue("@lastchatid", defaultLastID);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
}
finally
{
conn.Clone();
}
}
}
/// <summary>
/// 获取某个用户的消息列表,string类型,并且在获取消息的同时设置LastID。
/// </summary>
/// <param name="userName">欲获取消息的用户名</param>
public string GetChatMessage(string userName)
{
string returnStr = "";
int lastID = GetLastChatID(userName);
int freshID = GetFreshChatID(userName);
if (freshID > lastID)
{
string datapath = userDBPath + userName + @".db3";
int getChatID = freshID - lastID;
using(SQLiteConnection conn = new SQLiteConnection("Data Source=" + datapath))
{
DataSet ds = new DataSet();
try
{
conn.Open();
string strsql = "select [chatid],[fromusername],[message],[senddate] from (Select [chatid],[fromusername],[message],[senddate] From [chatmsg] order by chatid desc limit "+getChatID+") order by chatid asc";
SQLiteDataAdapter sdap = new SQLiteDataAdapter(strsql , conn);
sdap.Fill(ds);
conn.Clone();
//将DataSet转化为JSON格式
returnStr = JSONHelper.Convert2Json(ds);
//设置LastChatID值chatlastid Table
SetLastChatID(userName, freshID);
}
catch (Exception ex)
{
}
finally
{
}
}
}
return returnStr;
}
/// <summary>
/// 给指定用户名发送消息,保存至该用户个人数据库。(发送时间在插入数据的时候获取当前时间。)
/// </summary>
/// <param name="toUserName">消息接收者名称</param>
/// <param name="fromUserName">消息发送者名称</param>
/// <param name="message">消息内容</param>
public void SendChatMessage(string fromUserName, string toUserName, string message)
{
string senddate = DateTime.Now.ToString("u").TrimEnd('Z');
string datapath = userDBPath + toUserName + @".db3";
using (SQLiteConnection conn = new SQLiteConnection("Data Source=" + datapath))
{
try
{
conn.Open();
string strsql = "insert into chatmsg(fromusername,message,senddate) values(@fromUserName,@message,@senddate);";
SQLiteCommand cmd = new SQLiteCommand(strsql, conn);
cmd.Parameters.AddWithValue("@fromUserName", fromUserName);
cmd.Parameters.AddWithValue("@message", message);
cmd.Parameters.AddWithValue("@senddate", senddate);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
}
finally
{
conn.Clone();
}
}
}
/// <summary>
/// 设置公用数据库ChatLastID中的某个用户的LastID
/// </summary>
/// <param name="userName">欲设置ChatLastID的用户</param>
private void SetLastChatID(string userName, int lastchatid)
{
using(SQLiteConnection conn = new SQLiteConnection("Data Source=" + userinfoDBPath))
{
try
{
conn.Open();
string strsql = "update [chatlastid] set [lastchatid] = @lastchatid where [username] = @userName";
SQLiteCommand cmd = new SQLiteCommand(strsql, conn);
cmd.Parameters.AddWithValue("@userName", userName);
cmd.Parameters.AddWithValue("@lastchatid", lastchatid);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
}
finally
{
conn.Clone();
}
}
}
/// <summary>
/// 获取最新的ChatID
/// </summary>
/// <param name="userName">欲获取某个用户的名称</param>
private int GetFreshChatID(string userName)
{
int returnValue = 0;
string datapath = userDBPath + userName + @".db3";
using(SQLiteConnection conn = new SQLiteConnection("Data Source=" + datapath))
{
try
{
conn.Open();
string strsql = "Select max(chatid) From [chatmsg];";
SQLiteCommand cmd = new SQLiteCommand(strsql, conn);
returnValue = Convert.ToInt32(cmd.ExecuteScalar());
}
catch (Exception ex)
{
}
finally
{
conn.Clone();
}
}
return returnValue;
}
}
chatmsg 表:
Create [chatmsg](
[chatid] INTEGER PRIMARY KEY NOT NULL
,[fromusername] nvarchar(20) NOT NULL
,[message] nvarchar(200)
,[senddate] nvarchar(20)
);
chatlastid 表:
Create [chatlastid](
[username] nvarCHAR(20) PRIMARY KEY NOT NULL
,[lastchatid] INTEGER NOT NULL DEFAULT '0'
);
这个WebQQ有很多的不足之处,很多编码思想,编码规范等等都由这个自己来的,怎么想就做么做了,呵呵。如果你有好的建议,意见,咱多聊聊。^_^
发表于 @ 2008年06月16日 13:01:00|评论(loading...)|收藏