server向浏览器发送信息-SseEmitter使用

什么是SseEmitter

SseEmitter 是 Spring 框架中的一个类,用于支持服务器发送事件(Server-Sent Events, SSE)。SSE 是一种允许服务器主动向客户端推送实时更新的技术,通常用于需要实时数据更新的应用场景,如股票行情、社交媒体通知等。

在 Spring 中,SseEmitter 提供了一种简单的方式来实现 SSE。通过 SseEmitter,服务器可以在一个长连接中不断地向客户端发送事件,而客户端则可以通过 JavaScript 的 EventSource 对象来接收这些事件

和websocket的区别

SseEmitter(Server-Sent Events)和 WebSocket 是两种不同的技术,用于在客户端和服务器之间进行实时通信。它们有各自的特点和适用场景。

  1. SseEmitter(Server-Sent Events,SSE)

    • 单向通信:SSE 是一种单向通信协议,服务器可以向客户端发送更新,但客户端不能向服务器发送数据。
    • 基于HTTP:SSE 使用 HTTP 协议,客户端通过 HTTP 请求订阅服务器的事件流,服务器通过持续的 HTTP 响应发送事件。
    • 简单实现:SSE 的实现相对简单,特别适合于需要从服务器向客户端推送实时更新的场景,如股票行情、新闻推送等。
    • 浏览器支持:大多数现代浏览器都支持 SSE,但在某些旧版本的浏览器中可能不支持。
  2. WebSocket

    • 双向通信:WebSocket 是一种全双工通信协议,允许客户端和服务器之间进行双向数据传输。
    • 独立协议:WebSocket 是一个独立的协议,虽然最初的握手是通过 HTTP 完成的,但一旦连接建立,通信就不再依赖于 HTTP。
    • 高效传输:WebSocket 连接一旦建立,数据传输效率高,适合需要频繁、低延迟通信的场景,如在线游戏、实时聊天应用等。
    • 复杂实现:WebSocket 的实现相对复杂,需要处理连接的建立、维护和关闭等细节。

总结

  • 如果你的应用场景只需要服务器向客户端推送数据,并且实现简单是一个重要考虑因素,那么可以选择 SseEmitter(SSE)。
  • 如果你的应用场景需要双向实时通信,并且对传输效率和低延迟有较高要求,那么 WebSocket 是更好的选择。

代码示例

 

import org.springframework.web.bind.annotation.*;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/chat")
public class ChatController {

    private List<SseEmitter> emitters = new ArrayList<>();
    //发送
    @PostMapping("/send")
    public void sendMessage(@RequestBody ChatMessage message) {
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(message, MediaType.APPLICATION_JSON);
            } catch (IOException e) {
                emitter.completeWithError(e);
            }
        }
    }
    
    //接收
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamMessages() {
        SseEmitter emitter = new SseEmitter(60000L); //超时时间
        emitters.add(emitter);
        emitter.onCompletion(() -> emitters.remove(emitter));
        emitter.onTimeout(() -> emitters.remove(emitter));
        return emitter;
    }
}

//信息体
@Data
public class ChatMessage {
    private String sender;
    private String content;
    private String timestamp;

    // Getters and Setters
}

/chat/stream 接收到的消息 

 

### 如何使用 `SseEmitter` 实现服务器发送事件 (Server-Sent Events) #### SSE简介 Server-Sent Events(SSE)是一种允许服务器向客户端推送实时更新的技术。相比WebSocket,SSE更简单易用,在单向通信场景下表现良好。 #### SseEmitter介绍 `SseEmitter` 是Spring框架提供的一个类,专门用于处理基于HTTP协议的长连接,支持通过SSE技术向浏览器或其他HTTP客户端持续发送消息[^1]。 #### 添加依赖 为了在项目中启用对SseEmitter的支持,需确保pom.xml文件中含有如下依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> ``` 此配置使得应用程序能够运行于WebFlux模式之下,从而更好地兼容异步操作和响应式编程模型。 #### 创建事件服务类 定义一个名为`EventService`的服务层组件来管理待推送给用户的事件队列: ```java @Service public class EventService { private final Map<Long, List<String>> events = new ConcurrentHashMap<>(); public void addEvent(Long userId, String message){ events.computeIfAbsent(userId, k -> new CopyOnWriteArrayList<>()).add(message); } public Flux<String> getEventsByUserId(Long userId){ return Flux.fromIterable(events.getOrDefault(userId,Collections.emptyList())); } } ``` 上述代码片段展示了如何利用Java8的新特性以及Reactor库中的`Flux<T>`类型构建可观察的数据序列。 #### 构建REST API接口 创建控制器以暴露给外部调用者访问路径,并负责接收来自服务端的消息并转发至对应的订阅者: ```java @RestController @RequestMapping("/api/events") @RequiredArgsConstructor public class EventController { private final EventService eventService; @GetMapping(value="/{userId}", produces="text/event-stream;charset=UTF-8") public ResponseEntity<SseEmitter> subscribe(@PathVariable Long userId) throws InterruptedException{ SseEmitter emitter = new SseEmitter(); // 设置超时时间 emitter.onCompletion(() -> System.out.println("Connection closed")); emitter.onError(t->System.err.println("Error occurred:"+t.getMessage())); // 将当前emitter对象存入缓存以便后续广播消息时找到它 emitters.put(userId,emitter); // 启动线程定期检查是否有新消息到达 CompletableFuture.runAsync(()->sendMessages(emitter,eventService.getEventsByUserId(userId))); return new ResponseEntity<>(emitter,HttpStatus.OK); } private void sendMessages(SseEmitter sseEmitter,Flux<String> messages){ try{ messages.subscribe(msg->{ try{ if(!sseEmitter.isDisconnected()){ sseEmitter.send(SseEmitter.event().data(msg)); }else{ throw new RuntimeException("Client disconnected"); } }catch(Exception e){ sseEmitter.completeWithError(e); } }); }finally{ cleanup(sseEmitter); } } private void cleanup(SseEmitter sseEmitter){ Optional.ofNullable(sseEmitter).ifPresent(it->it.complete()); } } ``` 这里实现了当有新的用户登录或者产生行为变更时触发通知机制的功能逻辑。 #### 前端实现 HTML页面可以通过JavaScript轻松地监听这些由后端发出的通知信息: ```javascript var source = new EventSource('/api/events/1'); source.addEventListener('message',function(event){ console.log(`Received data:${event.data}`); },false); // 当不再需要继续接受消息的时候可以主动断开链接 window.addEventListener('beforeunload',(e)=>{ source.close(); }); ``` 以上就是完整的前后端联调过程描述[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值