>PHP 프레임워크 >Laravel >실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현

실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현

不言
不言원래의
2018-07-31 15:48:545420검색

전에 이벤트 방송에 대한 튜토리얼을 작성하겠다고 했는데, 오늘 드디어 이 글을 쓰게 되었습니다. 이번 튜토리얼은 이벤트 방송을 핵심 기술로 하는 Laravel+Pusher+Vue를 기반으로 합니다. 실시간 채팅방 애플리케이션, 더 이상 고민할 필요 없이 구체적인 내용을 살펴보겠습니다.

애플리케이션 초기화

설치 및 구성

먼저 Composer를 통해 새 채팅방 애플리케이션을 설치합니다.

composer create-project laravel/laravel chatroom --prefer-dist

이벤트 방송을 사용하므로 config/app.php에서 방송 서비스 제공자 주석을 해제해야 합니다.

실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현

.env의 BROADCAST_DRIVER 구성 항목을 pusher로 수정:

BROADCAST_DRIVER=pusher

Laravel은 기본적으로 Pusher를 지원하지만 여전히 해당 PHP SDK를 설치해야 합니다.

composer require pusher/pusher-php-server

Pusher 자격 증명 정보 설정

Pusher 공식 웹사이트를 방문하여 사용자 백엔드에 등록 및 로그인하고 새로운 채널 앱을 생성하세요:

실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현

생성이 완료되면 점프 페이지에서 앱 키를 받으실 수 있습니다. 관련 정보:

실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현

해당 필드를 채워 채팅방 애플리케이션의 루트 디렉터리에 있는 .env의 해당 구성 항목이면 충분합니다.

프런트 엔드 리소스 초기화

우리는 Laravel Mix를 사용하여 프런트 엔드 CSS와 JavaScript를 컴파일합니다:

npm install

또한 Laravel은 이벤트를 구독하고 수신할 수 있는 JavaScript 라이브러리 Laravel Echo도 제공합니다:

npm install --save laravel-echo pusher-js

설치 후 완료하려면 Laravel Echo에게 Pusher 를 사용하라고 지시해야 합니다. Laravel은 resources/assets/js/bootstrap.js에 이 구현을 제공했지만 기본적으로 주석 처리되어 있습니다:

import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true
});

사용자 인증 스캐폴딩 코드

로그인한 사용자만 채팅방에 입장할 수 있도록 설정했습니다. 프로세스를 단순화하기 위해 Laravel의 기본 사용자 인증 기능인

php artisan make:auth

위 명령을 사용하면 라우팅이 생성됩니다. 사용자 인증 시스템에 필요한 뷰, 컨트롤러 및 기타 코드. 기능이 적용되기 전에 데이터베이스 마이그레이션 명령을 실행하여 해당 데이터 테이블을 생성하고, .env에서 데이터베이스 관련 구성 항목을 편집하여 데이터베이스가 올바르게 연결될 수 있는지 확인한 후 다음 명령을 실행해야 합니다.

php artisan migrate

이제 다음과 같이 애플리케이션 초기화 준비가 완료되었습니다. 비즈니스 코드 작성을 시작합니다.

비즈니스 코드 구현

메시지 모델

먼저 보낸 메시지에 대한 모델 클래스와 해당 데이터베이스 마이그레이션 파일을 만듭니다.

php artisan make:model Message -m

새로 생성된 앱/메시지 모델 클래스에 다음 코드 줄을 편리한 배치에 추가합니다. 할당:

/**
 * Fields that are mass assignable
 *
 * @var array
 */
protected $fillable = ['message'];

그런 다음 새로 생성된 메시지를 데이터베이스/마이그레이션 디렉터리에 기록합니다. 마이그레이션 파일에 해당하는 up 메서드:

Schema::create('messages', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('user_id')->unsigned();
    $table->text('message');
    $table->timestamps();
});

마지막으로 마이그레이션 명령을 실행하여 데이터 테이블 메시지를 생성합니다.

php artisan migrate

사용자와 마이그레이션 간의 관계 message

는 매우 분명합니다. 사용자와 메시지 사이에는 일대다 관계가 있습니다. User 모델 클래스에 새 연결 메서드를 추가합니다.

/**
 * A user can have many messages
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function messages()
{
    return $this->hasMany(Message::class);
}

다음으로 메시지 모델 클래스에 해당 연결 관계를 정의합니다.

/**
 * A message belong to a user
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function user()
{
    return $this->belongsTo(User::class);
}

컨트롤러 코드

특정 비즈니스 로직을 구현하기 위해 컨트롤러 ChatsController를 만듭니다.

php artisan make:controller ChatsController

새로 생성된 컨트롤러 클래스 app/Http/Controllers/ChatsController를 작성합니다. 코드는 다음과 같습니다.

<?php
namespace App\Http\Controllers;
use Auth;
use App\Message;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ChatsController extends Controller
{
    public function __construct()
    {
        $this->middleware(&#39;auth&#39;);  // 登录用户才能访问
    }
    /**
     * Show chats
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view(&#39;chat&#39;);
    }
    /**
     * Fetch all messages
     *
     * @return Message
     */
    public function fetchMessages()
    {
        return Message::with(&#39;user&#39;)->get();
    }
    /**
     * Persist message to database
     *
     * @param  Request $request
     * @return Response
     */
    public function sendMessage(Request $request)
    {
        $user = Auth::user();
        $message = $user->messages()->create([
            &#39;message&#39; => $request->input(&#39;message&#39;)
        ]);
        return [&#39;status&#39; => &#39;Message Sent!&#39;];
    }
}

컨트롤러는 세 가지 비즈니스 메서드를 제공하며 인덱스는 다음과 같습니다. 채팅방 보기를 표시하는 데 사용되며, fetchMessages 사용자는 모든 메시지를 가져오고, sendMessage는 메시지를 보내는 데 사용됩니다.

응용 프로그램 경로 등록

이에 따라 Routes/web.php에 세 가지 경로를 등록합니다.

Route::get(&#39;/&#39;, &#39;ChatsController@index&#39;);
Route::get(&#39;messages&#39;, &#39;ChatsController@fetchMessages&#39;);
Route::post(&#39;messages&#39;, &#39;ChatsController@sendMessage&#39;);

등록된 경로에서 /home 경로를 제거합니다. 이에 따라 app/Http/Controllers/Auth/LoginController .php를 추가해야 합니다. app/Http/Controllers/Auth/RegisterController.php의 $redirectTo 속성을 조정하여 다음을 수행합니다.

protected $redirectTo = &#39;/&#39;;

채팅방 보기

채팅방 보기 코드의 경우 Bootsnipp 채팅방 코드 조각을 기반으로 약간 조정했습니다. 먼저 resources/views/chat.blade.php를 생성하세요:

@extends(&#39;layouts.app&#39;)
@section(&#39;content&#39;)
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">聊天室</div>
                    <div class="panel-body">
                        <chat-messages :messages="messages"></chat-messages>
                    </div>
                    <div class="panel-footer">
                        <chat-form
                                v-on:messagesent="addMessage"
                                :user="{{ Auth::user() }}"
                        ></chat-form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

이 뷰는 채팅방의 메인 페이지를 표시하는 데 사용됩니다. 뷰에서 일부 Vue 구성 요소를 사용하고 chat-messages 구성 요소는 모든 채팅 메시지를 표시하는 데 사용되며 chat-form 구성 요소는 메시지를 보내는 데 사용됩니다. 이러한 구성 요소에 대한 코드는 나중에 제공됩니다.

Vue 구성 요소를 작성하기 전에 resources/views/layouts/app.blade.php 템플릿에 채팅 보기에 대한 일부 스타일 코드를 추가합니다( 태그에 추가하기 전):

<style>
  .chat {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .chat li {
    margin-bottom: 10px;
    padding-bottom: 5px;
    border-bottom: 1px dotted #B3A9A9;
  }
  .chat li .chat-body p {
    margin: 0;
    color: #777777;
  }
  .panel-body {
    overflow-y: scroll;
    height: 350px;
  }
  ::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
    background-color: #F5F5F5;
  }
  ::-webkit-scrollbar {
    width: 12px;
    background-color: #F5F5F5;
  }
  ::-webkit-scrollbar-thumb {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
    background-color: #555;
  }
</style>

Next in resources/ 자산/js/comComponents에 ChatMessages.vue 구성 요소를 생성합니다:

<template>
    <ul class="chat">
        <li class="left clearfix" v-for="message in messages">
            <div class="chat-body clearfix">
                <div class="header">
                    <strong class="primary-font">
                        {{ message.user.name }}
                    </strong>
                </div>
                <p>
                    {{ message.message }}
                </p>
            </div>
        </li>
    </ul>
</template>
<script>
    export default {
        props: [&#39;messages&#39;]
    };
</script>

그런 다음 동일한 디렉터리에 ChatForm.vue 구성 요소를 생성합니다:

<template>
    <div class="input-group">
        <input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="在这里输入要发送的消息..." v-model="newMessage" @keyup.enter="sendMessage">
        <span class="input-group-btn">
            <button class="btn btn-primary btn-sm" id="btn-chat" @click="sendMessage">
                发送
            </button>
        </span>
    </div>
</template>
<script>
    export default {
        props: [&#39;user&#39;],
        data() {
            return {
                newMessage: &#39;&#39;
            }
        },
        methods: {
            sendMessage() {
                this.$emit(&#39;messagesent&#39;, {
                    user: this.user,
                    message: this.newMessage
                });
                this.newMessage = &#39;&#39;
            }
        }    
    }
</script>

마지막으로 resources/assets/js/app에 이 두 구성 요소를 등록해야 합니다. Vue 루트 인스턴스에서:

require(&#39;./bootstrap&#39;);
window.Vue = require(&#39;vue&#39;);
Vue.component(&#39;chat-messages&#39;, require(&#39;./components/ChatMessages.vue&#39;));
Vue.component(&#39;chat-form&#39;, require(&#39;./components/ChatForm.vue&#39;));
const app = new Vue({
    el: &#39;#app&#39;,
    data: {
        messages: []
    },
    created() {
        this.fetchMessages();
    },
    methods: {
        fetchMessages() {
            axios.get(&#39;/messages&#39;).then(response => {
                this.messages = response.data;
            });
        },
        addMessage(message) {
            this.messages.push(message);
            axios.post(&#39;/messages&#39;, message).then(response => {
                console.log(response.data);
            });
        }
    }
});

Broadcast 메시지 보내기 이벤트

채팅방에서 실시간 상호 작용을 위해서는 특정 이벤트를 브로드캐스트해야 합니다. 이 경우 사용자가 메시지를 보낼 때 MessageSent 이벤트를 트리거합니다. 메시지:

php artisan make:event MessageSent

작성된 앱/이벤트/MessageSent 이벤트 클래스 코드는 다음과 같습니다.

<?php
namespace App\Events;
use App\Message;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    /**
     * User that sent the message
     *
     * @var User
     */
    public $user;
    /**
     * Message details
     *
     * @var Message
     */
    public $message;
    /**
     * Create a new event instance.
     * @param User $user
     * @param Message $message
     * @return void
     */
    public function __construct(User $user, Message $message)
    {
        $this->user = $user;
        $this->message = $message;
    }
    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel(&#39;chat&#39;);
    }
}

由于只有登录用户才能访问我们的应用,所以我们定义了一个私有的频道 chat,只有登录用户才能连接上它。

接下来,我们需要修改 ChatsController 的 sendMessage() 来广播 MessageSent 事件:

public function sendMessage(Request $request)
{
    $user = Auth::user();
    $message = $user->messages()->create([
        &#39;message&#39; => $request->input(&#39;message&#39;)
    ]);
    broadcast(new MessageSent($user, $message))->toOthers();
    return [&#39;status&#39; => &#39;Message Sent!&#39;];
}

然后在 routes/channels.php 中授权当前登录用户可以监听该私有频道:

Broadcast::channel(&#39;chat&#39;, function ($user) {
    return Auth::check();
});

现在,当一条消息发送后,MessageSent 事件就会被广播到 Pusher,使用 toOthers() 是为了将消息发送者从广播接收者中排除。

监听消息发送事件

MessageSent 事件在服务端被广播后,需要在客户端监听这个事件以便将最新发送消息更新到聊天室消息流中,我们可以通过在 resources/assets/js/app.js 中定义的 created() 方法中添加如下代码片段来实现这一功能:

created() {
    this.fetchMessages();
    Echo.private(&#39;chat&#39;)
        .listen(&#39;MessageSent&#39;, (e) => {
            this.messages.push({
                message: e.message.message,
                user: e.user
            });
        });
},

我们通过 Laravel Echo 连接到 chat 频道监听 MessageSent 广播事件,如果有新消息则将其推送到当前聊天室消息流中显示。

在正式测试聊天室应用之前,还需要运行以下命令通过 Laravel Mix 来编译前面编写的 JavaScript 代码:

npm run dev

使用示例

完成上述所有业务代码编写工作后,接下来就是见证工作成果的时候了,在项目根目录下运行如下命令启动应用:

php artisan serve

然后在浏览器通过 http://127.0.0.1:8000/ 访问应用,由于系统需要登录后才能访问,所以首先会跳转到登录页面,我们需要先注册一个新用户,注册成功后页面即跳转到聊天室页面,我们发送一条测试消息。

为了测试多个用户聊天的效果,打开另一个浏览器或者在当前浏览器新开一个隐身窗口,还是重复上面的访问注册步骤(注册名不同),注册成功后跳转到聊天室页面,看到的效果和上面一样,我们再发条消息试试。

可以看到两个窗口消息是同步的,所以已经达到我们预期的实时聊天效果,实现了通过事件广播构建实时聊天室的功能。

以上就是本篇文章的全部内容了,更多laravel内容请关注laravel框架入门教程。

相关文章推荐:

laravel框架中TokenMismatchException的异常处理内容

Laravel 5.1框架中的ACL用户授权和权限检查功能的实现

相关课程推荐:

2017年最新的五个Laravel视频教程推荐

위 내용은 실시간 채팅방 : Laravel+Pusher+Vue 기반의 이벤트 방송을 통해 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.