feat: sse
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
package com.webgame.webgamebackend.sse;
|
||||
|
||||
import com.webgame.webgamebackend.common.auth.AuthenticationProvider;
|
||||
import com.webgame.webgamebackend.common.dto.ApiResponse;
|
||||
import com.webgame.webgamebackend.common.event.SseEventPublisher;
|
||||
import com.webgame.webgamebackend.common.event.SseEventType;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SSE 订阅端点
|
||||
@@ -30,6 +36,7 @@ public class SseController {
|
||||
|
||||
private final SseConnectionManager connectionManager;
|
||||
private final AuthenticationProvider authProvider;
|
||||
private final SseEventPublisher eventPublisher;
|
||||
|
||||
@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public SseEmitter subscribe(
|
||||
@@ -73,6 +80,49 @@ public class SseController {
|
||||
return emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用消息发布接口
|
||||
*
|
||||
* 支持广播(不传 userId)和定向推送(传 userId)两种模式。
|
||||
* 可传入任意 JSON 数据作为消息体,事件类型固定为 CUSTOM。
|
||||
*
|
||||
* 请求体示例:
|
||||
* <pre>
|
||||
* // 广播
|
||||
* { "data": { "msg": "hello" } }
|
||||
*
|
||||
* // 定向推送
|
||||
* { "userId": "123", "data": { "msg": "hello" } }
|
||||
* </pre>
|
||||
*
|
||||
* @param body 请求体,包含可选的 userId 和必填的 data
|
||||
* @return 统一 API 响应
|
||||
*/
|
||||
@PostMapping("/publish")
|
||||
public ApiResponse<Map<String, Object>> publish(@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> data = (Map<String, Object>) body.get("data");
|
||||
if (data == null || data.isEmpty()) {
|
||||
return ApiResponse.fail(400, "data 字段不能为空");
|
||||
}
|
||||
|
||||
String userId = body.get("userId") != null ? body.get("userId").toString() : null;
|
||||
|
||||
if (userId != null && !userId.isBlank()) {
|
||||
eventPublisher.sendTo(userId, SseEventType.CUSTOM, data);
|
||||
log.info("[SSE] 测试定向推送, userId={}, data={}", userId, data);
|
||||
} else {
|
||||
eventPublisher.broadcast(SseEventType.CUSTOM, data);
|
||||
log.info("[SSE] 测试广播推送, data={}", data);
|
||||
}
|
||||
|
||||
return ApiResponse.ok(Map.of(
|
||||
"mode", userId != null && !userId.isBlank() ? "targeted" : "broadcast",
|
||||
"userId", userId != null ? userId : "all",
|
||||
"data", data
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 向 SSE 客户端返回认证错误
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user