Xây dựng service đếm view bằng laravel
Đếm view là 1 vấn đề thường gặp ở các trang web và ứng dụng ,và khi bạn có 1,2 trang web thì không sao ko cần thiết kế 1 service như này nhưng nếu bạn có tầm vài chục và vài trăm website và để quản lý khối lượng đếm view như thế sẽ rất khó khăn do đó nay mình viết 1 bài code hướng dẫn xây dựng service đếm view .Service này cơ bản chưa có user và phân quyền ,các bạn cần viết thêm để có thể làm 1 dự án thực tế
Bước 1 : Tạo ứng dụng web
composer create-project laravel/laravel demview
Sau khi tải thành công về chúng ta chạy command sau :
php artisan make:trait ResponseTrait
Trait này có tác dụng tạo thông tin trả về :
<?php
namespace App;
use Illuminate\Http\Client\Response;
trait ResponseTrait
{
public function success($data = null, $message = "success", $code = 200)
{
$datareturn = [
'data' => $data,
'message' => $message,
];
return response()->json($datareturn, status: 200);
}
public function error($message = "error", $code = 500)
{
$datareturn = [
'data' => '',
'message' => $message,
];
return response()->json($datareturn, 500);
}
}
Và chúng ta tạo Postview với lệnh sau :
php artisan make:model Postview -mrc
Trong file migrate chúng ta code như sau :
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('postviews', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger(column: 'website_id')->default(0);
$table->unsignedBigInteger('post_id')->default(0);
$table->unsignedBigInteger('views')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('postviews');
}
};
Chạy migrate thì chương trình sẽ tạo cho chúng ta 1 table với thông tin là website_id ,post_id và views
Trong controller :
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Postviews;
use App\ResponseTrait;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class PostviewController extends Controller
{
use ResponseTrait;
public string $cacheKey;
public $data;
public function __construct(Request $request) {}
public function add(Request $request)
{
$data_get = $request->only('website_id', 'post_id');
$this->cacheKey = 'web_' . $data_get['website_id'] . '_post_' . $data_get['post_id'] . '_views';
$this->data = $data_get;
// Tăng số lượng lượt xem trong cache nếu không có cache thì tạo cache
if (!Cache::has($this->cacheKey)) {
Cache::set($this->cacheKey, 0);
}
try {
// cộng lượt view vào đây
$viewCount = Cache::increment($this->cacheKey);
// Kiểm tra nếu view count trong cache đạt đến một mốc nhất định (ví dụ: 1000)
if ($viewCount >= 100) {
try {
// Sử dụng lock để tránh race condition khi nhiều người truy cập cùng lúc
Cache::lock('post_' . $this->cacheKey . '_lock', 10)->block(5, function () use ($viewCount): void {
$post_id = (int)$this->data['post_id'];
$website_id = (int)$this->data['website_id'];
$postviews = Cache::flexible('getdata_' . $website_id . '_post' . $post_id, [100, 205], function () use ($post_id, $website_id) {
return Postviews::where('website_id', '=', $website_id)->where('post_id', '=', $post_id)->first();
});
if ($postviews) {
$postviews->increment('views', $viewCount);
$data_return = $postviews;
}
// Xóa cache sau khi cập nhật vào database
Cache::forget($this->cacheKey);
});
} catch (\Exception $e) {
Log::error('lỗi lock');
Log::error($e->getMessage());
}
}
return $this->success();
} catch (\Exception $e) {
Log::error(message: $e->getMessage());
return $this->error('lỗi insert');
}
}
public function getdata(Request $request, int $website_id, int $post_id)
{
$this->cacheKey = 'web_' . $website_id . '_post_' . $post_id . '_views';
// Tăng số lượng lượt xem trong cache nếu không có cache thì tạo cache
if (!Cache::has($this->cacheKey)) {
Cache::set($this->cacheKey, 0);
}
try {
$post_id = (int)$post_id;
$website_id = (int)$website_id;
$postviews = Cache::flexible('getdata_' . $website_id . '_post' . $post_id, [10, 15], function () use ($post_id, $website_id) {
return Postviews::where('website_id', '=', $website_id)->where('post_id', '=', $post_id)->first();
});
$cachedViews = Cache::get($this->cacheKey, 0);
$count_return = $postviews->views + $cachedViews;
return $this->success($count_return);
} catch (\Exception $e) {
Log::error(message: $e->getMessage());
return $this->error('lỗi insert');
}
}
}
Bạn có thể kết hợp với jwt token hoặc dùng api key để bảo mật thêm