TP5与基于workerman的GatewayWorker框架实战在线客服教程【即时通讯】
一、前期准备 环境搭建
GatewayWorker手册页面直接下载demo(根据自己使用的环境下载)
觉得我的不标准的话可以去哔哩哔哩上看看《码农技术社区》这位大佬的视频挺详细的我就是跟着视频学会的
下载出来是长这个样子的
运行的话直接双击start_for_win.bat就可以了,停止的话ctrl+c,再打y回车就可以了,如图:
启动的样子
停止的样子
首先把GatewayWorker复制到tp5的vendor里面,如图:
打开vendor/GatewayWorker/Applications/YourApp/start_gateway.php,把tcp协议改成Websocket
二、长连接实现群发,初次体验
然后随便找个模板,随便发个消息试试,如图:
实例代码:
var ws = new WebSocket("ws://127.0.0.1:8282");ws.onmessage = function(e){ console.log(e)}$(".send-btn").click(function(){ var content = $(".send-input").val(); ws.send(content) $(".send-input").val("");})
三、群发及客户端和socket服务器保持长连接双向消息推送
然后再稍微改动一下就可以得到一个有点小问题的聊天(也不能说问题因为是向所有人发送信息所以回自己哪里也会多一条信息)
代码改动部分(改完Events.php一定要重启start_for_win.bat,否则不生效)
public static function onMessage($client_id, $message){ $message_data = json_decode($message,true); if(!$message_data){ return; } switch($message_data['type']){ case 'say'; $data = [ 'type' => 'text', 'id' => $client_id, 'data' => $message_data['data'], ]; Gateway::sendToAll(json_encode($data)); return; } // 向所有人发送 // Gateway::sendToAll("$client_id said $message\r\n");}
页面js部分
var ws = new WebSocket("ws://127.0.0.1:8282");ws.onmessage = function(e){ // eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。 // console.log(e) var msg = eval("("+e.data+")"); // console.log(msg) switch(msg.type){ case 'text': var html = '' +'' +''+msg.data+'' +'' $(".chat-content").append(html); return; }}$(".send-btn").click(function(){ var content = $(".send-input").val(); // var res = '{"data":"'+content+'","type":"say"}'; var res = { 'data':content, 'type':'say', }; //JSON.stringify json转字符串 ws.send(JSON.stringify(res)) var html = '' +''+content+'' +'' +''; $(".chat-content").append(html); $(".send-input").val("");})
四、长连接绑定客户id实现一对一聊天
消息通过用户id来发送信息,效果如图:
这里1给2发送了一个你好啊,2给1发了个我很好
而3哪里啥都没有
首先呢获取你的id跟对方的id发给页面
public function index(){ $input = input('get.'); //fromid个人id toid 对方id $this->assign(['fromid'=>$input['fromid'],'toid'=>$input['toid']]); return $this->fetch();}
并在前台接受并传给终端告诉他我是谁又要发给谁
var fromid = {$fromid};//个人idvar toid = {$toid};//他人id// console.log(fromid)// console.log(toid)var ws = new WebSocket("ws://127.0.0.1:8282");ws.onmessage = function(e){ // eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。 // console.log(e) var msg = eval("("+e.data+")"); // console.log(msg) switch(msg.type){ case 'init': var bind = { 'type':'bind', 'fromid':fromid, }; //JSON.stringify json转字符串 ws.send(JSON.stringify(bind)) return case 'text': //判断是否是当前聊天对象 是的话才会展示 if(toid == msg.toid){ var html = '' +'' +''+msg.data+'' +'' $(".chat-content").append(html); } return; }}$(".send-btn").click(function(){ var content = $(".send-input").val(); // var res = '{"data":"'+content+'","type":"say"}'; var res = { 'data':content, 'type':'say', 'fromid':fromid, 'toid':toid, }; //JSON.stringify json转字符串 ws.send(JSON.stringify(res)) var html = '' +''+content+'' +'' +''; $(".chat-content").append(html); $(".send-input").val("");})
然后Events.php里面进行获取并绑定,还有发送信息绑定对方id,其他根据自己要求来 (改完Events.php一定要重启start_for_win.bat,否则不生效)
public static function onConnect($client_id) { // 向当前client_id发送数据 // Gateway::sendToClient($client_id, "Hello $client_id\r\n"); // 向所有人发送 // Gateway::sendToAll("$client_id login\r\n"); //向客户端client_id发送$send_data数据。如果client_id对应的客户端不存在或者不在线则自动丢弃发送数据 Gateway::sendToClient($client_id,json_encode([ 'type'=>'init', 'client_id'=>$client_id, ])); } public static function onMessage($client_id, $message) { $message_data = json_decode($message,true); if(!$message_data){ return; } switch($message_data['type']){ case 'bind': //为啥这个绑定不在一开始连接时触发的时候绑定,因为是一开始才会触发的绑定,给别人发的话还得刷新才行,所以就在发消息的时候绑定id //将client_id与uid绑定,以便通过Gateway::sendToUid($uid)发送数据,通过Gateway::isUidOnline($uid)用户是否在线。 //uid解释:这里uid泛指用户id或者设备id,用来唯一确定一个客户端用户或者设备。 Gateway::bindUid($client_id,$message_data['fromid']); return; case 'say'; $data = [ 'type' => 'text', 'data' => $message_data['data'], 'fromid'=>$message_data['fromid'], 'toid'=>$message_data['toid'], 'time'=>time(), ]; // 向uid绑定的所有在线client_id发送数据。 // 注意:默认uid与client_id是一对多的关系,如果当前uid下绑定了多个client_id,则多个client_id对应的客户端都会收到消息,这类似于PC QQ和手机QQ同时在线接收消息。 Gateway::sendToUid($message_data['toid'],json_encode($data)); // 向所有人发送 // Gateway::sendToAll(json_encode($data)); return; } // 向所有人发送 // Gateway::sendToAll("$client_id said $message\r\n"); }
五、getwayworker长连接下的普通文本消息之聊天记录持久化
前台代码:
doctype html><html><head> <meta charset="utf-8"> <meta name="format-detection" content="telephone=no" /> <title>沟通中title> <link rel="stylesheet" type="text/css" href="__STATIC__/Gatewayworker/css/themes.css?v=2017129"> <link rel="stylesheet" type="text/css" href="__STATIC__/Gatewayworker/css/h5app.css"> <link rel="stylesheet" type="text/css" href="__STATIC__/Gatewayworker/fonts/iconfont.css?v=2016070717"> <script class="lazy" data-src="__STATIC__/Gatewayworker/js/jquery.min.js">script> <script class="lazy" data-src="__STATIC__/Gatewayworker/js/dist/flexible/flexible_css.debug.js">script> <script class="lazy" data-src="__STATIC__/Gatewayworker/js/dist/flexible/flexible.debug.js">script>head><body ontouchstart><div class='fui-page-group'><div class='fui-page chatDetail-page'> <div class="chat-header flex"> <i class="icon icon-toleft t-48">i> <span class="shop-titlte t-30">{$to.name}span> <span class="shop-online t-26">span> <span class="into-shop">进店span> div> <div class="fui-content navbar" style="padding:1.2rem 0 1.35rem 0;"> <div class="chat-content"> <p style="display: none;text-align: center;padding-top: 0.5rem" id="more"><a>加载更多a>p> {foreach $chat_record as $k => $v} <p class="chat-time"><span class="time">{$v.add_time}span>p> {if $from.id == $v.fromid} <div class="chat-text section-left flex"> <span class="char-img" style="background-image: url({$to.toux})">span> <span class="text"><i class="icon icon-sanjiao4 t-32">i>{$v.content}span> div> {else} <div class="chat-text section-right flex"> <span class="text"><i class="icon icon-sanjiao3 t-32">i>{$v.content}span> <span class="char-img" style="background-image: url({$from.toux})">span> div> {/if} {/foreach} div> div> <div class="fix-send flex footer-bar"> <i class="icon icon-emoji1 t-50">i> <input class="send-input t-28" maxlength="200"> <i class="icon icon-add t-50" style="color: #888;">i> <span class="send-btn">发送span> div>div>div><script> var fromid = {$from.id};//发送者id var toid = {$to.id};//接收者id // console.log(fromid) // console.log(toid) //连接服务器 var ws = new WebSocket("ws://127.0.0.1:8282"); //调用的方法均在GatewayWorker/Applications/Events.php里面的生命周期函数里面规定 //作用与Worker::$onMessage回调相同,区别是只针对当前连接有效,也就是可以针对某个连接的设置onMessage回调。 ws.onmessage = function(e){ // eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。 // console.log(e) //获取他人发送来的信息 var msg = eval("("+e.data+")"); switch(msg.type){ case 'init': //绑定id var bind = { 'type':'bind', 'fromid':fromid, }; //JSON.stringify json转字符串 send执行异步连接操作。此方法会立刻返回。 向客户端发送数据 ws.send(JSON.stringify(bind)) //判断是否在线 发过去 //初次加载判断是否在线 var online = { 'type':'online', 'toid':toid, 'fromid':fromid, }; ws.send(JSON.stringify(online)) //聊天内容定位到最下面 $('.chat-content').scrollTop(3000); return //接受消息 case 'text': //用当前他人id跟他人发送过的fromid来对比 判断是否是当前聊天对象 是的话才会展示 if(toid == msg.fromid){ var html = '' // +'' +'' +''+msg.data+'' +'' $(".chat-content").append(html); //聊天内容定位到最下面 $('.chat-content').scrollTop(3000); } return; //保存消息 从而消息持久化 case 'save': //发送消息更新在线状态 if(msg.isread == 2){ $('.shop-online').text('在线'); }else{ $('.shop-online').text('不在线'); } save_message(msg);//调用 保存聊天数据 方法 //聊天内容定位到最下面 $('.chat-content').scrollTop(3000); return; //判断是否在线 回调 case 'online': //初次加载判断是否在线 if(msg.status == 1){ $('.shop-online').text('在线'); }else{ $('.shop-online').text('不在线'); } return; } } //发送信息 $(".send-btn").click(function(){ var content = $(".send-input").val(); // var res = '{"data":"'+content+'","type":"say"}'; var res = { 'data':content, 'type':'say', 'fromid':fromid, 'toid':toid, }; //聊天内容定位到最下面 $('.chat-content').scrollTop(3000); //JSON.stringify json转字符串 ws.send(JSON.stringify(res)) var html = '' +''+content+'' // +'' +'' +''; $(".chat-content").append(html); $(".send-input").val(""); }) //保存聊天数据 function save_message(data){ $.ajax({ type: "POST", url: "{:url('Gatewayworker/save_message')}", dataType: "json", data:{data}, success: function(res) {} }) }script>body>html>
后台代码:
namespace app\index\controller;use think\Db;use think\Controller;class Gatewayworker extends Controller{ //聊天页面 public function index(){ $input = input('get.'); //fromid 发送者id toid 接收者id $from = db('admin')->where('id',$input['fromid'])->field('id,name,toux')->find(); $to = db('admin')->where('id',$input['toid'])->field('id,name,toux')->find(); //聊天记录 (不完美,除了二者的聊天记录别人的只要满足条件的也会显示出来) $chat_record = db('chat_record') ->where(['fromid'=>$input['fromid'],'toid'=>$input['toid']]) ->whereOr(['fromid'=>$input['toid'],'toid'=>$input['fromid']]) ->page(1,10) ->order('chat_record_id') ->select(); // halt($chat_record); foreach($chat_record as $k => $v){ $chat_record[$k]['add_time'] = date('Y-m-d H:i:s',$v['add_time']); } $this->assign(['from'=>$from,'to'=>$to,'chat_record'=>$chat_record]); return $this->fetch(); } //保存聊天数据 public function save_message(){ $input = input('post.data'); $data=[ 'fromid'=>$input['fromid'], 'fromname'=>$this->getname($input['fromid']),//获取发送者name 'toid'=>$input['toid'], 'toname'=>$this->getname($input['toid']),//获取接收者name 'content'=>$input['data'], 'add_time'=>$input['time'], 'isread'=>$input['isread'],//消息是否在线(1在线 2下线) 'type'=>1,//消息类型(1文本消息 2图片 ) ]; db('chat_record')->insert($data); } //获取发送者或接收者name public function getname($id){ $data = db('admin')->where('id',$id)->field('id,name')->find(); return $data['name']; } }
Events.php里面的代码:
//declare(ticks=1);use \GatewayWorker\Lib\Gateway;/修改了这个文件一定要重启,否则不起作用class Events{ public static function onConnect($client_id) { // 向当前client_id发送数据 // Gateway::sendToClient($client_id, "Hello $client_id\r\n"); // 向所有人发送 // Gateway::sendToAll("$client_id login\r\n"); //向客户端client_id发送$send_data数据。如果client_id对应的客户端不存在或者不在线则自动丢弃发送数据 Gateway::sendToClient($client_id,json_encode([ 'type'=>'init', 'client_id'=>$client_id, ])); } public static function onMessage($client_id, $message) { //把前台发送过来的字符串转成数组 $message_data = json_decode($message,true); if(!$message_data){ return; } switch($message_data['type']){ //绑定id case 'bind': //为啥这个绑定不在一开始连接时触发的时候绑定,因为是一开始才会触发的绑定,给别人发的话还得刷新才行,所以就在发消息的时候绑定id //将client_id与uid绑定,以便通过Gateway::sendToUid($uid)发送数据,通过Gateway::isUidOnline($uid)用户是否在线。 //uid解释:这里uid泛指用户id或者设备id,用来唯一确定一个客户端用户或者设备。 Gateway::bindUid($client_id,$message_data['fromid']); return; case 'online': //初次加载 判断接收者是否在线 $status = Gateway::isUidOnline($message_data['toid']); $data=[ 'type'=>'online', 'status'=>$status, ]; // 向uid绑定的所有在线client_id发送数据。 // 注意:默认uid与client_id是一对多的关系,如果当前uid下绑定了多个client_id,则多个client_id对应的客户端都会收到消息,这类似于PC QQ和手机QQ同时在线接收消息。 //给发送者发送过去告诉他接收者是否在线 Gateway::sendToUid($message_data['fromid'],json_encode($data));return; //发送消息 数据保存 case 'say'; $data = [ 'type' => 'text',//文本类型 'data' => $message_data['data'],//发送内容 'fromid'=>$message_data['fromid'],//发送者id 'toid'=>$message_data['toid'],//接收者id 'time'=>time(),//当前时间 ]; //判断接收者是否在线 //发送消息更新在线状态 if(Gateway::isUidOnline($message_data['toid'])){ $data['isread'] = 2;//在线 // 向uid绑定的所有在线client_id发送数据。 // 注意:默认uid与client_id是一对多的关系,如果当前uid下绑定了多个client_id,则多个client_id对应的客户端都会收到消息,这类似于PC QQ和手机QQ同时在线接收消息。 Gateway::sendToUid($message_data['toid'],json_encode($data)); }else{ $data['isread'] = 1;//不在线 } //类型设置为保存 $data['type']='save'; //告诉发送者 保存聊天数据 从来保证数据持久化 (workerman官方建议这里只写发送消息逻辑,所以保存到数据库交给前台ajax来) Gateway::sendToUid($message_data['fromid'],json_encode($data)); // 向uid绑定的所有在线client_id发送数据。 // 注意:默认uid与client_id是一对多的关系,如果当前uid下绑定了多个client_id,则多个client_id对应的客户端都会收到消息,这类似于PC QQ和手机QQ同时在线接收消息。 // Gateway::sendToUid($message_data['toid'],json_encode($data)); // 向所有人发送 // Gateway::sendToAll(json_encode($data)); return; } // 向所有人发送 // Gateway::sendToAll("$client_id said $message\r\n"); } public static function onClose($client_id) { // 向所有人发送 // GateWay::sendToAll("$client_id logout\r\n"); }}
来源地址:https://blog.csdn.net/qq_44678350/article/details/125521558
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341