大家都知道WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
自从html5支持websocket以后,开始被大家用来实时通讯。下面分享一个使用websocket搭建的智能聊天系统:
智能聊天系统二维码,系统使用了地位,可使用手机端查看:
后台是使用C#开发的,下面给大家分享一下代码:
一、搭建websocket服务
后台新建一个一般处理程序Handler1 ,用于接受和发送消息(具体操作都写了注释):
/// <summary>
/// 离线消息
/// </summary>
public class MessageInfo
{
public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
{
MsgTime = _MsgTime;
MsgContent = _MsgContent;
}
public DateTime MsgTime { get; set; }
public ArraySegment<byte> MsgContent { get; set; }
}
/// </summary>
public class Handler1 : IHttpHandler
{
private IB_h_userinfo h_userinfo = BLLContainer.UnityIOC.Resolve<IB_h_userinfo>();
private IB_liaotian b_liaotian = BLLContainer.UnityIOC.Resolve<IB_liaotian>();
private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
public void ProcessRequest(HttpContext context)
{
//context.Response.ContentType = "text/plain";
//context.Response.Write("Hello World");
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(ProcessChat);
}
}
//添加用户信息,用做后期统计
private void AddUser(string user, string address)
{
h_userinfo userinfo = h_userinfo.GetModel(p => p.username.Equals(user));
if (userinfo != null)
{
//是否获取到定位地址
if (address != null && userinfo.Address != address.Replace(',', ' '))
{
string[] adds = address.Split(',');
userinfo.Province = adds[0];//省
userinfo.City = adds[1];//所在市
userinfo.Address = address.Replace(',',' ');//详情地址
}
userinfo.LastLandTime = DateTime.Now;//最后登录时间
h_userinfo.Update(userinfo);//更新用户数据
return;
}
else
{
h_userinfo m_UserDb = new h_userinfo();
m_UserDb.username = user;
m_UserDb.pwd = Tools.DESEncrypt.GetMd5("123456", 32).ToUpper();
m_UserDb.NickName = "";
m_UserDb.LastLandTime = DateTime.Now;
m_UserDb.RegTime = DateTime.Now;
m_UserDb.IsActivation = 0;
m_UserDb.email = "";
m_UserDb.RegType = 2;
m_UserDb.Address = address;
int regOk = h_userinfo.CompatibleUser_Add(m_UserDb);//添加一条用户数据
}
}
private async Task ProcessChat(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
string user = context.QueryString["user"].ToString();//用户名,ip地址
var ToUser = context.QueryString["ToUser"];//目的用户
var type = context.QueryString["type"];//类型 1管理员
var address = context.QueryString["address"];//用户地址
try
{
//将用户信息添加到数据库
AddUser(user, address);
#region 用户添加连接池
//第一次open时,添加到连接池中
if (!CONNECT_POOL.ContainsKey(user))
CONNECT_POOL.Add(user, socket);//不存在,添加
else
if (socket != CONNECT_POOL[user])//当前对象不一致,更新
CONNECT_POOL[user] = socket;
#endregion
#region 离线消息处理
if (MESSAGE_POOL.ContainsKey(user))
{
List<MessageInfo> msgs = MESSAGE_POOL[user];
foreach (MessageInfo item in msgs)
{
await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
}
MESSAGE_POOL.Remove(user);//移除离线消息
}
else
{
if (ToUser != null && type == null)
{
string message = "您好!我可以为您做点什么?(你可以对我说“讲个笑话”,“北京天气”)";
SendMessage(user, message);//自动回复
}
}
#endregion
string descUser = string.Empty;//目的用户
bool isRenGong = false;
while (true)
{
if (socket.State == WebSocketState.Open)
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024*8*10]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);//接收发送过来的信息
#region 消息处理(字符截取、消息转发)
try
{
#region 关闭Socket处理,删除连接池
if (socket.State != WebSocketState.Open)//连接关闭
{
if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
break;
}
#endregion
string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
string[] msgList = userMsg.Split('|');
if (msgList.Length == 2)
{
if (msgList[0].Trim().Length > 0)
descUser = msgList[0].Trim();//记录消息目的用户
string message = msgList[1];
MessageModel mes = new MessageModel();
mes.content = message;
mes.username = user;
mes.datetime = DateTime.Now.ToString("MM-dd HH:mm:ss");
mes.address = address;
string obj = JsonConvert.SerializeObject(mes);
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(obj));
if (message.Trim() == "呼叫主人" || isRenGong || (type != null && type.ToZMInt32() == 1))//判断是否真人回复,(客户端发送“呼叫主人”或者type=1时,信息会发送给目的用户)
{
isRenGong = true;
if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
{
WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
if (destSocket != null && destSocket.State == WebSocketState.Open)
await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
Task.Run(() =>
{
if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
});
}
if (message.Trim() == "呼叫主人")
{
message = "主人正在赶来的路上~~~~";
SendMessage(user, message);//自动回复
}
}
else if (message.Contains("笑话"))//信息中包含“笑话”表示回复笑话
{
string con = h_userinfo.SearchValue("select content from lengxiaohua where id=" + new Random().Next(1, 1000)).ToString();
SendMessage(user, con);//自动回复
}
else if (message.Contains("天气"))
{
object city_code = null;
message = message.Replace("市", "").Replace("县", "").Replace("今天", "").Replace("的", "").Replace("天气", "").Trim();
if (message.Replace("明天", "") != "" || message.Replace("后天", "") != "")
{
string tianqi = "";
if(message.Contains("明天")){
tianqi += "%mingtiantianqi";
message = message.Replace("明天", "");
}
if (message.Contains("后天"))
{
tianqi += "%houtiantianqi";
message = message.Replace("后天", "");
}
if (message.Length > 2)
{
message = message.Substring(0, 2);
}
city_code = h_userinfo.SearchValue("select city_code from city_code where area like '%" + message + "%' or city like '%" + message + "%'");
if (city_code != null)
tianqi += Tools.HttpHelper.submitData("", "http://t.weather.sojson.com/api/weather/city/" + city_code + "", "json", "get");
if (tianqi!="")
SendMessage(user, tianqi + "%tianqi");//自动回复
}
if (address != null && city_code == null)
{
string tianqi = "";
if (message.Contains("明天"))
{
tianqi += "%mingtiantianqi";
}
if (message.Contains("后天"))
{
tianqi += "%houtiantianqi";
}
string[] adds = address.Split(',');
string city = adds[1].Replace("市", "");
if (city.Length > 4)
{
city = city.Substring(0, 2);
}
string area = adds[2].Substring(0, 2);
city_code = h_userinfo.SearchValue("select city_code from city_code where area like '%" + area + "%' and city like '%" + city + "%'");
if (city_code == null)
{
city_code = h_userinfo.SearchValue("select city_code from city_code where city like '%" + city + "%'");
}
if (city_code != null)
{
tianqi += Tools.HttpHelper.submitData("", "http://t.weather.sojson.com/api/weather/city/" + city_code + "", "json", "get");
}
SendMessage(user, tianqi + "%tianqi");//自动回复
}
}
else
{
AutomaticReply(user, message);//智能回复
}
}
else//不存在目的用户时默认群发
{
MessageModel mes = new MessageModel();
mes.content = userMsg;
mes.username = user;
mes.datetime = DateTime.Now.ToString("MM-dd HH:mm:ss");
mes.address = address;
string obj = JsonConvert.SerializeObject(mes);
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(obj));
//foreach (KeyValuePair<string, WebSocket> item in CONNECT_POOL)
//{
// if (item.Value != CONNECT_POOL[user])
// await item.Value.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
//}
List<h_userinfo> users = h_userinfo.GetModels(p => p.RegType == 2).ToList();
foreach (h_userinfo userinfo in users)
{
if (CONNECT_POOL.ContainsKey(userinfo.username))//判断客户端是否在线
{
WebSocket destSocket = CONNECT_POOL[userinfo.username];//目的客户端
if (destSocket != null && destSocket.State == WebSocketState.Open && destSocket != CONNECT_POOL[user])
await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
Task.Run(() =>
{
if (!MESSAGE_POOL.ContainsKey(userinfo.username))//将用户添加至离线消息池中
MESSAGE_POOL.Add(userinfo.username, new List<MessageInfo>());
MESSAGE_POOL[userinfo.username].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
});
}
}
}
}
catch (Exception exs)
{
//消息转发异常处理,本次消息忽略 继续监听接下来的消息
}
#endregion
}
else
{
break;
}
}//while end
}
catch (Exception ex)
{
//整体异常处理
if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
}
}
private void AutomaticReply(string user, string message)
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024*8*10]);
WebSocket destSocket = null;
MessageModel mes = new MessageModel();
var con = h_userinfo.SearchValue("select answer from liaotian where question like '" + message + "'");
if (con == null)
{
con = h_userinfo.SearchValue("select answer from liaotian where question like '" + message + "%'");
}
if (con == null)
{
con = h_userinfo.SearchValue("select answer from liaotian where question like '%" + message + "%'");
}
if (con != null)
{
string content = con.ToString();
content = content.Replace("[cqname]", "笑笑").Replace("[name]", "你");
mes.content = content;
}
else
{
mes.content = "笑笑同学还是个孩子,听不懂你在说什么,让我的主人来帮你解答,你可以对我说“<span style='font-weight: bold;'>呼叫主人<span>”";
}
mes.username = "笑笑机器人";
mes.datetime = DateTime.Now.ToString("MM-dd HH:mm:ss");
string obj = JsonConvert.SerializeObject(mes);
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(obj));
destSocket = CONNECT_POOL[user];//目的客户端
if (destSocket != null && destSocket.State == WebSocketState.Open)
destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
private void SendMessage(string user, string message)
{
MessageModel mes = new MessageModel();
mes.content = message;
mes.username = "笑笑机器人";
mes.datetime = DateTime.Now.ToString("MM-dd HH:mm:ss");
string obj = JsonConvert.SerializeObject(mes);
ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(obj));
WebSocket destSocket = CONNECT_POOL[user];//目的客户端
if (destSocket != null && destSocket.State == WebSocketState.Open)
destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
public bool IsReusable
{
get
{
return false;
}
}
public class MessageModel
{
public string username { get; set; }
public string datetime { get; set; }
public string content { get; set; }
public string address { get; set; }
}
}
二、添加相关数据库表
这里使用的MySql数据库,代码中有用到一张用户表,城市代码表(用于查询天气),笑话表,智能聊天数据表。
1、用户表
用户表只存了基本的IP地址,前台获取到的定位信息,添加时间和登录时间,注册类型等;
/*
Navicat MySQL Data Transfer
Source Server : 云mysql
Source Server Version : 50628
Source Host : gz-cdb-mskal2se.sql.tencentcdb.com:62567
Source Database : hua
Target Server Type : MYSQL
Target Server Version : 50628
File Encoding : 65001
Date: 2018-09-30 11:27:16
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for h_userinfo
-- ----------------------------
DROP TABLE IF EXISTS `h_userinfo`;
CREATE TABLE `h_userinfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(200) DEFAULT NULL,
`pwd` varchar(32) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`IsActivation` int(1) DEFAULT '0',
`MobilePhone` varchar(20) DEFAULT NULL,
`IsBindPhone` int(1) DEFAULT '0',
`BindPhoneDate` datetime DEFAULT NULL,
`NickName` varchar(50) DEFAULT NULL,
`Male` char(2) DEFAULT '男',
`Birth` date DEFAULT NULL,
`IdentityCode` varchar(50) DEFAULT NULL,
`Province` varchar(50) DEFAULT NULL,
`City` varchar(50) DEFAULT NULL,
`Address` varchar(50) DEFAULT NULL,
`RegTime` datetime DEFAULT CURRENT_TIMESTAMP,
`LastLandTime` datetime DEFAULT NULL,
`Status` int(1) DEFAULT '0',
`PayPwd` varchar(50) DEFAULT NULL,
`AddDate` datetime DEFAULT CURRENT_TIMESTAMP,
`RealName` varchar(20) DEFAULT NULL,
`amount` double DEFAULT NULL,
`RegType` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
2、城市代码表
通过城市名查询对应城市代码,具体sql如下:
/*
Navicat MySQL Data Transfer
Source Server : 云mysql
Source Server Version : 50628
Source Host : gz-cdb-mskal2se.sql.tencentcdb.com:62567
Source Database : hua
Target Server Type : MYSQL
Target Server Version : 50628
File Encoding : 65001
Date: 2018-09-30 11:25:42
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for city_code
-- ----------------------------
DROP TABLE IF EXISTS `city_code`;
CREATE TABLE `city_code` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`province` varchar(50) DEFAULT NULL,
`city` varchar(255) DEFAULT NULL,
`area` varchar(255) DEFAULT NULL,
`city_code` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2565 DEFAULT CHARSET=utf8;
INSERT INTO `city_code` VALUES (1, '北京', '北京', '北京', '101010100');
具体数据可到https://download.csdn.net/download/lwpoor123/10697421下载
3、冷笑话表
保存笑话数据,应为数据太多,这里就提供一条sql示例:
/*
Navicat MySQL Data Transfer
Source Server : 云mysql
Source Server Version : 50628
Source Host : gz-cdb-mskal2se.sql.tencentcdb.com:62567
Source Database : hua
Target Server Type : MYSQL
Target Server Version : 50628
File Encoding : 65001
Date: 2018-09-30 11:24:42
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for lengxiaohua
-- ----------------------------
DROP TABLE IF EXISTS `lengxiaohua`;
CREATE TABLE `lengxiaohua` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(2047) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9720 DEFAULT CHARSET=utf8;
INSERT INTO `lengxiaohua` VALUES (1, '今天走在路上,突然一个女生过来问我:亲,你这头哪剪的?我说:在XXX剪的。这时她男朋友走过来了,她挽着她老公的胳膊边走边说:以后别去XXX剪头了。结果她男朋友说:SB才去那剪头呢!');
具体数据可到https://download.csdn.net/download/lwpoor123/10697447下载
4、聊天表
存储智能聊天数据,sql如下:
/*
Navicat MySQL Data Transfer
Source Server : 云mysql
Source Server Version : 50628
Source Host : gz-cdb-mskal2se.sql.tencentcdb.com:62567
Source Database : hua
Target Server Type : MYSQL
Target Server Version : 50628
File Encoding : 65001
Date: 2018-09-30 11:29:12
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for liaotian
-- ----------------------------
DROP TABLE IF EXISTS `liaotian`;
CREATE TABLE `liaotian` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`question` varchar(2047) DEFAULT NULL,
`answer` varchar(2047) DEFAULT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `问题` (`question`)
) ENGINE=InnoDB AUTO_INCREMENT=18125 DEFAULT CHARSET=utf8;
有关聊天数据可到https://download.csdn.net/download/lwpoor123/10691512下载
三、搭建前端聊天框架
前端是使用C# MVC搭建的一个聊天框架;
1、新建一个控制器WSController,控制器代码如下:
public class WSController : Controller
{
private IB_h_userinfo b_h_userinfo = BLLContainer.UnityIOC.Resolve<IB_h_userinfo>();
// GET: WS
public ActionResult Index(string name,int? type,string username,string address)
{
if (name != null)
{
string ip = name;
ViewBag.Name = ip;
}
if (type != null)
{
ViewBag.Type = type;
}
if (username != null)
{
username = username;
ViewBag.UserName = username;
}
if (address != null)
{
ViewBag.Address = address;
}
return View();
}
public void kf()
{
string ip = "18313364090";//默认客服账号
Response.Redirect("/ws?name=" + ip);
}
public void poor()
{
string ip = "18313364090";//默认客服账号
Response.Redirect("/ws?username=" + ip);
}
[HttpPost]
public string UploadImg(byte[] hpf)
{
int isOK = 0;
string filesUrl = "";
string errMsg;
//只能上传图片
var extArray = new string[] { ".gif", ".jpg", ".jpeg", ".png", ".bmp", ".pdf" };
try
{
//静态方法根据文件流判断文件类型。
//string fileType = images.Substring(11, 3);
//images = images.Substring(22);
string fileType = IsAllowedExtension(hpf);
//byte[] hpf = System.Text.Encoding.Default.GetBytes(images);
if (hpf.Length >= 0 && !string.IsNullOrEmpty(fileType))
{
if (extArray.Contains(fileType, StringComparer.CurrentCultureIgnoreCase))
{
var length = hpf.Length;
if (length <= 10 * 1024 * 1024)
{
FastDfsHelper dfsFile = new FastDfsHelper("claim");
string imgUrl = string.Empty;
Stream file = new MemoryStream(hpf);
string newfileName = string.Empty;
string litName = string.Empty;
using (Stream imageStream = file)
{
string path = "C:/hua/imgSite/hua/websocket/";
string host = "http://img.lwpoor.cn/hua/websocket/";
string imagename = Guid.NewGuid().ToString();
string imageGuid = imagename + fileType;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
Bitmap bitmap = new Bitmap(imageStream);
bitmap.Save(path + imageGuid);
imgUrl = host + imageGuid;
};
isOK = 1;
filesUrl = imgUrl;
errMsg = "文件上传成功!";
}
else
{
isOK = 2;//文件大小不能超过10M
errMsg = "您选择的文件大小不能超过 10 MB!";
}
}
else
{
isOK = 3;
errMsg = string.Format("上传文件格式必须是:{0} 其中的一种! 异常类型为{1}", extArray.Join("|"), fileType);
}
}
else
{
isOK = 4;
errMsg = "上传文件为空!长度为:" + hpf.Length + "。或类型异常:" + fileType.ToString();
}
}
catch (Exception ex)
{
isOK = 0;
errMsg = "上传失败" + ex.ToString();
}
var returnMsg = new
{
isOK = isOK,
filesUrl = filesUrl,
errMsg = errMsg,
};
return JsonConvert.SerializeObject(returnMsg);
}
#region 图片流判断类型
public static string IsAllowedExtension(byte[] fu)
{
int fileLen = fu.Length;
byte[] imgArray = new byte[fileLen];
MemoryStream ms = new MemoryStream(fu);
System.IO.BinaryReader br = new BinaryReader(ms);
string fileclass = "";
byte buffer;
try
{
buffer = br.ReadByte();
fileclass = buffer.ToString();
buffer = br.ReadByte();
fileclass += buffer.ToString();
}
catch (Exception ex)
{
throw ex;
}
br.Close();
ms.Close();
string type = ReturnImageType(Int32.Parse(fileclass));
return type;
}
public static string ReturnImageType(Int32 i)
{
string type;
switch (i)
{
case 255216:
return type = ".jpg";
case 7173:
return type = ".gif";
case 6677:
return type = ".bmp";
case 13780:
return type = ".png";
case 3780:
return type = ".pdf";
default:
return type = "";
}
}
#endregion
}
2、前端页面代码如下(代码都用相关注释):
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>笑笑同学~~~</title>
<meta name="description" content="你的专属机器人!">
<meta name="keywords" content="你的专属机器人">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="~/WebSocket/wchat/font_Icon/iconfont.css" rel="stylesheet" />
<link href="~/WebSocket/wchat/css/chat.css" rel="stylesheet" />
<style>
html {
overflow: -moz-hidden-unscrollable;
}
body::-webkit-scrollbar {
display: none;
}
body {
-ms-overflow-style: none;
overflow: auto;
}
.chatBox {
border-radius: 0px;
border: solid 0px #d5d5d5;
}
.iconfont {
font-family: "iconfont" !important;
font-size: 22px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.chatBox-send > div button {
padding: 1px 5px;
margin-left: 6px;
}
.chatBox-send {
width: 100%;
padding: 10px 5px;
background: #fff;
border-top: 1px #fff solid;
position: absolute;
bottom: 0;
left: 0;
}
.div-textarea {
margin-top: 6px;
font-family: 叶根友毛笔行书2.0版;
font-size: 16px;
border-bottom: 1px #ddd solid;
}
.div-textarea:focus {
box-shadow: 0 0 15px rgba(0, 0, 0, 0);
border-bottom: 1px #01bef0 solid;
}
.author-user {
text-align: center;
margin: 0px 0 5px 0;
color: #888;
}
.author-name {
text-align: center;
margin: 10px 0 5px 0;
color: #888;
}
</style>
</head>
<body>
<div class="chatContainer">
<div class="chatBtn">
<i class="iconfont icon-xiaoxi1"></i>
</div>
<div class="chat-message-num"></div>
<div class="chatBox" ref="chatBox">
<div class="chatBox-head">
<div class="chatBox-head-one">
Conversations
<div class="chat-close" style="margin: 10px 10px 0 0;font-size: 14px">关闭</div>
</div>
<div class="chatBox-head-two">
<div class="chat-return">返回</div>
<div class="chat-people">
<div class="ChatInfoHead">
<img src="" alt="头像" />
</div>
<div class="ChatInfoName">这是用户的名字,看看名字到底能有多长</div>
</div>
<div class="chat-close">关闭</div>
</div>
</div>
<div class="chatBox-info">
<div class="chatBox-list" ref="chatBoxlist">
<div class="chat-list-people">
<div><img src="/WebSocket/wchat/img/touxiang.png" alt="头像" /></div>
<div class="chat-name">
<p>笑笑机器人</p>
</div>
<div class="message-num"></div>
</div>
</div>
<div class="chatBox-kuang" ref="chatBoxkuang">
<div class="chatBox-content">
<div class="chatBox-content-demo" id="chatBox-content-demo">
</div>
</div>
<div class="chatBox-send">
<div class="div-textarea" contenteditable="true"></div>
<div>
<button id="chat-biaoqing" class="btn-default-styles">
<i class="iconfont icon-biaoqing"></i>
</button>
<label id="chat-tuxiang" title="发送图片" for="file" class="btn-default-styles">
<input type="file" onchange="selectImg(this)" accept="image/jpg,image/jpeg,image/png,image/gif"
name="file" id="file" class="hidden">
<i class="iconfont icon-tuxiang"></i>
</label>
<button id="chat-fasong" class="btn-default-styles">
<i class="iconfont icon-fasong"></i>
</button>
</div>
<div class="biaoqing-photo">
<ul>
<li><span class="emoji-picker-image" style="background-position: -9px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -40px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -71px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -102px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -133px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -164px -18px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -9px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -40px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -71px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -102px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -133px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -164px -52px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -9px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -40px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -71px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -102px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -133px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -164px -86px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -9px -120px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -40px -120px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -71px -120px;"></span></li>
<li>
<span class="emoji-picker-image" style="background-position: -102px -120px;"></span>
</li>
<li>
<span class="emoji-picker-image" style="background-position: -133px -120px;"></span>
</li>
<li>
<span class="emoji-picker-image" style="background-position: -164px -120px;"></span>
</li>
<li><span class="emoji-picker-image" style="background-position: -9px -154px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -40px -154px;"></span></li>
<li><span class="emoji-picker-image" style="background-position: -71px -154px;"></span></li>
<li>
<span class="emoji-picker-image" style="background-position: -102px -154px;"></span>
</li>
<li>
<span class="emoji-picker-image" style="background-position: -133px -154px;"></span>
</li>
<li>
<span class="emoji-picker-image" style="background-position: -164px -154px;"></span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<input type="hidden" id="ToName" value="@ViewBag.Name" />
<input type="hidden" id="ToAddress" value="@ViewBag.Address" />
<input type="hidden" id="UserName" value="@ViewBag.UserName" />
<input type="hidden" id="UserType" value="@ViewBag.Type" />
<input type="hidden" id="userIp" value="@Tools.PublicConfig.getIp()" />
<script src="~/WebSocket/wchat/js/jquery.min.js"></script>
<script src="~/layer/layer.js"></script>
<script>
$(function () {
screenFuc();
});
(window.onresize = function () {
screenFuc();
})();
function screenFuc() {
var topHeight = $(".chatBox-head").innerHeight();//聊天头部高度
if ($('#UserType').val() != "1") {
if (isWeiXinBrowser()) {
$(".chatBox-head").remove();
topHeight = 0;
$(".chatBox-info").css("top", 0);
}
}
//屏幕小于768px时候,布局change
var winWidth = $(window).innerWidth();
if (winWidth <= 768) {
var totalHeight = $(window).height(); //页面整体高度
$(".chatBox-info").css("height", totalHeight - topHeight);
var infoHeight = $(".chatBox-info").innerHeight();//聊天头部以下高度
//中间内容高度
$(".chatBox-content").css("height", infoHeight - 50);
$(".chatBox-content-demo").css("height", infoHeight - 50);
$(".chatBox-list").css("height", totalHeight - topHeight);
$(".chatBox-kuang").css("height", totalHeight - topHeight);
$(".div-textarea").css("width", winWidth - 130);
} else {
$(".chatBox-info").css("height", 495);
$(".chatBox-content").css("height", 448);
$(".chatBox-content-demo").css("height", 448);
$(".chatBox-list").css("height", 495);
$(".chatBox-kuang").css("height", 495);
$(".div-textarea").css("width", 240);
}
}
//判断是否为微信浏览器
function isWeiXinBrowser() {
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true;
} else {
return false;
}
}
//未读信息数量为空时
var totalNum = $(".chat-message-num").html();
if (totalNum == "") {
$(".chat-message-num").css("padding", 0);
}
$(".message-num").each(function () {
var wdNum = $(this).html();
if (wdNum == "") {
$(this).css("padding", 0);
}
});
//打开/关闭聊天框
$(".chatBtn").click(function () {
$(".chatBox").toggle(10);
})
$(".chat-close").click(function () {
$(".chatBox").toggle(10);
//ws.close();
})
//进聊天页面
$(".chat-list-people").each(function () {
$(this).click(function () {
var n = $(this).index();
$(".chatBox-head-one").toggle();
$(".chatBox-head-two").toggle();
$(".chatBox-list").fadeToggle();
$(".chatBox-kuang").fadeToggle();
var username = $(this).children(".chat-name").children("p").eq(0).html();
//传名字
$(".ChatInfoName").text(username);
//传头像
$(".ChatInfoHead>img").attr("src", $(this).children().eq(0).children("img").attr("src"));
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
})
});
//返回列表
$(".chat-return").click(function () {
$(".chatBox-head-one").toggle(1);
$(".chatBox-head-two").toggle(1);
$(".chatBox-list").fadeToggle(1);
$(".chatBox-kuang").fadeToggle(1);
});
//发送信息
$("#chat-fasong").click(function () {
var textContent = $(".div-textarea").html().replace(/[\n\r]/g, '<br>')
if (textContent != "") {
$(".chatBox-content-demo").append("<div class=\"clearfloat\">" +
"<div class=\"author-name\"><small class=\"chat-date\">" + tick() + "</small> </div> " +
"<div class=\"author-user\" style=\"text-align:right;\"><small class=\"chat-date\">@Tools.PublicConfig.getIp()</small> </div>" +
"<div class=\"right\"> <div class=\"chat-message\"> " + textContent + " </div> " +
"<div class=\"chat-avatars\"><img src=\"/WebSocket/wchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>");
//发送后清空输入框
$(".div-textarea").html("");
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
sendMessage(textContent);
}
});
//发送表情
$("#chat-biaoqing").click(function () {
$(".biaoqing-photo").toggle();
});
$(document).click(function () {
$(".biaoqing-photo").css("display", "none");
});
$("#chat-biaoqing").click(function (event) {
event.stopPropagation();//阻止事件
});
$(".emoji-picker-image").each(function () {
$(this).click(function () {
var bq = $(this).parent().html();
console.log(bq)
$(".chatBox-content-demo").append("<div class=\"clearfloat\">" +
"<div class=\"author-name\"><small class=\"chat-date\">" + tick() + "</small> </div> " +
"<div class=\"author-user\" style=\"text-align:right;\"><small class=\"chat-date\">@Tools.PublicConfig.getIp()</small> </div>" +
"<div class=\"right\"> <div class=\"chat-message\"> " + bq + " </div> " +
"<div class=\"chat-avatars\"><img src=\"/WebSocket/wchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>");
//发送后关闭表情框
$(".biaoqing-photo").toggle();
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
sendMessage(bq);
})
});
//发送图片
function selectImg(pic) {
if (!pic.files || !pic.files[0]) {
return;
}
var reader = new FileReader();
reader.onload = function (evt) {
var images = evt.target.result;
$(".chatBox-content-demo").append("<div class=\"clearfloat\">" +
"<div class=\"author-name\"><small class=\"chat-date\">" + tick() + "</small> </div> " +
"<div class=\"right\"> <div class=\"chat-message\"><img src=" + images + "></div> " +
"<div class=\"chat-avatars\"><img src=\"/WebSocket/wchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>");
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
var data = images.replace("data:image/png;base64,", "");
data = data.replace("data:image/gif;base64,", "");
data = data.replace("data:image/jpg;base64,", "");
data = data.replace("data:image/jpeg;base64,", "");
data = data.replace("data:image/bmp;base64,", "");
data = data.replace("data:image/pdf;base64,", "");
$.ajax({
url: "http://m.lwpoor.cn/ws/UploadImg",
type: "post",
dataType: "json",
data: { hpf: data },
success: function (data) {
var url = data.filesUrl;
sendMessage(url + "%images")
},
error: function (e, s, c) {
}
})
};
reader.readAsDataURL(pic.files[0]);
}
function tick() {
var date = new Date();
this.year = date.getFullYear();
this.month = date.getMonth() + 1;
this.date = date.getDate();
this.day = new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六")[date.getDay()];
this.hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
this.minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
this.second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return this.month + "-" + this.date + " " + this.hour + ":" + this.minute + ":" + this.second + " " + this.day;
}
function sendMessage(msg) {
if (ws.readyState == WebSocket.OPEN) {
var user = $.trim($("#ToName").val());
if (user == "") {
ws.send(msg);
} else {
ws.send(user + "|" + msg);
}
}
else {
layer.msg('连接已经关闭');
}
}
</script>
<script>
$(function () {
$(".chatBox-head-one").toggle();
$(".chatBox-head-two").toggle();
$(".chatBox-list").fadeToggle();
$(".chatBox-kuang").fadeToggle();
$(".chat-return").hide();
$(".chat-close").hide();
//传名字
$(".ChatInfoName").text("笑笑机器人");
//传头像
$(".ChatInfoHead>img").attr("src", "http://m.lwpoor.cn/WebSocket/wchat/img/touxiang.png");
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
if ($('#UserType').val() == "1") {
var username = $('#ToName').val();
var address = $('#ToAddress').val();
$(".ChatInfoName").hide();
$(".ChatInfoHead").hide();
$('.chat-people').html("<span>" + username + "(" + address + ")</span>")
}
})
</script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.4"></script>
<script>
var address = getStor("address", 30);
var mesCount = 0;
var ws;
$(function () {
var url = "ws://m.lwpoor.cn/WebSocket/[email protected]()";
var username = $.trim($("#UserName").val());
if (username != "") {
url = "ws://m.lwpoor.cn/WebSocket/Handler1.ashx?user=" + username;
}
var user = $.trim($("#ToName").val());
if (user != "") {
url += "&ToUser=" + user;
}
var type = $.trim($("#UserType").val());
if (type != "") {
url += "&type=" + type;
}
if (address != null && address != "") {
url += "&address=" + address;
}
ws = new WebSocket(url);
ws.onopen = function () {
layer.msg("连接成功!");
}
ws.onmessage = function (evt) {
if (evt.data != "") {
mesCount++;
var data = JSON.parse(evt.data);
var message = data.content;
var length = message.length;
var html = "";
if (message.indexOf("%images") > -1) {
message = message.replace("%images", "");
html = "<div class=\"clearfloat\">";
html += "<div class=\"author-name\"><small class=\"chat-date\">" + data.datetime + "</small> </div> ";
html += ($('#UserName').val() == "18313364090") ?
"<div class=\"author-user\" style=\"text-align:left;\"><small onclick=\"goToUser('" + data.username + "','" + data.address + "')\" class=\"chat-date\">" + data.username + ":" + data.address + "</small> </div>" :
"<div class=\"author-user\" style=\"text-align:left;\"><small class=\"chat-date\">" + data.username + "</small> </div>";
html += "<div class=\"left\"> <div class=\"chat-avatars\"><img src=\"/WebSocket/wchat/img/touxiang.png\" alt=\"头像\" /></div> ";
html += "<div class=\"chat-message\"><img src=" + message + "></div> </div> </div>";
} else {
if (message.indexOf("%tianqi") > -1) {
message = message.replace("%tianqi", "");
try {
if (message.indexOf("%mingtiantianqi") > -1) {
message = message.replace("%mingtiantianqi", "");
var weatherinfo = JSON.parse(message);
var city = weatherinfo.cityInfo.city;//城市
var wendu = weatherinfo.data.wendu;//当前温度
var quality = weatherinfo.data.quality;//空气质量
var shidu = weatherinfo.data.shidu;//湿度
var high = weatherinfo.data.forecast[1].high.replace("高温", "").replace(".0", "");//最高温度
var low = weatherinfo.data.forecast[1].low.replace("低温", "").replace(".0", "");//最低温度
var sunset = weatherinfo.data.forecast[1].sunset;//日落时间
var fx = weatherinfo.data.forecast[1].fx;//风向
var type = weatherinfo.data.forecast[1].type;//天气
var notice = weatherinfo.data.forecast[1].notice;//通知
message = city + "明天" + type + "," + low + "到" + high + "," + fx + ",空气质量" + quality + "~~~" + notice + "。"
}
else if (message.indexOf("%houtiantianqi") > -1) {
message = message.replace("%houtiantianqi", "");
var weatherinfo = JSON.parse(message);
var city = weatherinfo.cityInfo.city;//城市
var wendu = weatherinfo.data.wendu;//当前温度
var quality = weatherinfo.data.quality;//空气质量
var shidu = weatherinfo.data.shidu;//湿度
var high = weatherinfo.data.forecast[2].high.replace("高温", "").replace(".0", "");//最高温度
var low = weatherinfo.data.forecast[2].low.replace("低温", "").replace(".0", "");//最低温度
var sunset = weatherinfo.data.forecast[2].sunset;//日落时间
var fx = weatherinfo.data.forecast[2].fx;//风向
var type = weatherinfo.data.forecast[2].type;//天气
var notice = weatherinfo.data.forecast[2].notice;//通知
message = city + "后天" + type + "," + low + "到" + high + "," + fx + ",空气质量" + quality + "~~~" + notice + "。"
}
else {
var weatherinfo = JSON.parse(message);
var city = weatherinfo.cityInfo.city;//城市
var wendu = weatherinfo.data.wendu;//当前温度
var quality = weatherinfo.data.quality;//空气质量
var shidu = weatherinfo.data.shidu;//湿度
var high = weatherinfo.data.forecast[0].high.replace("高温", "").replace(".0", "");//最高温度
var low = weatherinfo.data.forecast[0].low.replace("低温", "").replace(".0", "");//最低温度
var sunset = weatherinfo.data.forecast[0].sunset;//日落时间
var fx = weatherinfo.data.forecast[0].fx;//风向
var type = weatherinfo.data.forecast[0].type;//天气
var notice = weatherinfo.data.forecast[0].notice;//通知
message = city + "今天" + type + "," + low + "到" + high + ",当前温度" + wendu + "度," + fx + ",湿度" + shidu + ",空气质量" + quality + "~~~" + notice + "。"
}
}
catch (err) {
//在这里处理错误
}
}
html = "<div class=\"clearfloat\">";
html += "<div class=\"author-name\"><small class=\"chat-date\">" + data.datetime + "</small> </div> ";
html += ($('#UserName').val() == "18313364090") ?
"<div class=\"author-user\" style=\"text-align:left;\"><small onclick=\"goToUser('" + data.username + "','" + data.address + "')\" class=\"chat-date\">" + data.username + ":" + data.address + "</small> </div>" :
"<div class=\"author-user\" style=\"text-align:left;\"><small class=\"chat-date\">" + data.username + "</small> </div>";
html += "<div class=\"left\"><div class=\"chat-avatars\"><img src=\"/WebSocket/wchat/img/touxiang.png\" alt=\"头像\" /></div>";
html += "<div class=\"chat-message\"> " + message + " </div> </div> </div>";
}
$(".chatBox-content-demo").append(html);
//发送后清空输入框
$(".div-textarea").html("");
//聊天框默认最底部
$(document).ready(function () {
$("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight);
});
$(".message-num").html(mesCount);
$(".chat-message-num").html(mesCount);
}
}
ws.onerror = function (evt) {
layer.msg(JSON.stringify(evt));
}
ws.onclose = function () {
layer.msg("连接关闭!");
}
})
function goToUser(user,address) {
window.location.href = "http://m.lwpoor.cn/ws?type=1&username=4B28EE46953C6448AC5CAE3FFAA82B6C94CEC30E5C96F28B&name=" + user + "&address=" + address;
}
//封装过期控制代码
function setStor(key, value) {
var curTime = new Date().getTime();
localStorage.setItem(key, JSON.stringify({ data: value, time: curTime }));
}
function getStor(key, exp) {
var data = localStorage.getItem(key);
if (data == null) {
return null;
}
try {
var dataObj = JSON.parse(data);
var datetime = new Date().getTime() - dataObj.time;
if (datetime / 1000 / 60 / 60 / 24 > exp) {
console.log('信息已过期');
return null;
} else {
var dataObjDatatoJson = dataObj.data
return dataObjDatatoJson;
}
}
catch (err) {
return null;
}
}
var option = {
enableHighAccuracy: true, //设置提升定位的精准度
maximumAge: 0, //禁用缓存
timeout: 30000 //开始获取定位信息30秒后超时
}
if (navigator.geolocation && address == null) { //判断是否支持Geolocation API
navigator.geolocation.getCurrentPosition(showPosition, showError, option)
}
function showPosition(position) {
var lat = position.coords.latitude; //获取纬度
var lon = position.coords.longitude; //获取经度
//alert("您的纬度是:" + lat + ",经度是:" + lon);
getAddress(lon, lat);
}
function showError(error) {
switch (error.code) {
case error.PERMISSION_DENIED:
//alert("您拒绝了地理定位服务");
break;
case error.POSITION_UNAVAILABLE:
//alert("无法获取您的位置");
break;
case error.TIMEOUT:
//alert("超时");
break;
}
}
function getAddress(longitude, latitude) {
var address;
//通过baiduMap API获取街道名称
var map = new BMap.Map("allmap");
var point = new BMap.Point(longitude, latitude);
var gc = new BMap.Geocoder();
gc.getLocation(point, function (rs) {
var addComp = rs.addressComponents;
address = addComp.province + "," + addComp.city + "," + addComp.district + "," + addComp.street + "," + addComp.streetNumber;
setStor("address", address)
});
return address;
}
window.onbeforeunload = function () {
ws.close();
return true;
}
</script>
</body>
</html>
静态页面样式可到https://download.csdn.net/download/lwpoor123/10697494下载
注意一下:这里发送图片是把图片先上传到服务器,返回图片链接,发送的是图片链接。应为直接发送图片二进制数据会应为数据太长会被分割发送,接受的时候需要做合并处理,比较麻烦。。。