Spring基于SseEmitter实现服务端向客户端发送消息
1、Service层
public interface SseEmitterService {
SseEmitter connect(String clientId);
Boolean sendMsg(String clientId, SseDataVO sseDataVO);
void close(String clientId);
}
2、实现
@Slf4j
@Service
public class SseEmitterServiceImpl implements SseEmitterService {
private static final Map<String, SseEmitter> sseCache = new ConcurrentHashMap<>();
public SseEmitter connect(String clientId) {
SseEmitter sseEmitter = new SseEmitter(60 * 60 * 8L * 1000);
SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event().reconnectTime(10000);
try {
sseEmitter.send(sseEventBuilder.data(MessageUtils.message("E_SSE_0001")));
} catch (IOException e) {
throw new CustomException("E_SSE_0002");
}
if (sseCache.containsKey(clientId)) {
try {
sseCache.get(clientId).complete();
sseCache.remove(clientId);
}catch (Exception e){
log.error("SSE 关闭失败: {}", clientId, e);
}
}
sseCache.put(clientId, sseEmitter);
sseEmitter.onTimeout(() -> {
log.error("SSE 超时: {}", clientId);
sseCache.remove(clientId);
});
sseEmitter.onCompletion(() -> {
log.info("SSE 关闭: {}", clientId);
});
sseEmitter.onError((e) -> {
log.error("SSE 发生错误: {}, {}", clientId, e.getMessage());
sseCache.remove(clientId);
});
log.info("SSE 连接成功: {}", clientId);
return sseEmitter;
}
@Override
public Boolean sendMsg(String clientId, SseDataVO sseDataVO) {
SseEmitter sseEmitter = sseCache.get(clientId);
if (!ObjectUtils.isEmpty(sseEmitter)) {
try {
sseEmitter.send(SseEmitter.event().data(sseDataVO));
log.info("SSE 发送消息成功: {},info:{}", clientId, sseDataVO.toString());
return true;
} catch (Exception e) {
log.error("SSE 发送消息失败: {},info:{}", clientId, sseDataVO.toString(), e);
}
}else{
log.error("SSE为空,发送消息失败: {},info:{}", clientId, sseDataVO.toString());
}
return false;
}
@Override
public void close(String clientId) {
SseEmitter sseEmitter = sseCache.get(clientId);
if (!ObjectUtils.isEmpty(sseEmitter)) {
sseEmitter.complete();
sseCache.remove(clientId);
}
}
}