Java 如何过滤Jersey SSE中的事件?
在查看jersey sse示例时,我在jersey示例文件夹中找到了一个示例sse item store webapp。这是一个非常简单的应用程序,有一个输入和一个按钮。您键入一些文本,单击按钮,其他人将得到更改Java 如何过滤Jersey SSE中的事件?,java,jersey,server-sent-events,Java,Jersey,Server Sent Events,在查看jersey sse示例时,我在jersey示例文件夹中找到了一个示例sse item store webapp。这是一个非常简单的应用程序,有一个输入和一个按钮。您键入一些文本,单击按钮,其他人将得到更改 @Path("items") public class ItemStoreResource { private static final ReentrantReadWriteLock storeLock = new ReentrantReadWriteLock();
@Path("items")
public class ItemStoreResource {
private static final ReentrantReadWriteLock storeLock = new ReentrantReadWriteLock();
private static final LinkedList<String> itemStore = new LinkedList<String>();
private static final SseBroadcaster broadcaster = new SseBroadcaster();
private static volatile long reconnectDelay = 0;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String listItems() {
try {
storeLock.readLock().lock();
return itemStore.toString();
} finally {
storeLock.readLock().unlock();
}
}
@GET
@Path("events")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput itemEvents(@HeaderParam(SseFeature.LAST_EVENT_ID_HEADER) @DefaultValue("-1") int lastEventId) {
final EventOutput eventOutput = new EventOutput();
if (lastEventId >= 0) {
LOGGER.info("Received last event id :" + lastEventId);
// decide the reconnect handling strategy based on current reconnect delay value.
final long delay = reconnectDelay;
if (delay > 0) {
LOGGER.info("Non-zero reconnect delay [" + delay + "] - responding with HTTP 503.");
throw new ServiceUnavailableException(delay);
} else {
LOGGER.info("Zero reconnect delay - reconnecting.");
replayMissedEvents(lastEventId, eventOutput);
}
}
if (!broadcaster.add(eventOutput)) {
LOGGER.severe("!!! Unable to add new event output to the broadcaster !!!");
// let's try to force a 5s delayed client reconnect attempt
throw new ServiceUnavailableException(5L);
}
return eventOutput;
}
private void replayMissedEvents(final int lastEventId, final EventOutput eventOutput) {
try {
storeLock.readLock().lock();
final int firstUnreceived = lastEventId + 1;
final int missingCount = itemStore.size() - firstUnreceived;
if (missingCount > 0) {
LOGGER.info("Replaying events - starting with id " + firstUnreceived);
final ListIterator<String> it = itemStore.subList(firstUnreceived, itemStore.size()).listIterator();
while (it.hasNext()) {
eventOutput.write(createItemEvent(it.nextIndex() + firstUnreceived, it.next()));
}
} else {
LOGGER.info("No events to replay.");
}
} catch (IOException ex) {
throw new InternalServerErrorException("Error replaying missed events", ex);
} finally {
storeLock.readLock().unlock();
}
}
@POST
public void addItem(@FormParam("name") String name) {
// Ignore if the request was sent without name parameter.
if (name == null) {
return;
}
final int eventId;
try {
storeLock.writeLock().lock();
eventId = itemStore.size();
itemStore.add(name);
// Broadcasting an un-named event with the name of the newly added item in data
broadcaster.broadcast(createItemEvent(eventId, name));
// Broadcasting a named "size" event with the current size of the items collection in data
broadcaster.broadcast(new OutboundEvent.Builder().name("size").data(Integer.class, eventId + 1).build());
} finally {
storeLock.writeLock().unlock();
}
}
private OutboundEvent createItemEvent(final int eventId, final String name) {
Logger.getLogger(ItemStoreResource.class.getName()).info("Creating event id [" + eventId + "] name [" + name + "]");
return new OutboundEvent.Builder().id("" + eventId).data(String.class, name).build();
}
}
@Path(“项目”)
公共类ItemStoreResource{
私有静态最终ReentrantReadWriteLock storeLock=new ReentrantReadWriteLock();
私有静态最终LinkedList itemStore=新LinkedList();
专用静态最终SSE广播电台=新SSE广播电台();
专用静态易失性长重连延迟=0;
@得到
@生成(MediaType.TEXT\u PLAIN)
公共字符串listItems(){
试一试{
storeLock.readLock().lock();
返回itemStore.toString();
}最后{
storeLock.readLock().unlock();
}
}
@得到
@路径(“事件”)
@产生(SseFeature.SERVER\u SENT\u事件)
public EventOutput itemEvents(@HeaderParam(SseFeature.LAST_EVENT_ID_HEADER)@DefaultValue(“-1”)int-lastEventId){
final EventOutput EventOutput=新的EventOutput();
如果(lastEventId>=0){
LOGGER.info(“收到的上一个事件id:+lastEventId”);
//根据当前重新连接延迟值确定重新连接处理策略。
最终长延迟=重新连接延迟;
如果(延迟>0){
info(“非零重新连接延迟[“+延迟+”]-用HTTP503响应”);
抛出新的ServiceUnavailableException(延迟);
}否则{
info(“零重新连接延迟-重新连接”);
replayMissedEvents(lastEventId、eventOutput);
}
}
如果(!broadcaster.add(eventOutput)){
LOGGER.severe(!!!无法将新事件输出添加到广播程序!!!);
//让我们尝试强制5s延迟的客户端重新连接尝试
抛出新的ServiceUnavailableException(5L);
}
返回事件输出;
}
私有void replayMissedEvents(final int lastEventId,final EventOutput EventOutput){
试一试{
storeLock.readLock().lock();
final int firstUnreceived=lastEventId+1;
final int missingCount=itemStore.size()-firstUnreceived;
如果(丢失计数>0){
info(“重放事件-从id开始”+firstUnreceived);
final ListIterator it=itemStore.subList(firstUnreceived,itemStore.size()).ListIterator();
while(it.hasNext()){
write(createItemEvent(it.nextIndex()+firstUnreceived,it.next());
}
}否则{
info(“没有要重播的事件”);
}
}捕获(IOEX异常){
抛出新的InternalServerErrorException(“错误重放错过的事件”,ex);
}最后{
storeLock.readLock().unlock();
}
}
@职位
public void addItem(@FormParam(“name”)字符串名){
//如果发送的请求没有name参数,则忽略。
if(name==null){
返回;
}
最终int事件ID;
试一试{
storeLock.writeLock().lock();
eventId=itemStore.size();
itemStore.add(名称);
//使用数据中新添加项的名称广播未命名事件
广播(createItemEvent(eventId,名称));
//使用数据中项集合的当前大小广播命名的“大小”事件
broadcast.broadcast(新的OutboundEvent.Builder().name(“size”).data(Integer.class,eventId+1.build());
}最后{
storeLock.writeLock().unlock();
}
}
私有OutboundEvent createItemEvent(最终int eventId,最终字符串名称){
Logger.getLogger(ItemStoreResource.class.getName()).info(“创建事件id[“+eventId+”]name[“+name+”]);
返回新的OutboundEvent.Builder().id(“+eventId).data(String.class,name).build();
}
}
例如,如果我有一个聊天室,我不知道如何使用SSE实现这一点,因为每个客户端都连接到/items/events
,如果有人将新消息发布到某个聊天室播音员
将此消息广播到所有已签名的事件,但我只希望广播某些聊天室的事件
谁与Jersey SSE合作?你能建议如何实现这一点吗?试着使用smth,就像一个带有聊天室ID的地图,将SseBroadcast对象映射到SseBroadcast对象,然后你可以将某个房间的所有用户订阅给广播公司。您可以将其用作tet-a-tet对话或团队对话 样本如下:
private static final Map<Long, SseBroadcaster> ROOM_SSE_BROADCASTER = new ConcurrentHashMap<>();
@GET
@Path("/updatestate/{roomId}/{userId}")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput updateState(@PathParam("roomId") Long roomId, @PathParam("userId") Long userId) {
EventOutput eo = new EventOutput();
ROOM_SSE_BROADCASTER.get(roomId).add(eo);
return eo;
}
public static void updateRoom(Long roomId) {
ROOM_SSE_BROADCASTER.get(roomId).broadcast(buildEvent());
}
public static void registerRoom(Long roomId) {
ROOM_SSE_BROADCASTER.put(roomId, new SseBroadcaster());
}
private static OutboundEvent buildEvent() {
OutboundEvent.Builder builder = new OutboundEvent.Builder();
OutboundEvent event = builder.data(String.class, "update").build();
return event;
}
private static final Map ROOM_SSE_BROADCASTER=new ConcurrentHashMap();
@得到
@路径(“/updatestate/{roomId}/{userId}”)
@产生(SseFeature.SERVER\u SENT\u事件)
public EventOutput updateState(@PathParam(“roomId”)Long roomId,@PathParam(“userId”)Long userId){
EventOutput eo=新的EventOutput();
ROOM_SSE_播音员。获取(roomId)。添加(eo);
返回eo;
}
公共静态无效更新eRoom(长roomId){
ROOM_SSE_BROADCASTER.get(roomId.broadcast)(buildEvent());
}
公共静态无效注册表项(长roomId){
ROOM_SSE_播音员.put(roomId,新SSE播音员());
}
私有静态OutboundEvent buildEvent(){
OutboundEvent.Builder=新建OutboundEvent.Builder();
OutboundEvent=builder.data(String.class,“update”).build();
返回事件;
}