本文目录导读:

我将为您创建一个完整的Laravel广播事件驱动实时更新系统示例。
项目设置
安装必要的包
# 安装Laravel Reverb(Laravel 11+) composer require laravel/reverb # 或使用Pusher composer require pusher/pusher-php-server # 前端依赖 npm install --save laravel-echo pusher-js
配置.env文件
# Reverb配置 BROADCAST_CONNECTION=reverb REVERB_APP_ID=local REVERB_APP_KEY=local REVERB_APP_SECRET=secret REVERB_HOST="127.0.0.1" REVERB_PORT=8080 REVERB_SCHEME=http # 或 Pusher配置 # BROADCAST_CONNECTION=pusher # PUSHER_APP_ID=your-app-id # PUSHER_APP_KEY=your-key # PUSHER_APP_SECRET=your-secret # PUSHER_APP_HOST=127.0.0.1 # PUSHER_APP_PORT=443 # PUSHER_APP_SCHEME=https
创建广播事件
创建订单事件
<?php
// app/Events/OrderCreated.php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderCreated implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $order;
/**
* Create a new event instance.
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new Channel('orders'),
];
}
/**
* 自定义广播数据
*/
public function broadcastWith(): array
{
return [
'order_id' => $this->order->id,
'customer_name' => $this->order->customer_name,
'total_amount' => $this->order->total_amount,
'status' => $this->order->status,
'created_at' => $this->order->created_at->toISOString(),
];
}
/**
* 自定义广播事件名称
*/
public function broadcastAs(): string
{
return 'order.created';
}
}
创建订单更新事件
<?php
// app/Events/OrderStatusUpdated.php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderStatusUpdated implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $order;
public $oldStatus;
public $newStatus;
public function __construct(Order $order, $oldStatus, $newStatus)
{
$this->order = $order;
$this->oldStatus = $oldStatus;
$this->newStatus = $newStatus;
}
public function broadcastOn(): array
{
return [
new Channel('orders'),
new PrivateChannel('user.' . $this->order->user_id),
];
}
public function broadcastWith(): array
{
return [
'order_id' => $this->order->id,
'old_status' => $this->oldStatus,
'new_status' => $this->newStatus,
'updated_at' => now()->toISOString(),
];
}
public function broadcastAs(): string
{
return 'order.status.updated';
}
}
创建实时通知事件
<?php
// app/Events/NewNotification.php
namespace App\Events;
use App\Models\Notification;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewNotification implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $notification;
public function __construct(Notification $notification)
{
$this->notification = $notification;
}
public function broadcastOn(): array
{
return [
new Channel('notifications.' . $this->notification->user_id),
];
}
public function broadcastWith(): array
{
return [
'id' => $this->notification->id,
'type' => $this->notification->type,
'message' => $this->notification->message,
'data' => $this->notification->data,
'read' => $this->notification->read_at !== null,
'created_at' => $this->notification->created_at->toISOString(),
];
}
public function broadcastAs(): string
{
return 'notification.created';
}
}
创建模型事件监听
Order模型
<?php
// app/Models/Order.php
namespace App\Models;
use App\Events\OrderCreated;
use App\Events\OrderStatusUpdated;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'customer_name',
'customer_email',
'total_amount',
'status',
'items'
];
protected $casts = [
'items' => 'array',
'total_amount' => 'decimal:2',
];
protected $dispatchesEvents = [
'created' => OrderCreated::class,
];
// 状态更新自动触发事件
public function updateStatus(string $newStatus)
{
$oldStatus = $this->status;
$this->update(['status' => $newStatus]);
event(new OrderStatusUpdated($this, $oldStatus, $newStatus));
return $this;
}
// 关联用户
public function user()
{
return $this->belongsTo(User::class);
}
}
创建控制器
<?php
// app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Events\OrderCreated;
use App\Events\OrderStatusUpdated;
use App\Models\Order;
use App\Models\Notification;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class OrderController extends Controller
{
/**
* 创建订单并触发事件
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'customer_name' => 'required|string|max:255',
'customer_email' => 'required|email',
'total_amount' => 'required|numeric|min:0',
'items' => 'required|array',
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$order = Order::create([
'user_id' => auth()->id(),
...$request->all()
]);
// 手动触发事件
event(new OrderCreated($order));
// 创建通知
$notification = Notification::create([
'user_id' => auth()->id(),
'type' => 'order_confirmation',
'message' => "Order #{$order->id} confirmed successfully",
'data' => [
'order_id' => $order->id,
'total' => $order->total_amount
]
]);
// 触发通知事件
event(new NewNotification($notification));
return response()->json([
'message' => 'Order created successfully',
'order' => $order
], 201);
}
/**
* 更新订单状态
*/
public function updateStatus(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'status' => 'required|in:pending,processing,shipped,delivered,cancelled'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$order = Order::findOrFail($id);
$order->updateStatus($request->status);
// 创建状态更新通知
$notification = Notification::create([
'user_id' => $order->user_id,
'type' => 'order_status',
'message' => "Order #{$order->id} status changed to {$request->status}",
'data' => [
'order_id' => $order->id,
'status' => $request->status
]
]);
event(new NewNotification($notification));
return response()->json([
'message' => 'Order status updated successfully',
'order' => $order
]);
}
/**
* 标记通知为已读
*/
public function markNotificationRead($notificationId)
{
$notification = Notification::findOrFail($notificationId);
$notification->update(['read_at' => now()]);
return response()->json(['message' => 'Notification marked as read']);
}
}
前端JavaScript设置
创建resources/js/bootstrap.js配置
// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
// Reverb配置
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 8080,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
enabledTransports: ['ws', 'wss'],
});
// Pusher配置(如果使用Pusher)
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true
// });
创建实时监听组件
// resources/js/live/realtime-handlers.js
export class RealtimeHandler {
constructor() {
this.orderChannel = null;
this.notificationChannels = [];
this.init();
}
init() {
// 监听所有订单事件
this.setupOrderListeners();
// 监听用户私有通知(需要认证)
this.setupNotificationListeners();
}
setupOrderListeners() {
this.orderChannel = window.Echo.channel('orders');
// 监听新订单
this.orderChannel.listen('.order.created', (data) => {
this.handleNewOrder(data);
});
// 监听订单状态更新
this.orderChannel.listen('.order.status.updated', (data) => {
this.handleOrderStatusUpdate(data);
});
}
setupNotificationListeners() {
// 获取当前用户ID
const userId = document.querySelector('meta[name="user-id"]')?.content;
if (userId) {
this.setupPrivateChannel(userId);
}
}
setupPrivateChannel(userId) {
console.log(`Setting up private channel for user: ${userId}`);
// 监听用户私有通知通道
const channel = window.Echo.channel(`user.${userId}`);
// 监听订单状态更新
channel.listen('.order.status.updated', (data) => {
this.handlePrivateOrderUpdate(data);
});
// 监听新通知
const notificationChannel = window.Echo.channel(`notifications.${userId}`);
notificationChannel.listen('.notification.created', (data) => {
this.handleNewNotification(data);
});
this.notificationChannels.push(channel, notificationChannel);
}
handleNewOrder(data) {
console.log('New order received:', data);
// 创建通知DOM元素
const notification = this.createNotificationElement(
'New Order',
`Order #${data.order_id} from ${data.customer_name} for $${data.total_amount}`,
'success'
);
this.appendNotification(notification);
// 播放声音提示
this.playNotificationSound();
// 更新订单计数
this.updateOrderCounter();
// 触发自定义事件
window.dispatchEvent(new CustomEvent('order:created', { detail: data }));
}
handleOrderStatusUpdate(data) {
console.log('Order status updated:', data);
// 更新UI
this.updateOrderStatusUI(data.order_id, data.new_status);
// 显示通知
const notification = this.createNotificationElement(
'Order Updated',
`Order #${data.order_id} has been ${data.new_status}`,
'info'
);
this.appendNotification(notification);
// 触发自定义事件
window.dispatchEvent(new CustomEvent('order:status-updated', { detail: data }));
}
handleNewNotification(data) {
console.log('New notification:', data);
const notification = this.createNotificationElement(
'Notification',
data.message,
'info'
);
this.appendNotification(notification);
this.updateNotificationBadge();
// 触发自定义事件
window.dispatchEvent(new CustomEvent('notification:received', { detail: data }));
}
createNotificationElement(title, message, type) {
const container = document.createElement('div');
container.className = `notification-item alert alert-${type} fade-in`;
container.innerHTML = `
<div class="notification-content">
<h4>${title}</h4>
<p>${message}</p>
</div>
<button class="close-btn" onclick="this.parentElement.remove()">×</button>
`;
return container;
}
appendNotification(notification) {
const notificationContainer = document.querySelector('#notification-container');
if (notificationContainer) {
notificationContainer.appendChild(notification);
// 自动移除通知
setTimeout(() => {
notification.classList.add('fade-out');
setTimeout(() => notification.remove(), 300);
}, 5000);
}
}
updateOrderStatusUI(orderId, status) {
const orderElement = document.querySelector(`[data-order-id="${orderId}"]`);
if (orderElement) {
const statusElement = orderElement.querySelector('.order-status');
if (statusElement) {
statusElement.textContent = status;
statusElement.className = `order-status badge-${status}`;
}
}
}
playNotificationSound() {
const audio = new Audio('/sounds/notification.mp3');
audio.play().catch(() => console.log('Sound playback blocked'));
}
updateOrderCounter() {
const counter = document.querySelector('#order-counter');
if (counter) {
const current = parseInt(counter.textContent) || 0;
counter.textContent = current + 1;
}
}
updateNotificationBadge() {
const badge = document.querySelector('#notification-badge');
if (badge) {
const current = parseInt(badge.dataset.count) || 0;
badge.dataset.count = current + 1;
badge.textContent = current + 1;
}
}
destroy() {
// 清理监听器
this.orderChannel?.stopListening('.order.created');
this.orderChannel?.stopListening('.order.status.updated');
this.notificationChannels.forEach(channel => {
channel.stopListening('.order.status.updated');
channel.stopListening('.notification.created');
});
}
}
// 初始化实时处理程序
export const realtimeHandler = new RealtimeHandler();
在应用入口引入
// resources/js/app.js import './bootstrap'; import './live/realtime-handlers';
Blade模板
{{-- resources/views/orders/index.blade.php --}}
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="user-id" content="{{ auth()->id() }}">Live Orders</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<div class="container">
<h1>Live Orders Dashboard</h1>
<!-- 通知区域 -->
<div id="notification-container"></div>
<!-- 统计信息 -->
<div class="stats-grid">
<div class="stat-card">
<h3>New Orders</h3>
<span id="order-counter">0</span>
</div>
<div class="stat-card">
<h3>Notifications</h3>
<span id="notification-badge" data-count="0">0</span>
</div>
</div>
<!-- 订单列表 -->
<div class="orders-list">
@foreach($orders as $order)
<div class="order-card" data-order-id="{{ $order->id }}">
<div class="order-header">
<h3>Order #{{ $order->id }}</h3>
<span class="order-status badge-{{ $order->status }}">{{ $order->status }}</span>
</div>
<div class="order-body">
<p>Customer: <strong>{{ $order->customer_name }}</strong></p>
<p>Total: <strong>${{ number_format($order->total_amount, 2) }}</strong></p>
<p>Created: <strong>{{ $order->created_at->format('Y-m-d H:i:s') }}</strong></p>
</div>
<div class="order-actions">
<select class="status-select" onchange="updateStatus({{ $order->id }}, this.value)">
<option value="">Select Status</option>
@foreach(['pending', 'processing', 'shipped', 'delivered', 'cancelled'] as $status)
<option value="{{ $status }}" {{ $order->status === $status ? 'selected' : '' }}>
{{ ucfirst($status) }}
</option>
@endforeach
</select>
</div>
</div>
@endforeach
</div>
</div>
<script>
// 额外的自定义函数
function updateStatus(orderId, status) {
fetch(`/api/orders/${orderId}/status`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ status: status })
})
.then(response => response.json())
.then(data => {
console.log('Order updated:', data);
})
.catch(error => console.error('Error:', error));
}
// 监听自定义事件
window.addEventListener('order:created', (e) => {
console.log('Custom event - Order created:', e.detail);
});
window.addEventListener('order:status-updated', (e) => {
console.log('Custom event - Order status updated:', e.detail);
});
window.addEventListener('notification:received', (e) => {
console.log('Custom event - Notification received:', e.detail);
});
</script>
</body>
</html>
启动服务
# 启动Reverb服务 php artisan reverb:start # 启动队列(如果使用队列) php artisan queue:work # 开发环境启动 npm run dev # 生产环境构建 npm run build
路由配置
<?php
// routes/api.php
use App\Http\Controllers\OrderController;
use App\Http\Controllers\NotificationController;
Route::middleware('auth:sanctum')->group(function () {
Route::post('/orders', [OrderController::class, 'store']);
Route::put('/orders/{id}/status', [OrderController::class, 'updateStatus']);
Route::post('/notifications/{id}/read', [OrderController::class, 'markNotificationRead']);
});
测试事件
# 使用Artisan测试事件
php artisan tinker
# 创建测试订单
$order = App\Models\Order::create([
'user_id' => 1,
'customer_name' => 'John Doe',
'customer_email' => 'john@example.com',
'total_amount' => 100.00,
'status' => 'pending',
'items' => json_encode([['product' => 'Test', 'quantity' => 1, 'price' => 100]])
]);
# 这将自动触发OrderCreated事件
注意事项
- 性能优化:大量并发广播时,建议使用Redis队列
- 认证安全:私有频道需要实现授权逻辑
- 重连机制:考虑实现WebSocket断线重连
- 错误处理:实现适当的错误处理和日志记录
- 前端优化:合理使用事件节流和防抖
这个系统实现了实时订单更新、状态变更通知、用户通知等功能,可基于此扩展更多实时功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播