用于与前端链接消息触发
@Resource
private SseMessageService sseMessageService;
@Resource
private ConfigPrinterConfig configPrinter;
@CrossOrigin(origins = "*", allowedHeaders = "GET")
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamSseMvc(String userId, String uniqueKey, HttpServletResponse response) {
response.setContentType("text/event-stream;charset=UTF-8");
SseEmitter emitter = new SseEmitter(Long.valueOf(configPrinter.getSseRequestTimeOut()));
sseMessageService.setUniqueKey(uniqueKey);
sseMessageService.addEmitter(userId, emitter);
sseMessageService.sendMessage(userId, "初始连接", "init");
return emitter;
}
private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
@Setter
private String uniqueKey = "";
public void addEmitter(String userId, SseEmitter emitter) {
emitters.put(userId, emitter);
log.info(DateUtils.getTime() + " 连接用户 userId:{}", userId);
emitter.onTimeout(() -> {
emitters.remove(userId);
emitter.complete();
});
emitter.onCompletion(() -> {
emitters.remove(userId);
emitter.complete();
});
emitter.onError((e) -> {
emitters.remove(userId);
emitter.completeWithError(e);
});
}
@Async()
public void removeEmitter(String userId, SseEmitter emitter) {
emitters.remove(userId);
emitter.complete();
}
@Async()
public void sendMessage(String userId, String message, String label) {
SseEmitter emitter = emitters.get(userId);
if (emitter != null) {
try {
// 创建一个 JSON 对象
Map<String, String> map = new HashMap<>();
map.put("label", label);
map.put("userId", userId);
map.put("message", message);
map.put("uniqueKey", uniqueKey);
map.put("id", String.valueOf(UUID.randomUUID()));
map.put("dateTimeNow", DateUtils.dateTimeNow());
emitter.send(new JSONObject(map).toString());
} catch (Exception e) {
emitter.completeWithError(e);
removeEmitter(userId, emitter);
}
}
}
解释
在使用 Server-Sent Events (SSE) 的场景中,消息的接收方通常是前端的 JavaScript 客户端。以下是消息接收的基本流程:
1. 前端设置 SSE 连接
在前端,你需要使用 JavaScript 创建一个 EventSource 对象来连接后端的 SSE 端点。例如:
const eventSource = new EventSource('http://你的服务器地址/sse?userId=用户ID&uniqueKey=唯一键');
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Received message:', data);
// 处理接收到的消息
};
// 处理连接关闭
eventSource.onclose = function() {
console.log('Connection closed');
};
// 处理错误
eventSource.onerror = function(error) {
console.error('Error occurred:', error);
};
2. 后端发送消息
在你的 SseMessageService
中,通过 emitter.send(...)
发送的消息会通过 SSE 通道推送到连接的客户端。客户端会通过 onmessage
事件接收到这些消息。
3. 消息的结构
你在后端构造的消息(例如包含 label
、`userId`、`message` 等字段)会在前端解析,前端可以根据消息内容进行相应的处理,例如更新 UI 或执行其他逻辑。
总结
- 接收方: 前端 JavaScript 客户端通过 EventSource 接收后端推送的消息。
- 发送方: 后端通过 SseEmitter
实现消息的推送。
如果有更具体的问题或者需要深入探讨,请告诉我!