Laravel事件廣播

依賴 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 代碼的客戶端頁面,等待被廣播

觸發我們的後臺廣播事件(執行相應的控制器代碼)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章