0
user-people-family-house-home

【Laravel】利用websocket製作聊天室

本篇介紹如何在 Laravel 框架中,利用Websocket製作一個聊天室。思考一下流程登入→列表&rarr...

Posted by Roy on 2023-11-12 16:59:58 Views

本篇介紹如何在 Laravel 框架中,利用Websocket製作一個聊天室。

思考一下流程

登入→列表→加入聊天室→聊天室→傳送接收訊息(socket)

再來規劃一下大致需要Tables

users(會員)

rooms(聊天室)

user_room(會員跟聊天室的關聯)

messages(聊天訊息)

這裡範例是利用主機當socket

不想設定主機參數可以使用pusher

# 新增Project
laravel new {project}

修改env 

# .env
BROADCAST_DRIVER=pusher PUSHER_APP_ID=chat_room PUSHER_APP_KEY=chatchatchat PUSHER_APP_SECRET=
chatchatchatchatchatchat

修改bootstarp.js

# /resources/js/bootstarp.js
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
    broadcaster: 'pusher',
    encrypted: false,
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    wsHost: window.location.hostname,
    wsPort: 6001,
    forceTLS: false,
    disableStats: true
});

安裝套件

# 會員套件&啟用
npm install composer require laravel/jetstream php artisan jetstream:install livewire npm run dev
# socket套件
composer install
composer require pusher/pusher-php-server ^4.1
npm install --save laravel-echo pusher-js 
composer require beyondcode/laravel-websockets php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations" php artisan migrate php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

資料庫規劃

users

users

rooms

rooms

user_room

user_room

messages

messages

再來規劃broadcast的channel

至少在聊天室的時候要能及時推播訊息(根據room_id)

(以下為部分代碼)

app\Http\Controllers\MessageController


namespace App\Http\Controllers;

use App\Models\Room;
use App\Models\RoomJoin;
use App\Models\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Events\RoomMessageChannelEvent;
use Carbon\Carbon;

class MessageController extends Controller
{
/**
* @var Room
*/
public $model;

/**
* @var RoomJoin
*/
public $join;

/**
* @var Message
*/
public $message;

/**
* RoomController constructor.
*
* @param Room $room
* @param RoomJoin $join
* @param Message $message
*/
public function __construct(Room $room, RoomJoin $join, Message $message)
{
$this->model = $room;
$this->join = $join;
$this->message = $message;
}

/**
* @param \Illuminate\Http\Request $request
* @param $id
*
* @Author: Roy
* @DateTime: 2021/10/23 下午 12:15
*/
public function store(Request $request, $id)
{
if ($this->checkRoomAndUser($id) === false) {
return response()->json([
'status' => false,
'message' => '房間狀態有誤',
'redirect_uri' => route('room.chat', ['id' => $id]),
]);
}
$this->message->create(
[
'user_id' => Auth::user()->id,
'room_id' => $id,
'date' => Carbon::now()->toDateString(),
'content' => $request->get('content'),
]
);
broadcast((new RoomMessageChannelEvent(['user' => Auth::user(), 'content' => $request->get('content')], $id)));
return response()->json([
'status' => true,
'message' => null,
]);
}
}

app\event\RoomMessageChannelEvent


namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;
use Carbon\Carbon;

/**
* Class RoomMessageChannelEvent
*
* @package App\Events\Rooms
* @Author: Roy
* @DateTime: 2021/10/21 下午 02:34
*/
class RoomMessageChannelEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public $message;
public $room_id;

/**
* RoomMessage constructor.
*
* @param $message
* @param $room_id
*
* @Author: Roy
* @DateTime: 2021/10/21 上午 11:54
*/
public function __construct($message, $room_id)
{
$this->room_id = $room_id;
$this->message = (object) [
'user' => (object) [
'id' => Arr::get($message, 'user.id'),
'name' => Arr::get($message, 'user.name'),
'image' => sprintf("https://ui-avatars.com/api/?name=%s&color=7F9CF5&background=EBF4FF",
Arr::get($message, 'user.name')),
],
'content' => Arr::get($message, 'content'),
'time' => Carbon::now()->format('H:i'),
];
}

/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel(sprintf("chat.%s", $this->room_id));
}
}

javescript 使用laravel.echo,jquery,mustache

啟動websocket(預設port:6001)

# 預設port:6001
php artisan websockets:serve
//
php artisan websockets:serve --port=6001

範例畫面

範例

github範本 :

 https://github.com/cc711612/chat_room

範本 :

 https://chat.usongrat.tw

參考文獻:

https://beyondco.de/docs/laravel-websockets/getting-started/introduction

https://learnku.com/docs/laravel/8.x/broadcasting/9388#presence-channels

View Comments