下载laravel
composer create-project –prefer-dist laravel/laravel laravel_worker “5.8.*”
下载gatewayworker
www.workerman.net/download/Ga…
将下载下来的项目放到该路径下
下载gatewayclient
composer require workerman/gatewayclient
复制代码
cnpm install
cnpm install
复制代码
监听vue文件变化
npm run watch
复制代码
可能会出现下面的错误
此时需要将node_modules目录删除
rm -rf node_modules
复制代码
运行
npm install vue-template-compiler --save-dev --production=false
cnpm install
npm run watch
复制代码
数据库配置
创建数据库
配置.env
vim .env
#修改下面的值
DB_DATABASE=laravel_worker
DB_USERNAME=root
DB_PASSWORD=root
复制代码
数据表迁移
php artisan migrate
复制代码
用户
执行
php artisan make:auth
复制代码
新增用户
新增三个用户aaaa bbbb cccc
浏览器输入地址:http://192.168.240.131:84/register
laravel_worker\app\User.php 新增下面代码
/**
* 用户头像
* @return string
*/
public function avatar()
{
return 'https://source.unsplash.com/user/erondu/50x50';
}
复制代码
新建信息表
php artisan make:model Message -m
复制代码
laravel_worker\database\migrations\2021_06_08_081347_create_messages_table.php 新增下面代码
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('room_id')->nullable();
$table->text('content');
$table->timestamps();
});
}
复制代码
执行迁移命令
php artisan migrate
复制代码
用户进入聊天室
ChatRoom聊天界面
laravel_worker\resources\js\components目录下,新增ChatRoom.vue文件,代码如下
<template>
<div class="container">
<a href="https://juejin.cn/post/?room_id=1" class="btn btn-danger">音乐</a>
<a href="https://juejin.cn/post/?room_id=2" class="btn btn-primary">游戏</a>
<hr class="divider">
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">聊天室</div>
<div class="panel-body">
<div class="messages">
<div class="media">
<div class="media-left">
<a href="">
<img class="media-object img-circle">
</a>
</div>
<div class="media-body">
<p class="time">time</p>
<h4 class="media-heading">name</h4>
: content
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">聊天室在线用户</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">
<img class="img-circle">
user.name
</li>
</ul>
</div>
</div>
</div>
</div>
<hr class="divider">
<form @submit.prevent="onSubmit">
<div class="form-group">
<label for="user_id">发送给</label>
<select class="form-control" id="user_id">
<option value="">所有人</option>
<option>user.name</option>
</select>
</div>
<div class="form-group">
<label for="content">内容(回车可快速发送)</label>
<textarea class="form-control" rows="3" id="content"></textarea>
</div>
<button type="submit" class="btn btn-dark">提交</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {}
},
created: function () {
},
methods: {}
}
</script>
<style scoped>
.panel-body {
height: 480px;
overflow: auto;
}
.media-object.img-circle {
width: 64px;
height: 64px;
}
.img-circle {
width: 48px;
height: 48px;
}
.time {
float: right;
}
.media {
margin-top: 24px;
}
</style>
复制代码
D:\phpstudy\WWW\laravel_worker\resources\js\app.js 新增代码
// 注册组件
Vue.component('chat-room', require('./components/ChatRoom.vue').default);
复制代码
D:\phpstudy\WWW\laravel_worker\resources\views\home.blade.php 代码
@extends('layouts.app')
@section('content')
<chat-room></chat-room>
@endsection
复制代码
打开浏览器
http://192.168.240.131:84/home
修改socket协议
D:\phpstudy\WWW\laravel_worker\socket\GatewayWorker\Applications\YourApp\start_gateway.php 替换代码
$gateway = new Gateway("websocket://0.0.0.0:8282");
复制代码
修改Events.php
D:\phpstudy\WWW\laravel_worker\socket\GatewayWorker\Applications\YourApp\Events.php
public static function onConnect($client_id)
{
Gateway::sendToClient($client_id, json_encode(array(
'type' => 'init',
'client_id' => $client_id
)));
}
public static function onMessage($client_id, $message)
{
}
复制代码
启动gatewayworker
cd socket/GatewayWorker
php start.php start
复制代码
客户端建立websocket连接
<script>
let ws = new WebSocket('ws://192.168.240.131:8282')
export default {
data() {
return {}
},
created: function () {
ws.onmessage = (e) => {
let data = JSON.parse(e.data)
console.log(data)
}
},
methods: {}
}
</script>
复制代码
浏览器控制台调试输出
{type: "init", client_id: "7f0000010b5500000002"}
复制代码
进入聊天室
前端代码
<template>
<div class="container">
<a href="https://juejin.cn/post/?room_id=1" class="btn btn-danger">音乐</a>
<a href="https://juejin.cn/post/?room_id=2" class="btn btn-primary">游戏</a>
<hr class="divider">
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">聊天室</div>
<div class="panel-body">
<div class="messages">
<div class="media" v-for="message in messages">
<div class="media-left">
<a href="">
<img class="media-object img-circle" :src="https://juejin.cn/post/message.avatar">
</a>
</div>
<div class="media-body">
<p class="time">{{message.time}}</p>
<h4 class="media-heading">{{message.name}}</h4>
: {{message.content}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">聊天室在线用户</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">
<img class="img-circle">
user.name
</li>
</ul>
</div>
</div>
</div>
</div>
<hr class="divider">
<form @submit.prevent="onSubmit">
<div class="form-group">
<label for="user_id">发送给</label>
<select class="form-control" id="user_id">
<option value="">所有人</option>
<option>user.name</option>
</select>
</div>
<div class="form-group">
<label for="content">内容(回车可快速发送)</label>
<textarea class="form-control" rows="3" id="content"></textarea>
</div>
<button type="submit" class="btn btn-dark">提交</button>
</form>
</div>
</template>
<script>
let ws = new WebSocket('ws://192.168.240.131:8282')
export default {
data() {
return {
'messages': []
}
},
created: function () {
ws.onmessage = (e) => {
let data = JSON.parse(e.data)
console.log(data)
//如果没有类型,就为空
let type = data.type || ''
switch (type) {
case "init":
axios.post('/init', {client_id: data.client_id})
break;
case "say":
this.messages.push(data.data)
break;
default:
console.log(data)
}
}
},
methods: {}
}
</script>
<style scoped>
.panel-body {
height: 480px;
overflow: auto;
}
.media-object.img-circle {
width: 64px;
height: 64px;
}
.img-circle {
width: 48px;
height: 48px;
}
.time {
float: right;
}
.media {
margin-top: 24px;
}
</style>
复制代码
后端代码
D:\phpstudy\WWW\laravel_worker\routes\web.php 新增代码
Route::post('/init', 'HomeController@init');
复制代码
D:\phpstudy\WWW\laravel_worker\app\Http\Controllers\HomeController.php
<?php
namespace App\Http\Controllers;
use GatewayClient\Gateway;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
Gateway::$registerAddress = '127.0.0.1:1238';
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
}
public function init(Request $request)
{
//绑定用户
$this->bind($request);
//进入聊天室
$this->login();
}
public function login()
{
$data = [
'type' => 'say',
'data' => [
'avatar' => Auth::user()->avatar(),
'name' => Auth::user()->name,
'content' => '进入了聊天室',
'time' => date('Y-m-d H:i:s')
]
];
Gateway::sendToAll(json_encode($data));
}
public function bind($request)
{
$id = Auth::id();
$client_id = $request->client_id;
Gateway::bindUid($client_id, $id);
}
}
复制代码
发送聊天信息
前端代码
<template>
<div class="container">
<a href="https://juejin.cn/post/?room_id=1" class="btn btn-danger">音乐</a>
<a href="https://juejin.cn/post/?room_id=2" class="btn btn-primary">游戏</a>
<hr class="divider">
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">聊天室</div>
<div class="panel-body">
<div class="messages">
<div class="media" v-for="message in messages">
<div class="media-left">
<a href="">
<img class="media-object img-circle" :src="https://juejin.cn/post/message.avatar">
</a>
</div>
<div class="media-body">
<p class="time">{{message.time}}</p>
<h4 class="media-heading">{{message.name}}</h4>
: {{message.content}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">聊天室在线用户</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">
<img class="img-circle">
user.name
</li>
</ul>
</div>
</div>
</div>
</div>
<hr class="divider">
<form @submit.prevent="onSubmit">
<div class="form-group">
<label for="user_id">发送给</label>
<select class="form-control" id="user_id">
<option value="">所有人</option>
<option>user.name</option>
</select>
</div>
<div class="form-group">
<label for="content">内容(回车可快速发送)</label>
<textarea class="form-control" rows="3" id="content" v-model="content"></textarea>
</div>
<button type="submit" class="btn btn-dark">提交</button>
</form>
</div>
</template>
<script>
let ws = new WebSocket('ws://192.168.240.131:8282')
export default {
data() {
return {
'messages': [],
'content': '',
}
},
created: function () {
ws.onmessage = (e) => {
let data = JSON.parse(e.data)
console.log(data)
//如果没有类型,就为空
let type = data.type || ''
switch (type) {
case "init":
axios.post('/init', {client_id: data.client_id})
break;
case "say":
this.messages.push(data.data)
this.$nextTick(function () {
$('.panel-body').animate({scrollTop: $('.messages').height()})
})
break;
default:
console.log(data)
}
}
},
methods: {
onSubmit() {
axios.post('/say', {content: this.content})
this.content = ''
},
}
}
</script>
<style scoped>
.panel-body {
height: 480px;
overflow: auto;
}
.media-object.img-circle {
width: 64px;
height: 64px;
}
.img-circle {
width: 48px;
height: 48px;
}
.time {
float: right;
}
.media {
margin-top: 24px;
}
</style>
复制代码
后端代码
D:\phpstudy\WWW\laravel_worker\routes\web.php
Route::post('/say', 'HomeController@say');
复制代码
D:\phpstudy\WWW\laravel_worker\app\Message.php
protected $guarded = [];
复制代码
测试
打开两个浏览器
聊天历史记录
前端代码
只需要在switch中新增下面代码
case "history":
this.messages = data.data
break;
复制代码
后端代码
D:\phpstudy\WWW\laravel_worker\app\Http\Controllers\HomeController.php
public function init(Request $request)
{
//绑定用户
$this->bind($request);
//历史记录
$this->history();
//进入聊天室
$this->login();
}
/**
* 最新的5条聊天历史记录
*/
public function history()
{
$data = ['type' => 'history'];
$messages = Message::with('user')->orderBy('id', 'desc')->limit(5)->get();
$data['data'] = $messages->map(function ($item, $key) {
return [
'avatar' => $item->user->avatar(),
'name' => $item->user->name,
'content' => $item->content,
'time' => $item->created_at->format('Y-m-d H:i:s')
];
});
$data['data'] = array_reverse(json_decode($data['data'], true));
Gateway::sendToUid(Auth::id(), json_encode($data));
}
复制代码
D:\phpstudy\WWW\laravel_worker\app\Message.php
新增用户关联
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
//
protected $guarded = [];
public function user()
{
return $this->belongsTo('App\User');
}
}
复制代码
D:\phpstudy\WWW\laravel_worker\app\User.php
新增信息关联
public function messages()
{
return $this->hasMany('App\Message');
}
复制代码
在线用户列表
前端代码
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">聊天室在线用户</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item" v-for="user in users">
<img class="img-circle" :src="https://juejin.cn/post/user.avatar">
{{user.name}}
</li>
</ul>
</div>
</div>
</div>
复制代码
<form @submit.prevent="onSubmit">
<div class="form-group">
<label for="user_id">发送给</label>
<select class="form-control" id="user_id">
<option value="">所有人</option>
<option :value="user.id" v-for="user in users">{{user.name}}</option>
</select>
</div>
<div class="form-group">
<label for="content">内容(回车可快速发送)</label>
<textarea class="form-control" rows="3" id="content" v-model="content"></textarea>
</div>
<button type="submit" class="btn btn-dark">提交</button>
</form>
复制代码
data() {
return {
'messages': [],
'content': '',
'users': []
}
},
case "users":
this.users = data.data
break;
复制代码
后端代码
public function init(Request $request)
{
//绑定用户
$this->bind($request);
//历史记录
$this->history();
//获取在线用户列表
$this->users();
//进入聊天室
$this->login();
}
public function users()
{
$data = [
'type' => 'users',
'data' => Gateway::getAllClientSessions()
];
Gateway::sendToAll(json_encode($data));
}
public function bind($request)
{
$id = Auth::id();
$client_id = $request->client_id;
Gateway::bindUid($client_id, $id);
Gateway::setSession($client_id, [
'id' => $id,
'avatar' => Auth::user()->avatar(),
'name' => Auth::user()->name,
]);
}
复制代码
私聊
前端代码
<form @submit.prevent="onSubmit">
<div class="form-group">
<label for="user_id">发送给</label>
<select class="form-control" id="user_id" v-model="user_id">
<option value="">所有人</option>
<option :value="user.id" v-for="user in users">{{user.name}}</option>
</select>
</div>
<div class="form-group">
<label for="content">内容(回车可快速发送)</label>
<textarea class="form-control" rows="3" id="content" v-model="content"></textarea>
</div>
<button type="submit" class="btn btn-dark">提交</button>
</form>
复制代码
data() {
return {
'messages': [],
'content': '',
'users': [],
'user_id': '',
}
},
methods: {
onSubmit() {
axios.post('/say', {content: this.content, user_id: this.user_id})
this.content = ''
},
}
复制代码
后端代码
public function say(Request $request)
{
//所有人
$data = [
'type' => 'say',
'data' => [
'avatar' => Auth::user()->avatar(),
'name' => Auth::user()->name,
'content' => $request->input('content'),
'time' => date('Y-m-d H:i:s')
]
];
//私聊
if ($request->user_id) {
$data['data']['name'] = Auth::user()->name . '对 ' . User::find($request->user_id)->name . '说:';
Gateway::sendToUid(Auth::id(), json_encode($data));
Gateway::sendToUid($request->user_id, json_encode($data));
//私聊信息,只发给对应用户,不存数据库了
return;
}
Gateway::sendToAll(json_encode($data));
//存到数据库
Message::create([
'user_id' => Auth::id(),
'content' => $request->input('content')
]);
}
复制代码
房间
前端代码
<a href="https://juejin.cn/post/?room_id=1" class="btn btn-danger">音乐</a>
<a href="https://juejin.cn/post/?room_id=2" class="btn btn-primary">游戏</a>
复制代码
后端代码
public function index(Request $request)
{
$room_id = $request->room_id ? $request->room_id : '1';
session()->put('room_id', $room_id);
return view('home');
}
public function bind($request)
{
$id = Auth::id();
$client_id = $request->client_id;
Gateway::bindUid($client_id, $id);
Gateway::joinGroup($client_id, session('room_id'));
Gateway::setSession($client_id, [
'id' => $id,
'avatar' => Auth::user()->avatar(),
'name' => Auth::user()->name,
]);
}
public function say(Request $request)
{
//存到数据库
Message::create([
'user_id' => Auth::id(),
'room_id' => session('room_id'),
'content' => $request->input('content')
]);
}
复制代码
//将所有
Gateway::sendToAll(json_encode($data));
复制代码
//改为
Gateway::sendToGroup(session('room_id'), json_encode($data));
复制代码
用户退出
前端代码
case "logout":
this.$delete(this.users, data.client_id)
break;
复制代码
后端代码
D:\phpstudy\WWW\laravel_worker\socket\GatewayWorker\Applications\YourApp\Events.php
改完需要重新启动socket服务
/**
* 当用户断开连接时触发
* @param int $client_id 连接id
*/
public static function onClose($client_id)
{
// 向所有人发送
GateWay::sendToAll(json_encode([
'type' => 'logout',
'client_id' => $client_id
]));
}
复制代码
心跳
前端代码
case "ping":
ws.send('pong');
console.log(data)
break;
复制代码
后端代码
D:\phpstudy\WWW\laravel_worker\socket\GatewayWorker\Applications\YourApp\start_gateway.php
改完需要重新启动socket服务
// 心跳间隔
$gateway->pingInterval = 10;
// 心跳数据
$gateway->pingData = '{"type":"ping"}';
复制代码