容器为每个客户端连接创建了单独的端点实例,因此您无法做您试图做的事情。但我想您试图做的是在事件发生时向所有活动客户端连接发送消息,这很简单。
javax.websocket.Session
类具有getBasicRemote
方法,可检索表示与该会话关联的端点的RemoteEndpoint.Basic
实例。
您可以通过调用Session.getOpenSessions()
来检索所有打开的会话,然后遍历它们。循环将向每个客户端连接发送一条消息。以下是一个简单的示例:
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
@OnMessage
public void onMessage(Session session, String message) {
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()) {
s.getBasicRemote().sendText(message);
}
} catch (IOException ex) { ... }
}
}
但在你的情况下,你可能想使用CDI事件来触发对所有客户端的更新。在这种情况下,你需要创建一个CDI事件,然后在你的Websocket端点类中观察该方法:
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
@EJB
ArticleBean articleBean;
private static final Set<Session> sessions =
Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
public void onOpen(final Session session) {
sessions.add(session);
...
}
@OnClose
public void onClose(final Session session) {
sessions.remove(session);
}
public void broadcastArticle(@Observes @NewArticleEvent ArticleEvent articleEvent) {
synchronized(sessions) {
for (Session s : sessions) {
if (s.isOpen()) {
try {
s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
} catch (IOException ex) { ... }
}
}
}
}
}
在上面的例子中,EJB 将会执行以下操作:
...
@Inject
Event<ArticleEvent> newArticleEvent;
public void publishArticle(Article article) {
...
newArticleEvent.fire(new ArticleEvent(article));
...
}
请参阅Java EE 7教程中关于WebSockets和CDI事件的章节。
编辑:修改@Observer
方法以使用事件作为参数。
编辑2:在broadcastArticle循环中使用synchronized进行了包装,按照@gcvt的建议。
编辑3:更新了Java EE 7教程的链接。做得好,Oracle。嘘。
broadcastArticle
方法中,在 for 循环之前应该加上synchronized(sessions)
。 - gcvt