天天看點

Laravel5.6使用redis隊列實作系統通知

需求:

一、我們這個系統通知子產品的功能是背景發送一個系統通知給所有人或者是給一個人。比如我們在8月8号發送一個系統通知:歡迎大家來到武漢PHP教育訓練長樂未央學習技術。那麼每一個人都會收到這個通知,但是如果是8月9号注冊進來的人就不會收到這個通知。這個時候,這種通知必須是分發的,每個人都需要有一條記錄來儲存所分發的通知,是以這是一個分發的邏輯。

二、使用同步還是異步來分發。比如我們要是群發的話,需要從業人員在背景點選釋出按鈕就同步發送通知到使用者的通知箱呢還是異步使用隊列來做這個事情,當然選擇異步更加穩妥。它能防止一個請求比較慢的情況,營運人員點選釋出按鈕之後,會直接告訴營運人員你已經通知成功,但實際上在背景,我們會使用另外一個腳本來把這個通知一個一個地發送給使用者,這個就是一個異步的場景,使用者體驗比較好了。而且在使用者量比較大的情況下,必須使用異步的這種設計方案。一般來說,異步就要使用到隊列。一說到隊列,很多人就會想到redis之類的,redis是實作隊列的非常好的方式,但是并不是隻有redis能實作隊列,我們這裡示範資料庫在laravel中做隊列的方式,其實在laravel中,它不管隊列是使用redis還是MySQL來實作,隻需要改一個配置檔案即可,在業務邏輯上是沒有差別的。

接下來,我們來實作這個功能。

1、建立項目:打開終端,執行指令

laravel new queue

。建立好項目之後,參考我的另外一篇文章去實作多使用者登入注冊(兩個使用者即可)。文章位址:

https://itfun.tv/news/20

,實作成功後才能進行下一步操作。

2、我們這裡使用到隊列,是以在

.env

檔案中修改

QUEUE_DRIVER=sync

QUEUE_DRIVER=database

3、建立通知資料表遷移檔案:

php artisan make:migration create_notices_table

,打開後,在up方法中修改内容如下:

Schema::create('notices', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title', 50);
    $table->text('content');
    $table->timestamps();
});

Schema::create('user_notice', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('user_id')->default(0);
    $table->integer('notice_id')->default(0);
    $table->timestamps();
});
           

down

方法中

public function down()
{
    Schema::dropIfExists('notices');
    Schema::dropIfExists('user_notice');
}
           

解析:

notices

表是使用者通知表,

user_notice

是中間表,因為使用者和通知之間的關系是多對多。

接着執行資料庫遷移:

php artisan migrate

背景

1、在

web.php

中設定通知路由:

Route::middleware('auth.admin:admin')->name('admin.')->group(function () {
    $this->get('/', '[email protected]');

    $this->resource('notices', 'NoticeController')->except(['show', 'edit', 'update']);
});
           

2、建立對應控制器:

php artisan make:controller Admin/NoticeController -r

和模型:

php artisan make:model Models/Notice

3、在

User.php

模型中,定義關聯關系如下:

//使用者和通知之間是多對多
public function notices()
{
    return $this->belongsToMany('App\Models\Notice', 'user_notice', 'user_id', 'notice_id')->withPivot(['user_id', 'notice_id']);
}

//給使用者增加通知
public function addNotice($notice)
{
    return $this->notices()->save($notice);
}
           

4、背景實作新增通知和通知清單即可。樣式參考如下,代碼省略…

Laravel5.6使用redis隊列實作系統通知
Laravel5.6使用redis隊列實作系統通知

5、注意:功能實作後,新增一個使用者,此時

notices

表是有資料的,但是中間表是沒有資料的。

前端

1、在

web.php

中設定前端路由,用于顯示所有通知。

//前端通知顯示
$this->get('/notice', '[email protected]')->name('notice');
           

2、在前端Home控制器中建立

notice

方法,代碼如下:

/***
 * 前端通知頁面
 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 */
public function notice()
{
    //擷取目前使用者的notice
    $user = \Auth::user();
    $notices = $user->notices;
    return view('notice.index', compact('notices'));
}
           

3、加載頁面,在

resources/views/notice

建立index模闆,并循環加載通知内容。此時,通路前端通知的路由位址,你會發現資料庫裡的通知并沒有渲染出來,如圖:

Laravel5.6使用redis隊列實作系統通知

接下來我們要按需求實作消息的分發。

##隊列的使用

1、打開終端執行指令:

php artisan queue:table

,打開遷移檔案,代碼如下:

Schema::create('jobs', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('queue')->index()->comment('隊列名稱');
    $table->longText('payload')->comment('隊列資料');
    $table->unsignedTinyInteger('attempts')->comment('嘗試次數');
    $table->unsignedInteger('reserved_at')->nullable()->comment('保留時間');
    $table->unsignedInteger('available_at')->comment('可運作時間');
    $table->unsignedInteger('created_at')->comment('隊列建立時間');
});
           

2、執行遷移指令:

php artisan migrate

,會在資料庫中生成

jobs

3、生成任務類,執行指令:

php artisan make:job SendMessage

,這個指令會在你的項目目錄結構

App\Jobs

中生成一個任務類檔案

SendMessage.php

。打開檔案,寫上如下代碼:

<?php

namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class SendMessage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    private $notice;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($notice)
    {
        $this->notice = $notice;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //通知每個使用者的 系統消息
        $users = User::all();
        foreach ($users as $user) {
            $user->addNotice($this->notice);
        }
    }
}
           

4、打開背景通知控制器,在執行新增通知方法中加上如下代碼:

public function store(Request $request)
{
    $request->validate([
        'title' => 'bail|required|unique:notices|max:255',
        'content' => 'required',
    ]);

    $notice = Notice::create($request->all());

		//執行消息分發
    dispatch(new \App\Jobs\SendMessage($notice));

    return redirect(route('admin.notices.index'))->with('success', '新增通知成功');
}
           

5、啟動隊列:

php artisan queue:work

,注意:不要關閉了。

6、測試:浏覽器通路前端位址:

http://queue.test/notice

,你會看到如下頁面,即為消息分發成功:

Laravel5.6使用redis隊列實作系統通知

測試案例代碼可參考:

https://coding.net/u/holyow/p/queue/git

Well Done !!!