18.5 Web服务层
为了调用程序方便和使程序具有可扩展性,本章把Web QQ的常用操作封装在Web服务层。Web服务层调用底层代码的功能,向Web层提供服务,属于中间层。Improve.cs是Web服务层的代码文件。这里分为4部分加以介绍:发送、接收聊天信息;添加好友;获取聊天记录;其他一些方法。
18.5.1 发送、接收聊天信息
发送、接收聊天消息主要分为两种:发送、接收两人聊天消息和发送、接收群聊天消息。其中接收两人聊天消息的处理流程相对比较复杂。其程序流程如图18.12所示。
两人聊天发送、接收聊天消息的实现代码如下:
#region 发送接受消息(两人聊天和群)
// 两人对聊时用户发送消息
//receiver 接受者账号;msg 消息内容
[WebMethod]
public void SendMsg(HttpContext context, string receiver, string msg)
{
//接受者未在线,直接插入数据库;
if(context.Cache[receiver] == null)
{
string insertstr = "insert msg(sendername,receivername,msg) values('";
insertstr += selfname + "','" + receiver + "','" + msg + "')";
s.ExecuteSql(insertstr); //执行插入操作
}
else //在线,放入内存,等待接收。
{
((ChatUser)(context.Cache[receiver])).Message.Add(selfname, msg);
}
}
// 两人对聊时接收特定人给自己发的未读消息

图18.12 两人聊天接收消息的流程图
//sender 发送者
[WebMethod]
public MsgTable ReceiveMsg(HttpContext context, string sender)
{
MsgTable Message = new MsgTable();//要返回的消息表
//没有在线信息,直接从数据库中查找消息
if(context.Cache[selfname] == null)
{
SqlDataReader dr = s.GetReader("select * from msg where sendername='"
+ sender + "' and receivername = '" + selfname + "' and ifread =1");
while (dr.Read()) //查找到消息,把消息添加到返回的消息表中
{
Message.Add(new Msg(int.Parse(dr["id"].ToString()), dr["sendername"].
ToString(), dr["msg"].ToString(),
DateTime.Parse(dr["sendtime"].ToString()), dr["ifread"].ToString()
== "1" ? false : true));
}
dr.Close();
//更新消息已读状态
s.ExecuteSql("update msg set ifread=0 where sendername='" + sender
+"' and receivername ='" + selfname + "' and ifread=1");
}
else //有在线信息
{
//用户所拥有的所有消息
MsgTable mymsg = ((ChatUser)context.Cache[selfname]).Message;
Message.MaxRecord = 100; //设置每个用户能存放的消息数目为100条
string temp = "0"; //记录已经找到的消息id
//接收在线消息
for(int i = 0; i < mymsg.List.Count; i++)
{
//此条消息正是需要找的消息
if (((Msg)mymsg.List[i]).IfRead == false && ((Msg)mymsg.List[i]).
SenderName == sender)
{
Message.Add((Msg)mymsg.List[i]); //添加到返回表中
((Msg)mymsg.List[i]).IfRead = true;
temp += ("," + ((Msg)mymsg.List[i]).ID); //把id记录下
}
}
//数据库中有额外新消息
if(mymsg.HaveOtherMsg == true)
{
SqlDataReader dr = s.GetReader("select * from msg where id not in
(" + temp + ") and sendername='" + sender + "' and receivername
= '" + selfname + "' and ifread =1");
while (dr.Read()) //遍历取到的每条消息
{
//添加到返回表中
Message.Add(new Msg(int.Parse(dr["id"].ToString()), dr["sendername"].
ToString(), dr["msg"].ToString(), DateTime.Parse(dr["sendtime"].
ToString()), false));
}
dr.Close();
//把取走的消息更新为已读
s.ExecuteSql("update msg set ifread=0 where sendername='" +
sender + "' and receivername ='" + selfname + "' and ifread=1");
mymsg.HaveOtherMsg = false; //数据库中没有额外数据了
}
}
return Message;
}
// 发送群消息
// msg 消息内容
[WebMethod]
public void SendGroupMsg(string groupid, string msg)
{
//当前会话上下文
HttpContext context = HttpContext.Current;
if(context.Cache["$" + groupid] == null)/当前不存在这个群的对象实例,创建这个群
{
context.Cache.Insert("$" + groupid, new MyGroup(groupid));
}
//构造一个新消息
BaseMsg bm = new BaseMsg(selfname, msg);
//添加上这个消息
((GroupMsgTable)(HttpContext.Current.Cache["$" + groupid])).Add(bm);
}
// 接受群消息
//groupid 群组的id
[WebMethod]
public GroupMsgTable ReceiveGroupMsg(string groupid)
{
HttpContext context = HttpContext.Current;
GroupMsgTable gmt = new GroupMsgTable(); //返回的群消息表
if(context.Cache["$" + groupid] != null) //接受应该自己收到的群消息
gmt = ((MyGroup)(context.Cache["$" + groupid])).ReceiveMsg();
return gmt;
}
#endregion
18.5.2 添加好友
聊天者是否允许被添加为好友的设置有3种:允许任何人直接将自己添加为好友;拒绝任何人将自己添加为好友;允许经过验证的用户添加自己为好友。与之对应,添加好友时也应考虑这3种情况,分别加以处理。添加好友的流程如图18.13所示。

图18.13 添加好友的流程图
与添加好友相关的程序代码如下:
#region 添加好友的操作
// 请求增加好友第一步;有4种返回情况:havefriend;isblack;success;confirm;forbid;
//添加好友
// friendid 要添加好友的用户id
[WebMethod]
public string AddFriend(string friendid)
{
//取得好友账号
string friendname = s.getMyDataSet("select username from userinfo where
userid=" + friendid).Tables[0].Rows[0][0].ToString();
//查找要添加的好友是否已经在自己的联系人列表中了
SqlDataReader r = s.GetReader("select type from friend where userid =" +
selfid + " and othername='" + friendname + "' and type !=2");
if(r.Read() && r["type"].ToString() == "0") //已经是好友了
{
r.Close();
return "havefriend";
}
if(r.HasRows && r["type"].ToString() == "1") //此用户在黑名单中
{
r.Close();
return "isblack";
}
r.Close();
//此用户被添加为好友是否需要验证
r = s.GetReader("select canaddfriend from userinfo where userid = " + friendid);
string flag = ""; //是否需要验证
if(r.Read())
flag = r["canaddfriend"].ToString();
r.Close();//关闭连接
if(flag == "1") //可以直接加为好友
{
s.ExecuteSql("insert friend (type,userid,othername)values(0," + selfid
+ ",'" + friendname + "')", false); //加为好友
//对方是否把自己加为了好友或黑名单
r = s.GetReader("select id from friend where userid =" + friendid
+ " and othername = '" + selfname + "'");
if(!r.HasRows) //自己没在对方的联系人列表中,自己成为对方的陌生人
{
r.Close();
s.ExecuteSql("insert friend (type,userid,othername)values(2," +
friendid + ",'" + selfname + "')");
}
else
r.Close();
return "success"; //添加好友成功
}
if(flag == "0") //加为好友需要确认
{
return "confirm";
}
if(flag == "2") //对方拒绝被加为好友
{
return "forbid";
}
return "";
}
// 添加好友第二步,发出请求加为好友的文字请求
// friendid 要加为好友的id,notes 加为好友的请求留言
[WebMethod]
public void AskForAddF(string friendid, string notes)
{
string friendname = ""; //要加为好友的账号名
Sql s0 = new Sql();
SqlDataReader r0 = s0.GetReader("select username from userinfo where
userid=" + friendid);
if(r0.Read()) //根据id 取得了账号名
friendname = r0["username"].ToString();
r0.Close();
s0 = null; //清空
HttpContext context = HttpContext.Current;
string msg = selfname + " 请求加您为好友,您是否同意?<br/>消息:" + notes;
//构造消息内容
msg += "<a href=javascript:top.frames('chatqq').allowf(\"" + selfname +
"\");>同意 </a>  <a href=javascript:top.frames('chatqq').rejectf
(\"" + selfname + "\");>不同意 </a>";
//接受者未在线,直接存入数据库;
if(context.Cache[friendname] == null)
{
string insertstr = "insert msg(sendername,receivername,msg) values('";
insertstr += ("qucha" + "','" + friendname + "','" + msg + "')");
s.ExecuteSql(insertstr); //存入数据库
}
else //在线,放入内存,等待接收。
{
Msg mymsg = new Msg("qucha", msg);
((ChatUser)(context.Cache[friendname])).Message.Add(mymsg);
}
}
// 添加好友第三步,同意被加为好友
// friendname 好友账号
[WebMethod]
public void PermitAddFriend(string friendname)
{
string friendid = ""; //好友的id
Sql s0 = new Sql();
SqlDataReader r0 = s0.GetReader("select userid from userinfo where username=
'" + friendname + "'");
if(r0.Read()) //得到好友id
friendid = r0["userid"].ToString();
r0.Close();
s0 = null; //清除连接
//添加为好友
s.ExecuteSql("insert friend (type,userid,othername)values(0," + friendid
+ ",'" + selfname + "')", false);
SqlDataReader r = s.GetReader("select id from friend where userid =" + selfid
+ " and othername = '" + friendname + "'");
if(!r.HasRows) //自己未在对方的联系人列表中
{
r.Close();
//把自己加到对方的陌生人中
s.ExecuteSql("insert friend (type,userid,othername)values(2," + selfid
+ ",'" + friendname + "')");
}
else
r.Close(); //关闭连接
HttpContext context = HttpContext.Current;
//构造消息字符串
string msg = selfname + " 同意了您的好友请求<br/>";
//接受者未在线,直接插入数据库;
if(context.Cache[friendname] == null)
{
string insertstr = "insert msg(sendername,receivername,msg) values('";
insertstr += ("qucha" + "','" + friendname + "','" + msg + "')");
s.ExecuteSql(insertstr); //插入记录
}
else//在线,放入内存,等待接收
{
Msg mymsg = new Msg("qucha", msg); //构造系统消息
((ChatUser)(context.Cache[friendname])).Message.Add(mymsg);
}
}
//添加好友 第三步(2)拒绝被加为好友
//friendname 被添加者的账号
[WebMethod]
public void RejectAddFriend(string friendname)
{
HttpContext context = HttpContext.Current;
string msg = selfname + " 拒绝了您的好友请求<br/>";
//接受者未在线,直接存入数据库;
if(context.Cache[friendname] == null)
{
string insertstr = "insert msg(sendername,receivername,msg) values('";
insertstr += ("qucha" + "','" + friendname + "','" + msg + "')");
s.ExecuteSql(insertstr); //存入数据库
}
//在线,放入内存,等待接收。
else
{
Msg mymsg = new Msg("qucha", msg); //系统消息
((ChatUser)(context.Cache[friendname])).Message.Add(mymsg);
}
}
#endregion
18.5.3 获取聊天记录
GroupMsgHistory() 和MsgHistory()方法分别用来获取群聊天和两人聊天的聊天记录。无论群聊天还是两人聊天,最新的聊天记录都保存在Cache中。所以,获取聊天记录时,首先需要从Cache中获得聊天记录。然后再从数据库中获取聊天记录,最后将两者进行组合发送给用户。获取聊天记录的相关程序代码如下:
#region 聊天记录
// 获取群聊天的记录
// groupid 群号
[WebMethod]
public DataView GroupMsgHistory(string groupid)
{
Sql sql = new Sql();
DataSet ds;
string s = "select sendername,sendtime,msg from groupmsg where groupid
= " + groupid + "";
HttpContext context = HttpContext.Current;
ds = sql.getMyDataSet(s); //得到数据库中本群的所有消息
if(context.Cache["$" + groupid] != null) //如果cache中还存在本群的消息
{
MyGroup gmt = (MyGroup)(context.Cache["$" + groupid]);
for(int i = 0; i < gmt.List.Count; i++) //遍历cache中本群的每条聊天记录
{
BaseMsg bm = (BaseMsg)(gmt.List[i]);
//把记录添加到返回的数据中
ds.Tables[0].Rows.Add(new object[] { bm.SenderName, bm.SendTime,
bm.Message });
}
}
ds.Tables[0].DefaultView.Sort = "sendtime desc";//数据按发送时间进行排序
return ds.Tables[0].DefaultView;
}
// 获取两人聊天的记录
//othername 和自己聊天者的name
[WebMethod]
public DataView MsgHistory(string othername)
{
Sql sql = new Sql();
DataSet ds; //聊天的记录集
string s = "select sendername,sendtime,msg,receivername from msg where
(sendername= '"+ selfname + "' and receivername = '" + othername + "')
or (sendername='" + othername + "' and receivername='" + selfname + "')";
ds = sql.getMyDataSet(s); //得到数据库中需要的所有的数据
if(HttpContext.Current.Cache[selfname] != null) //自己的内存块中存有数据
{
MsgTable gmt = ((ChatUser)(HttpContext.Current.Cache[selfname])).
Message;
//遍历每条数据,把符合条件的数据添加到返回的数据集合中
for(int i = 0; i < gmt.List.Count; i++)
{
Msg bm = (Msg)(gmt.List[i]);
if(bm.SenderName == othername) //符合条件
ds.Tables[0].Rows.Add(new object[] { bm.SenderName, bm.Send
Time, bm.Message, selfname });
}
}
if(HttpContext.Current.Cache[othername] != null)//聊天对方的内存块中存有数据
{
//遍历每条数据,把符合条件的数据添加到返回的数据集合中
MsgTable gmt = ((ChatUser)(HttpContext.Current.Cache[othername])).
Message;
for(int i = 0; i < gmt.List.Count; i++)
{
Msg bm = (Msg)(gmt.List[i]);
if(bm.SenderName == selfname) //符合条件,添加数据
ds.Tables[0].Rows.Add(new object[] { bm.SenderName, bm.
SendTime, bm.Message, othername });
}
}
ds.Tables[0].DefaultView.Sort = "sendtime desc"; //数据排序
return ds.Tables[0].DefaultView;
}
#endregion
18.5.4 其他代码
除了上面介绍的程序代码外,Web服务层还包括其他一些功能代码。例如,登录,增、删黑名单,接收系统消息、判断某人是否给自己发送了最新消息等。具体实现代码如下:
using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace MyChat
{
// 聊天程序web服务
[WebService(Namespace = "http://www.qucha.net/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class improve : System.Web.Services.WebService
{
Sql s = new Sql(); //数据库操作类
int selfid=0; //用户id
string selfname=""; //用户名
public improve()
{
//初始化各种变量
if(User.Identity.IsAuthenticated) //用户已经登录
{
selfname = User.Identity.Name; //给name赋值
selfid = int.Parse(tools.GetUserId(selfname)); //给id赋值
}
}
// 登录 ,返回0操作失败,返回1操作成功,返回2密码错误
[WebMethod]
public int Login(string username, string pass)
{
int b = 0; //登录成功与否的标志
int userid = 1;
pass = tools.Encrypt(pass, "12345678"); //密码加密
//获取用户id
SqlDataReader r = s.GetReader("select userid,pass from userinfo where
username='" + username + "'");
if(r.Read() && r[1].ToString() != pass) //如果存在这个用户,但密码错误
{
r.Close(); //关闭连接
return 2; //返回2
}
else if (r.HasRows == false) //不存在这个用户,则在数据库中存入这个用户
{
r.Close(); //关闭连接
s.ExecuteSql("insert userinfo(pass,username) values ('" + pass +
"','" + username + "')", false);
//重新获取此用户的id
r = s.GetReader("select userid from userinfo where username='" +
username + "'");
r.Read();
}
userid = int.Parse(r[0].ToString()); //获取用户id
//登录
System.Web.Security.FormsAuthentication.RedirectFromLoginPage(username,
false );
selfid = userid; //用户id
selfname = username; //用户name
try
{
//初始化一个聊天用户类
MyChat.tools.AddNewUser(HttpContext.Current) ;
b = 1; //操作成功完成
tools.UpdateSelfTime(); //更新自己的过期时间
}
catch
{ }
return b;
}
// 删除好友
//friendname 好友的账号
[WebMethod]
public void DelFriend(string friendname)
{
string userid = tools.GetUserId(User.Identity.Name); //自己的id
//删除
s.ExecuteSql("delete from friend where userid =" + userid + " and
othername = '" + friendname + "' type =0");
}
#region 添加删除黑名单的操作
//添加黑名单
[WebMethod]
public void AddBlack(string blackname, string blackid)
{
//如果此用户在两个人的联系人名单中,删除这些信息
s.ExecuteSql("delete from friend where userid =" + selfid + " and
othername = '" + blackname + "'", false);
s.ExecuteSql("delete from friend where userid =" + blackid + " and
othername = '" + selfname + "'", false);
//插入黑名单
s.ExecuteSql("insert friend (type,userid,othername)values(1," +
selfid.ToString() + ",'" + blackname + "')");
}
//删除黑名单
[WebMethod]
public void DelBlack(string blackname)
{
s.ExecuteSql("delete from friend where userid =" + selfid.ToString()
+ " and othername = '" + blackname + "' type =1"); //删除
}
#endregion
// 判断特定用户是否给自己发送了新消息
//sn发送者姓名
//返回ture有新消息
public bool CheckMessage(string sn)
{
bool b = false;
string temp = "0"; //内存中存在的聊天记录id 的字符串
ChatUser my = (ChatUser)(HttpContext.Current.Cache[selfname]);
if(my == null) //没有聊天用户类,初始化一个
{
tools.AddNewUser(HttpContext.Current);
my = (ChatUser)(HttpContext.Current.Cache[selfname]);
}
//遍历自己的消息表,判断是否存在某用户的未读消息
for(int i = 0; i < my.Message.List.Count; i++)
{
//存在这样的消息
if(((Msg)(my.Message.List[i])).SenderName == sn && ((Msg)(my.
Message.List[i])).IfRead == false)
{
b = true;
return b; //存在消息返回
}
temp += ("," + i); //记录下已经处理的消息id
}
if(my.Message.HaveOtherMsg == true) //如果数据库中还有数据
{
Sql q = new Sql();
//读取所有符合条件的数据
SqlDataReader reader = q.GetReader("Select [id] From msg Where
[receivername] ='"+ selfname + "' and sendername='" + sn + "' and
ifread=1 and id not in (" + temp + ") ");
//有新消息
if(reader.HasRows)
{
b = true;
}
reader.Close();
}
return b;
}
// 得到特定用户的系统消息总数
public int GetSysMsgNum()
{
int b = 0;
string temp = "0"; //内存中存在的聊天记录id 字符串
ChatUser my = (ChatUser)(HttpContext.Current.Cache[selfname]);
if(my == null) //聊天用户类不存在,初始化一个
{
tools.AddNewUser(HttpContext.Current);
my = (ChatUser)(HttpContext.Current.Cache[selfname]);
}
//遍历所有数据,查询qucha发送的数据(即系统消息)
for(int i = 0; i < my.Message.List.Count; i++)
{
if(((Msg)(my.Message.List[i])).SenderName == "qucha" && ((Msg)
(my.Message.List[i])).IfRead == false)
{
b++; //找到一条记录,数目加1
}
temp += ("," + i);
}
//数据库中还有其他数据
if(my.Message.HaveOtherMsg == true)
{
Sql q = new Sql();
//取数据
DataSet ds = q.getMyDataSet("Select [id] From msg Where
[receivername] ='"+ selfname + "' and sendername='" + "qucha" +
"' and ifread=1 and id not in (" + temp + ") ");
b += ds.Tables[0].Rows.Count; //把数目加上
}
return b;
}
}
}







