温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Laravel事件广播

发布时间:2020-07-01 19:14:43 来源:网络 阅读:750 作者:Leisure_Xu 栏目:开发技术

依赖 laravel(predis)、 redis、 nodejs(ioredis,socket.io) 

1、修改config\app.php

   providers数组   添加    'Illuminate\Broadcasting\BroadcastServiceProvider',

2、修改广播驱动方式为 config\broadcasting.php

   'default' => env('BROADCAST_DRIVER', 'redis'), 改为redis驱动

   使用redis作为php和js的通信方式。

3、配置config\database.php

   配置redis服务连接参数

定义一个被广播的事件

<?phpnamespace App\Events;use App\Events\Event;use Illuminate\Queue\SerializesModels;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;use Illuminate\Support\Facades\Session;class MessageBroadcastEvent extends Event implements ShouldBroadcast{    use SerializesModels;    public $users;    public $message = array();    protected $channel;    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($users, $message, $channel)
    {
        $this->users = $users;

        $this->message = array(            'id'      => $message['id'], 
            'title'   => $message['title'], 
            'content' => $message['content'], 
            'url'     => $message['url'], 
            'time'    => date('m-d H:i:s', strtotime($message['created_at']))
            );

        $this->channel = $channel;
    }    /**
     * Get the channels the event should be broadcast on.
     * 广播到哪个频道
     * @return array
     */
    public function broadcastOn()
    {        return [$this->channel];
    }
}

默认情况下,Event中的所有public属性都会被序列化后广播。上面的例子中就是$users, $message 两个属性。也可以

使用broadcastWith这个方法,明确的指出要广播什么数据。例如:

public function broadcastWith(){
    return ['message ' => $this->message ];
}

Redis和Websocket服务器

依赖的就是redis的sub/pub功能

启动一个node websocket服务器来和client通信,我们使用socket.io

node 服务端代码 保存为 index.js 放在node服务目录

var app = require('http').createServer(handler);var io = require('socket.io')(app);var Redis = require('ioredis');var redis = new Redis('6379', '192.168.10.10'); //连接redis服务器//监听客户端端口 这里是 6001app.listen(6001, function() {    console.log('Server is running!');
});function handler(req, res) {
    res.writeHead(200);
    res.end('');
}

io.on('connection', function(socket) {    console.log('connected');
});

redis.psubscribe('*', function(err, count) {    console.log(count);
});

redis.on('pmessage', function(subscribed, channel, message) {    console.log(subscribed);    console.log(channel);    console.log(message);

    //发送到客户端的数据
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

客户端代码,只要客户端需要被广播的页面正确引用 node socket.io 模块客户端js文件(自行将这个客户端模块文件放到项目public目录)

<script src="js/socket.io/node_modules/socket.io-client/socket.io.js"></script>//客户端也使用socket.io,测试代码:控制台打印输出

//连接socket服务器
var socket = io('http://localhost:6001');
socket.on('connection', function (data) {
    console.log(data);
});

//收听的频道
socket.on('channel-{{ Session::get('shop')->id }}:App\\Events\\MessageBroadcastEvent', function(data) {
    //控制台输出广播消息
    console.log(message);
    
    //这里可以根据收到的消息,做一些改变页面结构的工作……
});

//可以收听多个频道
socket.on('channel-system:App\\Events\\MessageBroadcastEvent', function(data){
    console.log(data);

    //这里可以根据收到的消息,做一些改变页面结构的工作……
});

//控制台输出连接信息
console.log(socket);

项目中触发事件

在控制器或者在路由匿名函数中都可以直接调用广播事件

1、控制器中直接调用

//发送给哪些用户 id 。 这里定义消息接收用户,是在前台用于检测登陆用户是否在这个数组中,存在则做出相应的即时提醒。//注意:其实广播消息都会被发送到对应的频道的。$users = array(1, 2);//这里可以保存发送消息到 messages 表$message = new Message();
$message->title           = '您的店铺有一条新销售单';
$message->content         = '您的店铺有一条新销售单,单号1000000';
$message->message_type_id = 1;
$message->status          = 0;
$message->url             = 'http://www.xxx.com';
$message->save();//保存发送用户 到 user_message 表$userMessage = array();
$time    = date("Y-m-d H:i:s");foreach ($users as $user) { 
    $tmp = array(
        'created_at' =>$time,
        'updated_at' =>$time,
        'user_id'    =>$user,
        'message_id' =>$message->id, 
        'read'       =>0
    );
    $userMessage[] = $tmp;
}
UserMessage::insert($userMessage);//广播的频道//我们以店铺id来标识频道,这样前端用户页面也根据店铺id标识来收听自己店铺频道,就能做到店铺广播消息消息只能广播到本店铺用户$channel = 'channel-' . Session::get('shop')->id; 
//$channel = 'channel-system'; //其他频道//$response = event(new MessageBroadcastEvent($users, $message, $channel));Event::fire(new MessageBroadcastEvent($users, $message, $channel)); //这两种方式都可以触发事件

2、路由中直接调用

//示例代码Route::get('/event', function(){
    Event::fire(new \App\Events\SomeEvent(3));
    return "hello world";
});

使用:

必须开启 node websocket 服务端。我在本机windows下C盘安装node,服务端代码就放在这个目录下,进入cmd

终端,执行命令,node index.js 启动服务端。

打开包含有 socket.io 代码的客户端页面,等待被广播

触发我们的后台广播事件(执行相应的控制器代码)


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI